Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch core-9-0-branch Excluding Merge-Ins
This is equivalent to a diff from 94c9e43558 to 34db3351f1
|
2026-09-08
| ||
| 10:14 | Sometimes, on macOS, 15/20 minutes are not enough to run all testcases Leaf check-in: 34db3351f1 user: jan.nijtmans tags: core-9-0-branch | |
|
2026-09-07
| ||
| 20:13 | burnett01/rsync-deployments -> 9.0.1 check-in: 063eab4f10 user: jan.nijtmans tags: core-9-0-branch | |
|
2026-08-20
| ||
| 03:10 | Merge 9.0. Fix explanation of exec -encoding option (thanks, @Schelte) check-in: a9496f804e user: apnadkarni tags: trunk, main | |
|
2026-08-18
| ||
| 15:42 | Fix [e4c24e86b5]: timer documentation typos Closed-Leaf check-in: a14a16c336 user: jan.nijtmans tags: bug-e4c24e86b5 | |
| 12:50 | Fix [4bd630]: --without-tzdata on windows check-in: 94c9e43558 user: jan.nijtmans tags: trunk, main | |
| 12:44 | Fix [4bd630]: --without-tzdata on windows check-in: fd06472ef4 user: jan.nijtmans tags: core-9-0-branch | |
|
2026-08-16
| ||
| 23:55 | Update Windows icon to new Tcl 9 logo check-in: 499b05be3c user: pbrooks tags: trunk, main | |
Deleted .github/tcltest.json.
|
| < < < < < < < < < < < < < < < |
Deleted .github/workflows/custom.yml.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to .github/workflows/linux-build.yml.
1 2 3 4 5 |
name: Linux
on:
push:
branches:
- "main"
| | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
name: Linux
on:
push:
branches:
- "main"
- "core-9-0-branch"
tags:
- "core-*"
workflow_dispatch:
permissions:
contents: read
jobs:
plan:
runs-on: ubuntu-26.04
outputs:
gcc: ${{ steps.matrix.outputs.gcc }}
steps:
- name: Select build matrix based on branch name
id: matrix
run: |
(
echo gcc=$(jq -nc '{config: (if env.IsMatched == "true" then env.FULL else env.PARTIAL end) | fromjson }' )
) | tee -a $GITHUB_OUTPUT
env:
IsMatched: ${{ github.ref_name == 'main' || github.ref_name == 'core-9-0-branch' }}
# DO NOT CHANGE THESE MATRIX SPECS; IT AFFECTS OUR COST CONTROLS
FULL: >
[
"",
"CFLAGS=-DTCL_NO_DEPRECATED=1",
"--disable-shared",
"--disable-zipfs",
|
| ︙ | ︙ | |||
39 40 41 42 43 44 45 |
[
"",
"--enable-symbols=all",
"CFLAGS=-m32 CPPFLAGS=-m32 LDFLAGS=-m32 --disable-64bit"
]
gcc:
needs: plan
| | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
[
"",
"--enable-symbols=all",
"CFLAGS=-m32 CPPFLAGS=-m32 LDFLAGS=-m32 --disable-64bit"
]
gcc:
needs: plan
runs-on: ubuntu-26.04
strategy:
matrix: ${{ fromJson(needs.plan.outputs.gcc) }}
defaults:
run:
shell: bash
working-directory: unix
steps:
|
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
timeout-minutes: 5
- name: Info
run: |
ulimit -a || echo 'get limit failed'
make runtest SCRIPT=../.github/workflows/info.tcl || echo 'get info failed'
- name: Run Tests
run: |
| < < > | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
timeout-minutes: 5
- name: Info
run: |
ulimit -a || echo 'get limit failed'
make runtest SCRIPT=../.github/workflows/info.tcl || echo 'get info failed'
- name: Run Tests
run: |
make test
env:
ERROR_ON_FAILURES: 1
CI: 1
timeout-minutes: 30
- name: Test-Drive Installation
run: |
make install
timeout-minutes: 5
- name: Create Distribution Package
if: ${{ matrix.config == '' }}
|
| ︙ | ︙ |
Changes to .github/workflows/mac-build.yml.
1 2 3 4 5 |
name: macOS
on:
push:
branches:
- "main"
| | > | | | < < | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
name: macOS
on:
push:
branches:
- "main"
- "core-9-0-branch"
tags:
- "core-*"
workflow_dispatch:
permissions:
contents: read
jobs:
plan:
runs-on: ubuntu-26.04
outputs:
clang: ${{ steps.matrix.outputs.clang }}
steps:
- name: Select build matrix based on branch name
id: matrix
run: |
(
echo clang=$(jq -nc '{config: (if env.IsMatched == "true" then env.FULL else env.PARTIAL end) | fromjson }' )
) | tee -a $GITHUB_OUTPUT
env:
IsMatched: ${{ github.ref_name == 'main' || github.ref_name == 'core-9-0-branch' }}
# DO NOT CHANGE THIS MATRIX SPEC; IT AFFECTS OUR COST CONTROLS
FULL: >
[
"",
"--disable-shared",
"--disable-zipfs",
"--enable-symbols",
"--enable-symbols=mem",
"--enable-symbols=all"
]
PARTIAL: >
[
"",
"--enable-symbols=all"
]
xcode:
runs-on: macos-15
defaults:
run:
shell: bash
working-directory: macosx
steps:
- name: Checkout
uses: actions/checkout@v7
timeout-minutes: 5
- name: Prepare
run: |
touch tclStubInit.c tclOOStubInit.c tclOOScript.h
working-directory: generic
- name: Build
run: make -j4 all
env:
CFLAGS: -arch x86_64 -arch arm64
timeout-minutes: 15
- name: Run Tests
run: make -j4 test styles=develop
env:
ERROR_ON_FAILURES: 1
MAC_CI: 1
timeout-minutes: 30
clang:
runs-on: macos-15
needs: plan
strategy:
matrix: ${{ fromJson(needs.plan.outputs.clang) }}
defaults:
run:
shell: bash
working-directory: unix
|
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
timeout-minutes: 15
- name: Info
run: |
ulimit -a || echo 'get limit failed'
make runtest SCRIPT=../.github/workflows/info.tcl || echo 'get info failed'
- name: Run Tests
run: |
| < | | 96 97 98 99 100 101 102 103 104 105 106 107 |
timeout-minutes: 15
- name: Info
run: |
ulimit -a || echo 'get limit failed'
make runtest SCRIPT=../.github/workflows/info.tcl || echo 'get info failed'
- name: Run Tests
run: |
make test
env:
ERROR_ON_FAILURES: 1
MAC_CI: 1
timeout-minutes: 30
|
Changes to .github/workflows/onefiledist.yml.
1 2 3 4 5 |
name: Build Binaries
on:
push:
branches:
- "main"
| | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
name: Build Binaries
on:
push:
branches:
- "main"
- "core-9-0-branch"
tags:
- "core-*"
workflow_dispatch:
permissions:
contents: read
jobs:
linux:
name: Linux
runs-on: ubuntu-24.04
defaults:
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 |
name: Tclsh ${{ env.TCL_PATCHLEVEL }} macOS single-file build (snapshot)
path: 1dist/*.dmg
id: upload
outputs:
url: ${{ steps.upload.outputs.artifact-url }}
win:
name: Windows
| | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
name: Tclsh ${{ env.TCL_PATCHLEVEL }} macOS single-file build (snapshot)
path: 1dist/*.dmg
id: upload
outputs:
url: ${{ steps.upload.outputs.artifact-url }}
win:
name: Windows
runs-on: windows-2025
defaults:
run:
shell: msys2 {0}
timeout-minutes: 10
env:
CC: gcc
CFGOPT: --disable-symbols --disable-shared
|
| ︙ | ︙ | |||
176 177 178 179 180 181 182 |
url: ${{ steps.upload.outputs.artifact-url }}
combine:
needs:
- linux
- macos
- win
name: Combine Artifacts (prototype)
| | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
url: ${{ steps.upload.outputs.artifact-url }}
combine:
needs:
- linux
- macos
- win
name: Combine Artifacts (prototype)
runs-on: ubuntu-26.04
defaults:
run:
shell: bash
timeout-minutes: 10
env:
# See also
# https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables
|
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
merge-multiple: true
- name: Check data downloaded
run: |
ls -AlR
working-directory: data
- name: Transfer built files
# https://github.com/marketplace/actions/rsync-deployments-action
| | | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
merge-multiple: true
- name: Check data downloaded
run: |
ls -AlR
working-directory: data
- name: Transfer built files
# https://github.com/marketplace/actions/rsync-deployments-action
uses: burnett01/rsync-deployments@9.0.1
id: rsync
if: false # Disabled... for now
with:
# I don't know what the right switches are here, BTW
switches: -avzr
path: data/
remote_path: ${{ env.REMOTE_PATH }}
|
| ︙ | ︙ |
Changes to .github/workflows/win-build.yml.
1 2 3 4 5 |
name: Windows
on:
push:
branches:
- "main"
| | > | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
name: Windows
on:
push:
branches:
- "main"
- "core-9-0-branch"
tags:
- "core-*"
workflow_dispatch:
permissions:
contents: read
jobs:
plan:
runs-on: ubuntu-26.04
outputs:
msvc: ${{ steps.matrix.outputs.msvc }}
gcc: ${{ steps.matrix.outputs.gcc }}
steps:
- name: Select build matrix based on branch name
id: matrix
run: |
(
echo msvc=$(jq -nc '{arch: ["x64"], config: (if env.IsMatched == "true" then env.MSVC_FULL else env.MSVC_PARTIAL end) | fromjson }' )
echo gcc=$(jq -nc '{config: (if env.IsMatched == "true" then env.GCC_FULL else env.GCC_PARTIAL end) | fromjson }' )
) | tee -a $GITHUB_OUTPUT
env:
IsMatched: ${{ github.ref_name == 'main' || github.ref_name == 'core-9-0-branch' }}
# DO NOT CHANGE THESE MATRIX SPECS; IT AFFECTS OUR COST CONTROLS
MSVC_FULL: >
[
"",
"CHECKS=nodep",
"OPTS=static",
"OPTS=noembed",
|
| ︙ | ︙ | |||
52 53 54 55 56 57 58 |
GCC_PARTIAL: >
[
"",
"--disable-shared",
"--enable-symbols=all"
]
msvc:
| | | | > > > < | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
GCC_PARTIAL: >
[
"",
"--disable-shared",
"--enable-symbols=all"
]
msvc:
runs-on: windows-2025
needs: plan
defaults:
run:
shell: powershell
working-directory: win
strategy:
matrix: ${{ fromJson(needs.plan.outputs.msvc) }}
# Using powershell means we need to explicitly stop on failure
steps:
- name: Checkout
uses: actions/checkout@v7
timeout-minutes: 5
- name: Init MSVC
shell: cmd
run: |
for /f "usebackq tokens=*" %%i in (`vswhere -latest -property installationPath`) do set "VS_PATH=%%i"
call "%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }}
set | findstr /i "^VC ^VCTools ^Windows ^Universal ^INCLUDE ^LIB ^PATH ^DevEnv" >> %GITHUB_ENV%
- name: Build ${{ matrix.config }}
run: |
&nmake -f makefile.vc ${{ matrix.config }} all
if ($lastexitcode -ne 0) {
throw "nmake exit code: $lastexitcode"
}
timeout-minutes: 5
- name: Build Test Harness ${{ matrix.config }}
run: |
&nmake -f makefile.vc ${{ matrix.config }} tcltest
if ($lastexitcode -ne 0) {
throw "nmake exit code: $lastexitcode"
}
timeout-minutes: 5
- name: Run Tests ${{ matrix.config }}
run: |
&nmake -f makefile.vc ${{ matrix.config }} test
if ($lastexitcode -ne 0) {
throw "nmake exit code: $lastexitcode"
}
timeout-minutes: 30
env:
ERROR_ON_FAILURES: 1
gcc:
runs-on: windows-2025
needs: plan
defaults:
run:
shell: msys2 {0}
working-directory: win
strategy:
matrix: ${{ fromJson(needs.plan.outputs.gcc) }}
|
| ︙ | ︙ | |||
133 134 135 136 137 138 139 |
run: make -j4 tcltest
timeout-minutes: 5
- name: Info
run: |
ulimit -a || echo 'get limit failed'
make runtest SCRIPT=../.github/workflows/info.tcl || echo 'get info failed'
- name: Run Tests
| < < | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
run: make -j4 tcltest
timeout-minutes: 5
- name: Info
run: |
ulimit -a || echo 'get limit failed'
make runtest SCRIPT=../.github/workflows/info.tcl || echo 'get info failed'
- name: Run Tests
run: make test
timeout-minutes: 30
env:
ERROR_ON_FAILURES: 1
- name: Install
run: make install
timeout-minutes: 5
# If you add builds with Wine, be sure to define the environment variable
# CI_USING_WINE when running them so that broken tests know not to run.
|
Changes to .project.
1 2 | <?xml version="1.0" encoding="UTF-8"?> <projectDescription> | | | 1 2 3 4 5 6 7 8 9 10 | <?xml version="1.0" encoding="UTF-8"?> <projectDescription> <name>tcl9.0</name> <comment></comment> <projects> </projects> <buildSpec> </buildSpec> <natures> </natures> |
| ︙ | ︙ |
Changes to README.md.
1 2 | # README: Tcl | | | 1 2 3 4 5 6 7 8 9 10 | # README: Tcl This is the **Tcl 9.0.5** source distribution. You can get any source release of Tcl from [our distribution site](https://sourceforge.net/projects/tcl/files/Tcl/). 9.1 (in development, daily build) [](https://github.com/tcltk/tcl/actions/workflows/linux-build.yml?query=branch%3Amain) [](https://github.com/tcltk/tcl/actions/workflows/win-build.yml?query=branch%3Amain) |
| ︙ | ︙ | |||
47 48 49 50 51 52 53 | anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. See the file `license.terms` for complete information. ## <a id="doc">2.</a> Documentation Extensive documentation is available on our website. The home page for this release, including new features, is | | | | | > > > > > > > | > > > > > < < | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. See the file `license.terms` for complete information. ## <a id="doc">2.</a> Documentation Extensive documentation is available on our website. The home page for this release, including new features, is [here](https://www.tcl-lang.org/software/tcltk/9.0.html). Detailed release notes can be found at the [file distributions page](https://sourceforge.net/projects/tcl/files/Tcl/) by clicking on the relevant version. Information about Tcl itself can be found at the [Developer Xchange](https://www.tcl-lang.org/about/). There have been many Tcl books on the market. Many are mentioned in [the Wiki](https://wiki.tcl-lang.org/_/ref?N=25206). The complete set of reference manual entries for Tcl 9.0 is [online, here](https://www.tcl-lang.org/man/tcl9.0/). ### <a id="doc.unix">2a.</a> Unix Documentation The `doc` subdirectory in this release contains a complete set of reference manual entries for Tcl. Files with extension "`.1`" are for programs (for example, `tclsh.1`); files with extension "`.3`" are for C library procedures; and files with extension "`.n`" describe Tcl commands. The file "`doc/Tcl.n`" gives a quick summary of the Tcl language syntax. To print any of the man pages on Unix, cd to the "doc" directory and invoke your favorite variant of troff using the normal -man macros, for example groff -man -Tpdf Tcl.n >output.pdf to print Tcl.n to PDF. If Tcl has been installed correctly and your "man" program supports it, you should be able to access the Tcl manual entries using the normal "man" mechanisms, such as man Tcl ### <a id="doc.win">2b.</a> Windows Documentation The "doc" subdirectory in this release contains a complete set of Windows help files for Tcl. Once you install this Tcl release, a shortcut to the Windows help Tcl documentation will appear in the "Start" menu: Start | Programs | Tcl | Tcl Help ## <a id="build">3.</a> Compiling and installing Tcl There are brief notes in the `unix/README`, `win/README`, and `macosx/README` about compiling on these different platforms. There is additional information about building Tcl from sources [online](https://www.tcl-lang.org/doc/howto/compile.html). ## <a id="devtools">4.</a> Development tools ActiveState produces a high-quality set of commercial quality development tools that is available to accelerate your Tcl application development. Tcl Dev Kit builds on the earlier TclPro toolset and provides a debugger, static code checker, single-file wrapping utility, bytecode compiler, and more. More information can be found at https://www.activestate.com/products/tcl/ ## <a id="complangtcl">5.</a> Tcl newsgroup There is a USENET newsgroup, "`comp.lang.tcl`", intended for the exchange of information about Tcl, Tk, and related applications. The newsgroup is a great place to ask general information questions. For bug reports, please see the "Support and bug fixes" section below. |
| ︙ | ︙ |
Changes to changes.md.
1 2 3 4 5 6 | The source code for Tcl is managed by fossil. Tcl developers coordinate all changes to the Tcl source code at > [Tcl Source Code](https://core.tcl-lang.org/tcl/timeline) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | > > > > > | > | > > | | > > | > | > > > > > > | < | | > > > > > > > > > > > > > > > | | < < < < < < < < < > > > > > > > > > > > > | | | | | > > > > > | < > > > > > > > > > > > > > > > | < < < < > > > > > > > > > > | < < < < < > > | > > > > > > > > > > | < > | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
The source code for Tcl is managed by fossil. Tcl developers coordinate all
changes to the Tcl source code at
> [Tcl Source Code](https://core.tcl-lang.org/tcl/timeline)
Release Tcl 9.0.5 arises from the check-in with tag `core-9-0-5`.
Tcl patch releases have the primary purpose of delivering bug fixes
to the userbase.
# Bug fixes
- [format honours LC_NUMERIC for %f/%g](https://core.tcl-lang.org/tcl/tktview/fcd3da)
- [Warning: argument 1 of 'Tcl_SetPanicProc' might be a candiate for a format attribute](https://core.tcl-lang.org/tcl/tktview/6ae6c1)
- [platform::identify broken on Red Hat Linux](https://core.tcl-lang.org/tcl/tktview/61ba0b)
- [Windows: file normalize drops a component when parent enumeration is denied](https://core.tcl-lang.org/tcl/tktview/d40d8d)
- [Windows: busy loop when conhost process is killed](https://core.tcl-lang.org/tcl/tktview/f10d91)
- [glob -dir . returns corrupted entries in zipfs](https://core.tcl-lang.org/tcl/tktview/4676f5)
- [--without-tzdata on windows](https://core.tcl-lang.org/tcl/tktview/4bd630)
# Updated bundled packages, libraries, standards, data
- platform 1.1.1
- tzdata 2026c
Release Tcl 9.0.4 arises from the check-in with tag `core-9-0-4`.
Tcl patch releases have the primary purpose of delivering bug fixes
to the userbase.
# Bug fixes
- [unsupported commands should not be available in safe interpreters](https://core.tcl-lang.org/tcl/tktview/82d12c)
- [Check for -municode doesn't work on WSL](https://core.tcl-lang.org/tcl/tktview/632710)
- [configure --enable-man-compression error](https://core.tcl-lang.org/tcl/tktview/886549)
- [nmake: rmdir and mkdir are picked from cygwin if available](https://core.tcl-lang.org/tcl/tktview/be40b7)
- [lseq: has incorrect results in edge cases](https://core.tcl-lang.org/tcl/tktview/999b69)
- [lseq: "count" error persists across calls](https://core.tcl-lang.org/tcl/tktview/8d1fc7)
- [lseq: Remove the ability to pass expressions as numeric values in the lseq command.](https://core.tcl-lang.org/tips/doc/trunk/tip/746.md)
- [Performance regression in expr in/ni operators](https://core.tcl-lang.org/tcl/info/8994c9)
- [Uninitialized memory access in setting script limits](https://core.tcl-lang.org/tcl/info/f7495f)
- [Crash when defining const if namespace does not exist](https://core.tcl-lang.org/tcl/info/4b22d8)
- [Glob errors with -directory option and patterns containing absolute paths (Windows)](https://core.tcl-lang.org/tcl/info/b0682c)
- [Glob errors with -directory option with trailing backslash (Windows)](https://core.tcl-lang.org/tcl/info/b0682c)
- [File normalization inconsistency for glob result (Windows)](https://core.tcl-lang.org/tcl/info/108904)
- [Avoid ClockClientData typedef redefinition](https://core.tcl-lang.org/tcl/info/4724f3)
- [Building sqlite3 for tcl8 redefines typedef](https://core.tcl-lang.org/tcl/info/ad08bc)
- [Inconsistent file join with volume-relative arguments](https://core.tcl-lang.org/tcl/info/1215dc)
- [mind PTHREAD_NULL as sentinel value vs legitimate pthread_t arg](https://core.tcl-lang.org/tcl/info/673f2d)
- [fileevent poor performance due to shimmering](https://core.tcl-lang.org/tcl/info/7da6c2)
# Updated bundled packages, libraries, standards, data
- autoconf 2.73
- http 2.10.2
- Itcl 4.3.8
- sqlite3 3.53.0
- tcltest 2.5.11
- Thread 3.0.6
- tzdata 2026b
- zlib 1.3.2
Release Tcl 9.0.3 arises from the check-in with tag `core-9-0-3`.
Tcl patch releases have the primary purpose of delivering bug fixes
to the userbase.
# Bug fixes
- [On Unix, IsTimeNative() always defined but not always used](https://core.tcl-lang.org/tcl/tktview/6b8e39)
- [Tweak install permissions](https://core.tcl-lang.org/tcl/tktview/31d4fa)
- [interp creation resets encoding directory search path](https://core.tcl-lang.org/tcl/tktview/87b697)
- [Pointer arithmetic with NULL in buildInfoObjCmd()](https://core.tcl-lang.org/tcl/tktview/85fc8b)
- [TclPushVarName(): pointer overflow](https://core.tcl-lang.org/tcl/tktview/77059c)
- [Add IWYU export pragma annotations](https://core.tcl-lang.org/tcl/tktview/c7dc59)
- [Windows: Install man pages](https://core.tcl-lang.org/tcl/tktview/3161b7)
- [Windows: Install pkgconfig](https://core.tcl-lang.org/tcl/tktview/1cf49a)
- [Non-existent variables are ignored if re is {}](https://core.tcl-lang.org/tcl/tktview/cb03e5)
- [bug in single-argument 'max' with bignums](https://core.tcl-lang.org/tcl/tktview/8dd280)
- [Windows static builds: package require registry dde fails in child interpreters](https://core.tcl-lang.org/tcl/tktview/4f06d7)
- [Windows static builds: registry command is available in main interpreter without package require](https://core.tcl-lang.org/tcl/tktview/6094de)
# Updated bundled packages, libraries, standards, data
- Itcl 4.3.5
- http 2.10.1
- opt 0.4.10
- platform 1.1.0
- sqlite3 3.51.0
- tcltest 2.5.10
- Thread 3.0.4
- TDBC\* 1.1.13
- dde 1.4.6
- Unicode 17.0.0
Release Tcl 9.0.2 arises from the check-in with tag `core-9-0-2`.
Tcl patch releases have the primary purpose of delivering bug fixes
to the userbase.
# New commands and options
- [New command encoding user](https://core.tcl-lang.org/tips/doc/trunk/tip/716.md)
- [New exec option -encoding](https://core.tcl-lang.org/tips/doc/trunk/tip/716.md)
# Bug fixes
- [Better error-message than "interpreter uses an incompatible stubs mechanism"](https://core.tcl-lang.org/tcl/tktview/fc3509)
- [\[$interp eval $lambda\] after \[eval $lambda\] or vice versa fails](https://core.tcl-lang.org/tcl/tktview/67d5f7)
- [tcl::mathfunc::isunordered inconsistency with some integer values](https://core.tcl-lang.org/tcl/tktview/98006f)
- [test lseq hangs with -Os](https://core.tcl-lang.org/tcl/tktview/d2a3c5)
- [exec does not handle app execution aliases on Windows](https://core.tcl-lang.org/tcl/tktview/4f0b57)
- [auto_execok does not find several built-in cmd commands](https://core.tcl-lang.org/tcl/tktview/4e2c8b)
- [Panic "Buffer Underflow, BUFFER_PADDING not enough"](https://core.tcl-lang.org/tcl/tktview/73bb42)
- [MS-VS build system: pckIndex.tcl when building for 9 misses "t" for TCL 8.6 part](https://core.tcl-lang.org/tcl/tktview/a77029)
- [clock format -locale does not look up locale children if parent locale used first](https://core.tcl-lang.org/tcl/tktview/2c0f49)
- [Missing libtcl?.?.dll.a in Cygwin](https://core.tcl-lang.org/tcl/tktview/dcedba)
- [tclEpollNotfy PlatformEventsControl panics if websocket disconnected](https://core.tcl-lang.org/tcl/tktview/010d8f)
- [Tcl_InitStubs compatibility for 9.1](https://core.tcl-lang.org/tcl/tktview/fd8341)
- [proc with more than 2**31 variables](https://core.tcl-lang.org/tcl/tktview/92aeb8)
- [scan "long mantissa" %g](https://core.tcl-lang.org/tcl/tktview/42d14c)
- ["encoding system": wrong result without manifest](https://core.tcl-lang.org/tcl/tktview/8ffd8c)
- [lseq crash on out-of-range index](https://core.tcl-lang.org/tcl/tktview/7d3101)
- [lseq crash on nested indices](https://core.tcl-lang.org/tcl/tktview/452b10)
- [Build broken (trunk branch) tclCompExpr.c tclOOCall.c](https://core.tcl-lang.org/tcl/tktview/1dcda0)
- [Memory allocation runaway on truncated iso2022 encoding](https://core.tcl-lang.org/tcl/tktview/7346ad)
- [Missing include dir for extensions in non-default locations](https://core.tcl-lang.org/tcl/tktview/333512)
- [tcl::tm::path doesn't handle tilde expand](https://core.tcl-lang.org/tcl/tktview/b87673)
- [lseq numeric overflow](https://core.tcl-lang.org/tcl/tktview/0ee626)
- ["return": broken ordering of nested -options](https://core.tcl-lang.org/tcl/tktview/ecf35c)
- [Euro/Tail-sign missing from cp864 encoding](https://core.tcl-lang.org/tcl/tktview/ecafd8)
- [use after free on TSD in Winsock](https://core.tcl-lang.org/tcl/tktview/40b181)
- [use after free on Windows pipe handles](https://core.tcl-lang.org/tcl/tktview/7c2716)
- [tcl::build-info not documented](https://core.tcl-lang.org/tcl/tktview/ef7042)
- [Fix 32 bit overflow in interp limit](https://core.tcl-lang.org/tcl/tktview/9dfae3)
# Incompatibilities
- [The ActiveCodePage element has been removed from the Windows executable manifest for tclsh](https://core.tcl-lang.org/tips/doc/trunk/tip/716.md)
# Updated bundled packages, libraries, standards, data
- Itcl 4.3.3
- sqlite3 3.49.1
- Thread 3.0.2
- TDBC\* 1.1.11
- tzdata 2025b
Release Tcl 9.0.1 arises from the check-in with tag `core-9-0-1`.
Tcl patch releases have the primary purpose of delivering bug fixes
to the userbase. As the first patch release in the Tcl 9.0.\* series,
Tcl 9.0.1 also includes a small number of interface changes that complete
some incomplete features first delivered in Tcl 9.0.0.
# Completed 9.0 Features and Interfaces
- [TIP 701 - Tcl_FSTildeExpand C API](https://core.tcl-lang.org/tips/doc/trunk/tip/701.md)
- [TIP 707 - ptrAndSize internal rep in Tcl_Obj](https://core.tcl-lang.org/tips/doc/trunk/tip/707.md)
- [Size modifiers j, q, z, t not implemented]( https://core.tcl-lang.org/tcl/info/c4f365)
# Bug fixes
- [regression in tzdata, %z instead of offset TZ-name](https://core.tcl-lang.org/tcl/tktview/2c237b)
- [Tcl will not start properly if there is an init.tcl file in the current dir](https://core.tcl-lang.org/tcl/tktview/43c94f)
- [clock scan "24:00", ISO-8601 compatibility](https://core.tcl-lang.org/tcl/tktview/aee9f2)
- [Temporary folder with file "tcl9registry13.dll" remains after "exit"](https://core.tcl-lang.org/tcl/tktview/6ce3c0)
- [Wrong result by "lsearch -stride -subindices -inline -all"](https://core.tcl-lang.org/tcl/info/5a1aaa)
- [TIP 609 - required Tcl_ThreadAlert() skipped with nested event loop](https://core.tcl-lang.org/tcl/info/c7e4c4)
- [buffer overwrite for non-BMP characters in utf-16](https://core.tcl-lang.org/tcl/tktview/66da4d)
- [zipfs info on mountpoint of executable returns zero offset in field 4"](https://core.tcl-lang.org/tcl/info/aaa84f)
- [zlib-8.8, zlib-8.16 fail on Fedora 40, gcc 14.1.1](https://core.tcl-lang.org/tcl/tktview/73d5cb)
- [install registry and dde in $INSTALL_DIR\lib always](https://core.tcl-lang.org/tcl/tktview/364bd9)
- [cannot build .chm help file (Windows)](https://core.tcl-lang.org/tcl/tktview/bb110c)
# Incompatibilities
- No known incompatibilities with the Tcl 9.0.0 public interface.
# Updated bundled packages, libraries, standards, data
- Itcl 4.3.2
- sqlite3 3.47.2
- Thread 3.0.1
- TDBC\* 1.1.10
- tcltest 2.5.9
- tzdata 2024b, corrected
Release Tcl 9.0.0 arises from the check-in with tag `core-9-0-0`.
Highlighted differences between Tcl 9.0 and Tcl 8.6 are summarized below,
with focus on changes important to programmers using the Tcl library and
writing Tcl scripts.
# Major Features
## 64-bit capacity: Data values larger than 2Gb
- Strings can be any length (that fits in your available memory)
- Lists and dictionaries can have very large numbers of elements
## Internationalization of text
- Full Unicode range of codepoints
- New encodings: `utf-16`/`utf-32`/`ucs-2`(`le`|`be`), `CESU-8`, etc.
- `encoding` options `-profile`, `-failindex` manage encoding of I/O.
- `msgcat` supports custom locale search list
- `source` defaults to `-encoding utf-8`
## Zip filesystems and attached archives.
- Packaging of the Tcl script library with the Tcl binary library,
meaning that the `TCL_LIBRARY` environment variable is usually not required.
- Packaging of an application into a virtual filesystem is now a supported
core Tcl feature.
## Unix notifiers available using `epoll()` or `kqueue()`
- This relieves limits on file descriptors imposed by legacy `select()` and fixes a performance bottleneck.
# Incompatibilities
## Notable incompatibilities
- Unqualified varnames resolved in current namespace, not global.
Note that in almost all cases where this causes a change, the change is actually the removal of a latent bug.
- No `--disable-threads` build option. Always thread-enabled.
- I/O malencoding default response: raise error (`-profile strict`)
- Windows platform needs Windows 7 or Windows Server 2008 R2 or later
- Ended interpretation of `~` as home directory in pathnames.
(See `file home` and `file tildeexpand` for replacements when you need them.)
- Removed the `identity` encoding.
(There were only ever very few valid use cases for this; almost all uses
were systematically wrong.)
- Removed the encoding alias `binary` to `iso8859-1`.
- `$::tcl_precision` no longer controls string generation of doubles.
(If you need a particular precision, use `format`.)
- Removed pre-Tcl 8 legacies: `case`, `puts` and `read` variant syntaxes.
- Removed subcommands [`trace variable`|`vdelete`|`vinfo`]
- Removed `-eofchar` option for write channels.
- On Windows 10+ (Version 1903 or higher), system encoding is always utf-8.
- `%b`/`%d`/`%o`/`%x` format modifiers (without size modifier) for `format`
and `scan` always truncate to 32-bits on all platforms.
- `%L` size modifier for `scan` no longer truncates to 64-bit.
- Removed command `::tcl::unsupported::inject`.
(See `coroinject` and `coroprobe` for supported commands with significantly
more comprehensible semantics.)
## Incompatibilities in C public interface
- Extensions built against Tcl 8.6 and before will not work with Tcl 9.0;
ABI compatibility was a non-goal for 9.0. In _most_ cases, rebuilding
against Tcl 9.0 should work except when a removed API function is used.
- Many arguments expanded type from `int` to `Tcl_Size`, a signed integer type
large enough to support 64-bit sized memory objects.
The constant `TCL_AUTO_LENGTH` is a value of that type that indicates that
the length should be obtained using an appropriate function (typically `strlen()` for `char *` values).
- Ended support for `Tcl_ChannelTypeVersion` less than 5
- Introduced versioning of the `Tcl_ObjType` struct
- Removed macros `CONST*`: Tcl 9 support means dropping Tcl 8.3 support.
(Replaced with standard C `const` keyword going forward.)
- Removed registration of several `Tcl_ObjType`s.
- Removed API functions:
`Tcl_Backslash()`,
`Tcl_*VA()`,
`Tcl_*MathFunc*()`,
`Tcl_MakeSafe()`,
`Tcl_(Save|Restore|Discard|Free)Result()`,
`Tcl_EvalTokens()`,
`Tcl_(Get|Set)DefaultEncodingDir()`,
`Tcl_UniCharN(case)cmp()`,
`Tcl_UniCharCaseMatch()`
- Revised many internals; beware reliance on undocumented behaviors.
# New Features
## New commands
- `array default` — Specify default values for arrays (note that this alters the behaviour of `append`, `incr`, `lappend`).
- `array for` — Cheap iteration over an array's contents.
- `chan isbinary` — Test if a channel is configured to work with binary data.
- `coroinject`, `coroprobe` — Interact with paused coroutines.
- `clock add weekdays` — Clock arithmetic with week days.
- `const`, `info const*` — Commands for defining constants (variables that can't be modified).
- `dict getwithdefault` — Define a fallback value to use when `dict get` would otherwise fail.
- `file home` — Get the user home directory.
- `file tempdir` — Create a temporary directory.
- `file tildeexpand` — Expand a file path containing a `~`.
- `info commandtype` — Introspection for the kinds of commands.
- `ledit` — Equivalent to `lreplace` but on a list in a variable.
- `lpop` — Remove an item from a list in a variable.
- `lremove` — Remove a sublist from a list in a variable.
- `lseq` — Generate a list of numbers in a sequence.
- `package files` — Describe the contents of a package.
- `string insert` — Insert a string as a substring of another string.
- `string is dict` — Test whether a string is a dictionary.
- `tcl::process` — Commands for working with subprocesses.
- `*::build-info` — Obtain information about the build of Tcl.
- `readFile`, `writeFile`, `foreachLine` — Simple procedures for basic working with files.
- `tcl::idna::*` — Commands for working with encoded DNS names.
## New command options
- `chan configure ... -inputmode ...` — Support for raw terminal input and reading passwords.
- `clock scan ... -validate ...`
- `info loaded ... ?prefix?`
- `lsearch ... -stride ...` — Search a list by groups of items.
- `regsub ... -command ...` — Generate the replacement for a regular expression by calling a command.
- `socket ... -nodelay ... -keepalive ...`
- `vwait` controlled by several new options
- `expr` string comparators `lt`, `gt`, `le`, `ge`
- `expr` supports comments inside expressions
## Numbers
- <code>0<i>NNN</i></code> format is no longer octal interpretation. Use <code>0o<i>NNN</i></code>.
- <code>0d<i>NNNN</i></code> format to compel decimal interpretation.
- <code>NN_NNN_NNN</code>, underscores in numbers for optional readability
- Functions: `isinf()`, `isnan()`, `isnormal()`, `issubnormal()`, `isunordered()`
- Command: `fpclassify`
- Function `int()` no longer truncates to word size
## TclOO facilities
- private variables and methods
- class variables and methods
- abstract and singleton classes
- configurable properties
- `method -export`, `method -unexport`
|
Changes to compat/gettod.c.
1 2 3 4 5 6 | /* * gettod.c -- * * This file provides the gettimeofday function on systems * that only have the System V ftime function. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * gettod.c -- * * This file provides the gettimeofday function on systems * that only have the System V ftime function. * * Copyright (c) 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclPort.h" #include <sys/timeb.h> |
| ︙ | ︙ |
Changes to compat/mkstemp.c.
1 2 3 4 5 | /* * mkstemp.c -- * * Source code for the "mkstemp" library routine. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * mkstemp.c -- * * Source code for the "mkstemp" library routine. * * Copyright (c) 2009 Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include <errno.h> #include <fcntl.h> |
| ︙ | ︙ |
Changes to compat/strncasecmp.c.
1 2 3 4 5 | /* * strncasecmp.c -- * * Source code for the "strncasecmp" library routine. * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * strncasecmp.c -- * * Source code for the "strncasecmp" library routine. * * Copyright (c) 1988-1993 The Regents of the University of California. * Copyright (c) 1995-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclPort.h" |
| ︙ | ︙ |
Changes to compat/waitpid.c.
1 2 3 4 5 6 7 | /* * waitpid.c -- * * This procedure emulates the POSIX waitpid kernel call on BSD systems * that don't have waitpid but do have wait3. This code is based on a * prototype version written by Mark Diekhans and Karl Lehenbauer. * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * waitpid.c -- * * This procedure emulates the POSIX waitpid kernel call on BSD systems * that don't have waitpid but do have wait3. This code is based on a * prototype version written by Mark Diekhans and Karl Lehenbauer. * * Copyright (c) 1993 The Regents of the University of California. * Copyright (c) 1994 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclPort.h" |
| ︙ | ︙ |
Changes to doc/Concat.3.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | .nf \fB#include <tcl.h>\fR .sp const char * \fBTcl_Concat\fR(\fIargc, argv\fR) .fi .SH ARGUMENTS | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | .nf \fB#include <tcl.h>\fR .sp const char * \fBTcl_Concat\fR(\fIargc, argv\fR) .fi .SH ARGUMENTS .AS "const char *const" argv[] .AP Tcl_Size argc in Number of strings. .AP "const char *const" argv[] in Array of strings to concatenate. Must have \fIargc\fR entries. .BE .SH DESCRIPTION .PP \fBTcl_Concat\fR is a utility procedure used by several of the Tcl commands. Given a collection of strings, it concatenates |
| ︙ | ︙ |
Changes to doc/CrtTimerHdlr.3.
1 2 3 4 5 6 7 8 9 10 11 | '\" '\" Copyright (c) 1990 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_CreateTimerHandler 3 7.5 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME | | < < < < < < < < | < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
'\"
'\" Copyright (c) 1990 The Regents of the University of California.
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH Tcl_CreateTimerHandler 3 7.5 Tcl "Tcl Library Procedures"
.so man.macros
.BS
.SH NAME
Tcl_CreateTimerHandler, Tcl_DeleteTimerHandler \- call a procedure at a given time
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
.sp
Tcl_TimerToken
\fBTcl_CreateTimerHandler\fR(\fImilliseconds, proc, clientData\fR)
.sp
\fBTcl_DeleteTimerHandler\fR(\fItoken\fR)
.fi
.SH ARGUMENTS
.AS Tcl_TimerToken milliseconds
.AP int milliseconds in
How many milliseconds to wait before invoking \fIproc\fR.
.AP Tcl_TimerProc *proc in
Procedure to invoke after \fImilliseconds\fR have elapsed.
.AP void *clientData in
Arbitrary one-word value to pass to \fIproc\fR.
.AP Tcl_TimerToken token in
Token for previously created timer handler (the return value
from some previous call to \fBTcl_CreateTimerHandler\fR).
.BE
.SH DESCRIPTION
.PP
\fBTcl_CreateTimerHandler\fR arranges for \fIproc\fR to be
invoked at a time \fImilliseconds\fR milliseconds in the
future.
The callback to \fIproc\fR will be made by \fBTcl_DoOneEvent\fR,
so \fBTcl_CreateTimerHandler\fR is only useful in programs that
dispatch events through \fBTcl_DoOneEvent\fR or through Tcl commands
such as \fBvwait\fR.
The call to \fIproc\fR may not be made at the exact time given by
\fImilliseconds\fR: it will be made at the next opportunity
after that time. For example, if \fBTcl_DoOneEvent\fR is not
called until long after the time has elapsed, or if there
are other pending events to process before the call to
\fIproc\fR, then the call to \fIproc\fR will be delayed.
.PP
\fIProc\fR should have arguments and return value that match
the type \fBTcl_TimerProc\fR:
.PP
.CS
typedef void \fBTcl_TimerProc\fR(
void *\fIclientData\fR);
.CE
.PP
The \fIclientData\fR parameter to \fIproc\fR is a
copy of the \fIclientData\fR argument given to
\fBTcl_CreateTimerHandler\fR when the callback
was created. Typically, \fIclientData\fR points to a data
structure containing application-specific information about
what to do in \fIproc\fR.
.PP
\fBTcl_DeleteTimerHandler\fR may be called to delete a
previously created timer handler. It deletes the handler
indicated by \fItoken\fR so that no call to \fIproc\fR
will be made; if that handler no longer exists
(e.g. because the time period has already elapsed and \fIproc\fR
has been invoked then \fBTcl_DeleteTimerHandler\fR does nothing.
The tokens returned by \fBTcl_CreateTimerHandler\fR never have
a value of NULL, so if NULL is passed to \fBTcl_DeleteTimerHandler\fR
then the procedure does nothing.
.SH "SEE ALSO"
after(n), Tcl_CreateFileHandler(3), Tcl_DoWhenIdle(3)
.SH KEYWORDS
callback, clock, handler, timer
|
Changes to doc/DetachPids.3.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 | .AP int options in The options controlling the wait. WNOHANG specifies not to wait when checking the process. .BE .SH DESCRIPTION .PP \fBTcl_DetachPids\fR and \fBTcl_ReapDetachedProcs\fR provide a | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | .AP int options in The options controlling the wait. WNOHANG specifies not to wait when checking the process. .BE .SH DESCRIPTION .PP \fBTcl_DetachPids\fR and \fBTcl_ReapDetachedProcs\fR provide a mechanism for managing subprocesses that are running in the background. These procedures are needed because the parent of a process must eventually invoke the \fBwaitpid\fR kernel call (or one of a few other similar kernel calls) to wait for the child to exit. Until the parent waits for the child, the child's state cannot be completely reclaimed by the system. If a parent continually creates children and doesn't wait on them, the system's process table will eventually overflow, even if all the children have exited. .PP \fBTcl_DetachPids\fR may be called to ask Tcl to take responsibility for one or more processes whose process ids are contained in the \fIpidPtr\fR array passed as argument. The caller presumably has started these processes running in the background and does not want to have to deal with them again. .PP \fBTcl_ReapDetachedProcs\fR invokes the \fBwaitpid\fR kernel call on each of the background processes so that its state can be cleaned up if it has exited. If the process has not exited yet, \fBTcl_ReapDetachedProcs\fR does not wait for it to exit; it will check again the next time it is invoked. |
| ︙ | ︙ |
Changes to doc/Encoding.3.
1 2 3 4 5 6 7 8 9 10 | '\" '\" Copyright (c) 1997-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_GetEncoding 3 "8.1" Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | '\" '\" Copyright (c) 1997-1998 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_GetEncoding 3 "8.1" Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME Tcl_GetEncoding, Tcl_FreeEncoding, Tcl_GetEncodingFromObj, Tcl_ExternalToUtfDString, Tcl_ExternalToUtfDStringEx, Tcl_ExternalToUtf, Tcl_UtfToExternalDString, Tcl_UtfToExternalDStringEx, Tcl_UtfToExternal, Tcl_GetEncodingName, Tcl_SetSystemEncoding, Tcl_GetEncodingNameFromEnvironment, Tcl_GetEncodingNames, Tcl_CreateEncoding, Tcl_GetEncodingSearchPath, Tcl_SetEncodingSearchPath \- procedures for creating and using encodings .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp Tcl_Encoding \fBTcl_GetEncoding\fR(\fIinterp, name\fR) .sp |
| ︙ | ︙ | |||
30 31 32 33 34 35 36 | char * \fBTcl_UtfToExternalDString\fR(\fIencoding, src, srcLen, dstPtr\fR) .sp int \fBTcl_UtfToExternalDStringEx\fR(\fIinterp, encoding, src, srcLen, flags, dstPtr, errorIdxPtr\fR) .sp int | < < < | < < < | < < < | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | char * \fBTcl_UtfToExternalDString\fR(\fIencoding, src, srcLen, dstPtr\fR) .sp int \fBTcl_UtfToExternalDStringEx\fR(\fIinterp, encoding, src, srcLen, flags, dstPtr, errorIdxPtr\fR) .sp int \fBTcl_ExternalToUtf\fR(\fIinterp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr\fR) .sp int \fBTcl_UtfToExternal\fR(\fIinterp, encoding, src, srcLen, flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr, dstCharsPtr\fR) .sp const char * \fBTcl_GetEncodingName\fR(\fIencoding\fR) .sp Tcl_Size \fBTcl_GetEncodingNulLength\fR(\fIencoding\fR) .sp int \fBTcl_SetSystemEncoding\fR(\fIinterp, name\fR) .sp const char * \fBTcl_GetEncodingNameFromEnvironment\fR(\fIbufPtr\fR) .sp \fBTcl_GetEncodingNames\fR(\fIinterp\fR) .sp Tcl_Encoding \fBTcl_CreateEncoding\fR(\fItypePtr\fR) .sp Tcl_Obj * \fBTcl_GetEncodingSearchPath\fR() .sp int \fBTcl_SetEncodingSearchPath\fR(\fIsearchPath\fR) .fi .SH ARGUMENTS .AS "const Tcl_EncodingType" *dstWrotePtr in/out .AP Tcl_Interp *interp in Interpreter to use for error reporting, or NULL if no error reporting is desired. .AP "const char" *name in Name of encoding to load. .AP Tcl_Encoding encoding in The encoding to query, free, or use for converting text. If \fIencoding\fR is |
| ︙ | ︙ | |||
96 97 98 99 100 101 102 | Length of \fIsrc\fR or \fItsrc\fR in bytes. If the length is negative, the encoding-specific length of the string is used. .AP Tcl_DString *dstPtr out Pointer to an uninitialized or free \fBTcl_DString\fR in which the converted result will be stored. .AP int flags in This is a bit mask passed in to control the operation of the encoding functions. | > > > > > > > > > > > > > > | < | > > > > > > > < < | | < < > | | | < < < | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | Length of \fIsrc\fR or \fItsrc\fR in bytes. If the length is negative, the encoding-specific length of the string is used. .AP Tcl_DString *dstPtr out Pointer to an uninitialized or free \fBTcl_DString\fR in which the converted result will be stored. .AP int flags in This is a bit mask passed in to control the operation of the encoding functions. \fBTCL_ENCODING_START\fR signifies that the source buffer is the first block in a (potentially multi-block) input stream, telling the conversion routine to reset to an initial state and perform any initialization that needs to occur before the first byte is converted. \fBTCL_ENCODING_END\fR signifies that the source buffer is the last block in a (potentially multi-block) input stream, telling the conversion routine to perform any finalization that needs to occur after the last byte is converted and then to reset to an initial state. The \fBTCL_PROFILE_*\fR bits defined in the \fBPROFILES\fR section below control the encoding profile to be used for dealing with invalid data or other errors in the encoding transform. The flag \fBTCL_ENCODING_STOPONERROR\fR has no effect, it only has meaning in Tcl 8.x. Some flags bits may not be usable with some functions as noted in the function descriptions below. .AP Tcl_EncodingState *statePtr in/out Used when converting a (generally long or indefinite length) byte stream in a piece-by-piece fashion. The conversion routine stores its current state in \fI*statePtr\fR after \fIsrc\fR (the buffer containing the current piece) has been converted; that state information must be passed back when converting the next piece of the stream so the conversion routine knows what state it was in when it left off at the end of the last piece. May be NULL, in which case the value specified for \fIflags\fR is ignored and the source buffer is assumed to contain the complete string to convert. .AP char *dst out Buffer in which the converted result will be stored. No more than \fIdstLen\fR bytes will be stored in \fIdst\fR. .AP Tcl_Size dstLen in The maximum length of the output buffer \fIdst\fR in bytes. .AP int *srcReadPtr out Filled with the number of bytes from \fIsrc\fR that were actually converted. This may be less than the original source length if there was a problem converting some source characters. May be NULL. .AP int *dstWrotePtr out Filled with the number of bytes that were actually stored in the output buffer as a result of the conversion. May be NULL. .AP int *dstCharsPtr out Filled with the number of characters that correspond to the number of bytes stored in the output buffer. May be NULL. .AP Tcl_Size *errorIdxPtr out Filled with the index of the byte or character that caused the encoding transform to fail. May be NULL. .AP Tcl_DString *bufPtr out Storage for the prescribed system encoding name. .AP "const Tcl_EncodingType" *typePtr in Structure that defines a new type of encoding. |
| ︙ | ︙ | |||
154 155 156 157 158 159 160 | staging ground for all the various encodings. In the example above, text would be translated into TUTF-8 from whatever file encoding the operating system is using. Then it would be translated from TUTF-8 into whatever font encoding the display routines require. .PP Some basic encodings are compiled into Tcl. Others can be defined by the user or dynamically loaded from encoding files in a platform-independent manner. | | | | | | > | | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | staging ground for all the various encodings. In the example above, text would be translated into TUTF-8 from whatever file encoding the operating system is using. Then it would be translated from TUTF-8 into whatever font encoding the display routines require. .PP Some basic encodings are compiled into Tcl. Others can be defined by the user or dynamically loaded from encoding files in a platform-independent manner. .SH DESCRIPTION .PP \fBTcl_GetEncoding\fR finds an encoding given its \fIname\fR. The name may refer to a built-in Tcl encoding, a user-defined encoding registered by calling \fBTcl_CreateEncoding\fR, or a dynamically-loadable encoding file. The return value is a token that represents the encoding and can be used in subsequent calls to procedures such as \fBTcl_GetEncodingName\fR, \fBTcl_FreeEncoding\fR, and \fBTcl_UtfToExternal\fR. If the name did not refer to any known or loadable encoding, NULL is returned and an error message is returned in \fIinterp\fR. .PP The encoding package maintains a database of all encodings currently in use. The first time \fIname\fR is seen, \fBTcl_GetEncoding\fR returns an encoding with a reference count of 1. If the same \fIname\fR is requested further times, then the reference count for that encoding is incremented without the overhead of allocating a new encoding and all its associated data structures. |
| ︙ | ︙ | |||
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | \fBTcl_Encoding\fR token is written to the storage pointed to by \fIencodingPtr\fR, and the value \fBTCL_OK\fR is returned. If no such encoding is found, the value \fBTCL_ERROR\fR is returned, and no writing to \fB*\fR\fIencodingPtr\fR takes place. Just as with \fBTcl_GetEncoding\fR, the caller should call \fBTcl_FreeEncoding\fR on the resulting encoding token when that token will no longer be used. .PP \fBTcl_GetEncodingName\fR is roughly the inverse of \fBTcl_GetEncoding\fR. Given an \fIencoding\fR, the return value is the \fIname\fR argument that was used to create the encoding. The string returned by \fBTcl_GetEncodingName\fR is only guaranteed to persist until the \fIencoding\fR is deleted. The caller must not modify this string. .PP \fBTcl_GetEncodingNulLength\fR returns the length of the terminating nul byte sequence for strings in the specified encoding. .PP \fBTcl_SetSystemEncoding\fR sets the default encoding that should be used whenever the user passes a NULL value for the \fIencoding\fR argument to any of the other encoding functions. If \fIname\fR is NULL, the system encoding is reset to the default system encoding, \fBbinary\fR. If the name did not refer to any known or loadable encoding, \fBTCL_ERROR\fR is returned and an error message is left in \fIinterp\fR. Otherwise, this procedure increments the reference count of the new system encoding, decrements the reference count of the old system encoding, and returns \fBTCL_OK\fR. .PP | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < < < < < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | \fBTcl_Encoding\fR token is written to the storage pointed to by \fIencodingPtr\fR, and the value \fBTCL_OK\fR is returned. If no such encoding is found, the value \fBTCL_ERROR\fR is returned, and no writing to \fB*\fR\fIencodingPtr\fR takes place. Just as with \fBTcl_GetEncoding\fR, the caller should call \fBTcl_FreeEncoding\fR on the resulting encoding token when that token will no longer be used. .PP \fBTcl_ExternalToUtfDString\fR converts a source buffer \fIsrc\fR from the specified \fIencoding\fR into TUTF-8. The converted bytes are stored in \fIdstPtr\fR, which is then null-terminated. The caller should eventually call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR. When converting, if any of the characters in the source buffer cannot be represented in the target encoding, a default fallback character will be used. The return value is a pointer to the value stored in the DString. .PP \fBTcl_ExternalToUtfDStringEx\fR is a more flexible version of older \fBTcl_ExternalToUtfDString\fR function. It takes three additional parameters, \fBinterp\fR, \fBflags\fR and \fBerrorIdxPtr\fR. The \fBflags\fR parameter may be used to specify the profile to be used for the transform. The \fBTCL_ENCODING_START\fR and \fBTCL_ENCODING_END\fR bits in \fBflags\fR are ignored as the function assumes the entire source string to be decoded is passed into the function. On success, the function returns \fBTCL_OK\fR with the converted string stored in \fB*dstPtr\fR. For errors \fIother than conversion errors\fR, such as invalid flags, the function returns \fBTCL_ERROR\fR with an error message in \fBinterp\fR if it is not NULL. For conversion errors, \fBTcl_ExternalToUtfDStringEx\fR returns one of the \fBTCL_CONVERT_*\fR errors listed below for \fBTcl_ExternalToUtf\fR. When one of these conversion errors is returned, an error message is stored in \fBinterp\fR only if \fBerrorIdxPtr\fR is NULL. Otherwise, no error message is stored as the function expects the caller is interested the decoded data up to that point and not treating this as an immediate error condition. The index of the error location is stored in \fB*errorIdxPtr\fR. .PP The caller must call \fBTcl_DStringFree\fR to free up the \fB*dstPtr\fR resources irrespective of the return value from the function. .PP \fBTcl_ExternalToUtf\fR converts a source buffer \fIsrc\fR from the specified \fIencoding\fR into TUTF-8. Up to \fIsrcLen\fR bytes are converted from the source buffer and up to \fIdstLen\fR converted bytes are stored in \fIdst\fR. In all cases, \fI*srcReadPtr\fR is filled with the number of bytes that were successfully converted from \fIsrc\fR and \fI*dstWrotePtr\fR is filled with the corresponding number of bytes that were stored in \fIdst\fR. The return value is one of the following: .RS .IP \fBTCL_OK\fR 29 All bytes of \fIsrc\fR were converted. .IP \fBTCL_CONVERT_NOSPACE\fR 29 The destination buffer was not large enough for all of the converted data; as many characters as could fit were converted though. .IP \fBTCL_CONVERT_MULTIBYTE\fR 29 The last few bytes in the source buffer were the beginning of a multibyte sequence, but more bytes were needed to complete this sequence. A subsequent call to the conversion routine should pass a buffer containing the unconverted bytes that remained in \fIsrc\fR plus some further bytes from the source stream to properly convert the formerly split-up multibyte sequence. .IP \fBTCL_CONVERT_SYNTAX\fR 29 The source buffer contained an invalid byte or character sequence. This may occur if the input stream has been damaged or if the input encoding method was misidentified. .IP \fBTCL_CONVERT_UNKNOWN\fR 29 The source buffer contained a character that could not be represented in the target encoding. .RE .LP \fBTcl_UtfToExternalDString\fR converts a source buffer \fIsrc\fR from TUTF-8 into the specified \fIencoding\fR. The converted bytes are stored in \fIdstPtr\fR, which is then terminated with the appropriate encoding-specific null. The caller should eventually call \fBTcl_DStringFree\fR to free any information stored in \fIdstPtr\fR. When converting, if any of the characters in the source buffer cannot be represented in the target encoding, a default fallback character will be used. The return value is a pointer to the value stored in the DString. .PP \fBTcl_UtfToExternalDStringEx\fR is an enhanced version of \fBTcl_UtfToExternalDString\fR that transforms TUTF-8 encoded source data to a specified \fIencoding\fR. Except for the direction of the transform, the parameters and return values are identical to those of \fBTcl_ExternalToUtfDStringEx\fR. See that function above for details about the same. .PP Irrespective of the return code from the function, the caller must free resources associated with \fB*dstPtr\fR when the function returns. .PP \fBTcl_UtfToExternal\fR converts a source buffer \fIsrc\fR from TUTF-8 into the specified \fIencoding\fR. Up to \fIsrcLen\fR bytes are converted from the source buffer and up to \fIdstLen\fR converted bytes are stored in \fIdst\fR. In all cases, \fI*srcReadPtr\fR is filled with the number of bytes that were successfully converted from \fIsrc\fR and \fI*dstWrotePtr\fR is filled with the corresponding number of bytes that were stored in \fIdst\fR. The return values are the same as the return values for \fBTcl_ExternalToUtf\fR. .PP \fBTcl_GetEncodingName\fR is roughly the inverse of \fBTcl_GetEncoding\fR. Given an \fIencoding\fR, the return value is the \fIname\fR argument that was used to create the encoding. The string returned by \fBTcl_GetEncodingName\fR is only guaranteed to persist until the \fIencoding\fR is deleted. The caller must not modify this string. .PP \fBTcl_GetEncodingNulLength\fR returns the length of the terminating nul byte sequence for strings in the specified encoding. .PP \fBTcl_SetSystemEncoding\fR sets the default encoding that should be used whenever the user passes a NULL value for the \fIencoding\fR argument to any of the other encoding functions. If \fIname\fR is NULL, the system encoding is reset to the default system encoding, \fBbinary\fR. If the name did not refer to any known or loadable encoding, \fBTCL_ERROR\fR is returned and an error message is left in \fIinterp\fR. Otherwise, this procedure increments the reference count of the new system encoding, decrements the reference count of the old system encoding, and returns \fBTCL_OK\fR. .PP \fBTcl_GetEncodingNameFromEnvironment\fR provides a means for the Tcl library to report the encoding name it believes to be the correct one to use as the system encoding, based on system calls and examination of the environment suitable for the platform. It accepts \fIbufPtr\fR, a pointer to an uninitialized or freed \fBTcl_DString\fR and writes the encoding name to it. The \fBTcl_DStringValue\fR is returned. .PP \fBTcl_GetEncodingNames\fR sets the \fIinterp\fR result to a list consisting of the names of all the encodings that are currently defined or can be dynamically loaded, searching the encoding path specified by \fBTcl_SetEncodingSearchPath\fR. This procedure does not ensure that the dynamically-loadable encoding files contain valid data, but merely that they exist. .PP \fBTcl_CreateEncoding\fR defines a new encoding and registers the C procedures that are called back to convert between the encoding and TUTF-8. Encodings created by \fBTcl_CreateEncoding\fR are thereafter visible in the database used by \fBTcl_GetEncoding\fR. Just as with the \fBTcl_GetEncoding\fR procedure, the return value is a token that represents the encoding and can be used in subsequent calls to other |
| ︙ | ︙ | |||
445 446 447 448 449 450 451 |
void *\fIclientData\fR,
const char *\fIsrc\fR,
int \fIsrcLen\fR,
int \fIflags\fR,
Tcl_EncodingState *\fIstatePtr\fR,
char *\fIdst\fR,
int \fIdstLen\fR,
| | | | | | < | > | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
void *\fIclientData\fR,
const char *\fIsrc\fR,
int \fIsrcLen\fR,
int \fIflags\fR,
Tcl_EncodingState *\fIstatePtr\fR,
char *\fIdst\fR,
int \fIdstLen\fR,
int *\fIsrcReadPtr\fR,
int *\fIdstWrotePtr\fR,
int *\fIdstCharsPtr\fR);
.CE
.PP
The \fItoUtfProc\fR and \fIfromUtfProc\fR procedures are called by the
\fBTcl_ExternalToUtf\fR or \fBTcl_UtfToExternal\fR family of functions to
perform the actual conversion. The \fIclientData\fR parameter to these
procedures is the same as the \fIclientData\fR field specified to
\fBTcl_CreateEncoding\fR when the encoding was created. The remaining
arguments to the callback procedures are the same as the arguments,
documented at the top, to \fBTcl_ExternalToUtf\fR or
\fBTcl_UtfToExternal\fR, with the following exceptions. If the
\fIsrcLen\fR argument to one of those high-level functions is negative,
the value passed to the callback procedure will be the appropriate
encoding-specific string length of \fIsrc\fR. If any of the \fIsrcReadPtr\fR,
\fIdstWrotePtr\fR, or \fIdstCharsPtr\fR arguments to one of the high-level
functions is NULL, the corresponding value passed to the callback
procedure will be a non-NULL location.
.PP
The callback procedure \fIfreeProc\fR, if non-NULL, should match the type
\fBTcl_EncodingFreeProc\fR:
.PP
.CS
typedef void \fBTcl_EncodingFreeProc\fR(
void *\fIclientData\fR);
|
| ︙ | ︙ |
Changes to doc/FileSystem.3.
| ︙ | ︙ | |||
280 281 282 283 284 285 286 | If your extensions is compiled with \fB-DTCL_8_API\fR, this function will return NULL for paths having more than INT_MAX elements (which should trigger proper error-handling), otherwise expect it to crash. .AP Tcl_Obj *basePtr in The base path on to which to join the given elements. May be NULL. .AP Tcl_Size objc in The number of elements in \fIobjv\fR. | | | 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | If your extensions is compiled with \fB-DTCL_8_API\fR, this function will return NULL for paths having more than INT_MAX elements (which should trigger proper error-handling), otherwise expect it to crash. .AP Tcl_Obj *basePtr in The base path on to which to join the given elements. May be NULL. .AP Tcl_Size objc in The number of elements in \fIobjv\fR. .AP "Tcl_Obj *const" objv[] in The elements to join to the given base path. .AP Tcl_Obj *linkNamePtr in The name of the link to be created or read. .AP Tcl_Obj *toPtr in What the link called \fIlinkNamePtr\fR should be linked to, or NULL if the symbolic link specified by \fIlinkNamePtr\fR is to be read. .AP int linkAction in |
| ︙ | ︙ | |||
733 734 735 736 737 738 739 | .PP The resulting value is a pure .QW path value, which will only receive a UTF-8 string representation if that is required by some Tcl code. .PP \fBTcl_FSGetNativePath\fR is for use by the Win/Unix native | | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 | .PP The resulting value is a pure .QW path value, which will only receive a UTF-8 string representation if that is required by some Tcl code. .PP \fBTcl_FSGetNativePath\fR is for use by the Win/Unix native filesystems, so that they can easily retrieve the native (char* or TCHAR*) representation of a path. This function is a convenience wrapper around \fBTcl_FSGetInternalRep\fR. It may be desirable in the future to have non-string-based native representations (for example, on macOS, a representation using a fileSpec of FSRef structure would probably be more efficient). On Windows a full Unicode representation would allow for paths of unlimited length. Currently the representation is simply a character string which may contain either the relative path or a complete, absolute normalized path in the native encoding (complex |
| ︙ | ︙ |
Changes to doc/FindExec.3.
1 2 3 4 5 6 | '\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" | | > | | | < > > | > > > > > > | | | | | > | | > | | | | < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | '\" '\" Copyright (c) 1995-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_FindExecutable 3 8.1 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME Tcl_FindExecutable, Tcl_GetNameOfExecutable \- identify or return the name of the binary file containing the application .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp const char * \fBTcl_FindExecutable\fR(\fIargv0\fR) .sp const char * \fBTcl_GetNameOfExecutable\fR() .fi .SH ARGUMENTS .AS char *argv0 .AP char *argv0 in The first command-line argument to the program, which gives the application's name. .BE .SH DESCRIPTION .PP The \fBTcl_FindExecutable\fR procedure computes the full path name of the executable file from which the application was invoked and saves it for Tcl's internal use. The executable's path name is needed for several purposes in Tcl. For example, it is needed on some platforms in the implementation of the \fBload\fR command. It is also returned by the \fBinfo nameofexecutable\fR command. .PP The result of \fBTcl_FindExecutable\fR is the full Tcl version with build information (e.g., \fB9.0.0+abcdef...abcdef.gcc-1002\fR). .PP On UNIX platforms this procedure is typically invoked as the very first thing in the application's main program; it must be passed \fIargv[0]\fR as its argument. It is important not to change the working directory before the invocation. \fBTcl_FindExecutable\fR uses \fIargv0\fR along with the \fBPATH\fR environment variable to find the application's executable, if possible. If it fails to find the binary, then future calls to \fBinfo nameofexecutable\fR will return an empty string. .PP On Windows platforms this procedure is typically invoked as the very first thing in the application's main program as well; Its \fIargv[0]\fR argument is only used to indicate whether the executable has a stderr channel (any non-null value) or not (the value null). If \fBTcl_SetPanicProc\fR is never called and no debugger is running, this determines whether the panic message is sent to stderr or to a standard system dialog. .PP \fBTcl_GetNameOfExecutable\fR simply returns a pointer to the internal full path name of the executable file as computed by \fBTcl_FindExecutable\fR. This procedure call is the C API equivalent to the \fBinfo nameofexecutable\fR command. NULL is returned if the internal full path name has not been computed or unknown. .PP \fBTcl_FindExecutable\fR can not be used in stub-enabled extensions. .SH KEYWORDS binary, executable file |
Changes to doc/GetInt.3.
| ︙ | ︙ | |||
71 72 73 74 75 76 77 | .QW \fB0o\fR then \fIsrc\fR is expected to be in octal form; otherwise, if the first such characters are .QW \fB0b\fR then \fIsrc\fR is expected to be in binary form; otherwise, \fIsrc\fR is expected to be in decimal form. | < < < < < < < < < < < < | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | .QW \fB0o\fR then \fIsrc\fR is expected to be in octal form; otherwise, if the first such characters are .QW \fB0b\fR then \fIsrc\fR is expected to be in binary form; otherwise, \fIsrc\fR is expected to be in decimal form. .PP \fBTcl_GetDouble\fR expects \fIsrc\fR to consist of a floating-point number, which is: white space; a sign; a sequence of digits; a decimal point .QW \fB.\fR ; a sequence of digits; the letter .QW \fBe\fR ; |
| ︙ | ︙ |
Changes to doc/GetTime.3.
1 2 3 4 5 6 7 8 9 10 | '\" '\" Copyright (c) 2001 Kevin B. Kenny <kennykb@acm.org>. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_GetTime 3 8.4 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME | | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | '\" '\" Copyright (c) 2001 Kevin B. Kenny <kennykb@acm.org>. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_GetTime 3 8.4 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME Tcl_GetTime, Tcl_SetTimeProc, Tcl_QueryTimeProc \- get date and time .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp \fBTcl_GetTime\fR(\fItimePtr\fR) .sp \fBTcl_SetTimeProc\fR(\fIgetProc, scaleProc, clientData\fR) .sp \fBTcl_QueryTimeProc\fR(\fIgetProcPtr, scaleProcPtr, clientDataPtr\fR) .fi .SH ARGUMENTS |
| ︙ | ︙ | |||
38 39 40 41 42 43 44 | .AP Tcl_ScaleTimeProc *scaleProcPtr out Pointer to place the currently registered scale handler function into. .AP void **clientDataPtr out Pointer to place the currently registered pass-through value into. .BE .SH DESCRIPTION .PP | < < < < < < < < < | < > | | | > | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
.AP Tcl_ScaleTimeProc *scaleProcPtr out
Pointer to place the currently registered scale handler function into.
.AP void **clientDataPtr out
Pointer to place the currently registered pass-through value into.
.BE
.SH DESCRIPTION
.PP
The \fBTcl_GetTime\fR function retrieves the current time as a
\fITcl_Time\fR structure in memory the caller provides. This
structure has the following definition:
.PP
.CS
typedef struct {
long long \fIsec\fR;
long \fIusec\fR;
} \fBTcl_Time\fR;
.CE
.PP
On return, the \fIsec\fR member of the structure is filled in with the
number of seconds that have elapsed since the \fIepoch:\fR the epoch
is the point in time of 00:00 UTC, 1 January 1970. This number does
\fInot\fR count leap seconds; an interval of one day advances it by
86400 seconds regardless of whether a leap second has been inserted.
.PP
The \fIusec\fR member of the structure is filled in with the number of
microseconds that have elapsed since the start of the second
designated by \fIsec\fR. The Tcl library makes every effort to keep
this number as precise as possible, subject to the limitations of the
computer system. On multiprocessor variants of Windows, this number
may be limited to the 10- or 20-ms granularity of the system clock.
(On single-processor Windows systems, the \fIusec\fR field is derived
from a performance counter and is highly precise.)
.SS "VIRTUALIZED TIME"
.PP
The \fBTcl_SetTimeProc\fR function registers two related handler functions
with the core. The first handler function is a replacement for
\fBTcl_GetTime\fR, or rather the OS access made by
\fBTcl_GetTime\fR. The other handler function is used by the Tcl
notifier to convert wait/block times from the virtual domain into real
time.
.PP
The \fBTcl_QueryTimeProc\fR function returns the currently registered
handler functions. If no external handlers were set then this will
return the standard handlers accessing and processing the native time
of the OS. The arguments to the function are allowed to be NULL; and
any argument which is NULL is ignored and not set.
.PP
The signatures of the handler functions are as follows:
.PP
.CS
typedef void \fBTcl_GetTimeProc\fR(
Tcl_Time *\fItimebuf\fR,
void *\fIclientData\fR);
typedef void \fBTcl_ScaleTimeProc\fR(
Tcl_Time *\fItimebuf\fR,
void *\fIclientData\fR);
.CE
.PP
The \fItimebuf\fR fields contain the time to manipulate, and the
\fIclientData\fR fields contain a pointer supplied at the time the handler
functions were registered.
.PP
Any handler pair specified has to return data which is consistent between
them. In other words, setting one handler of the pair to something assuming a
10-times slowdown, and the other handler of the pair to something assuming a
two-times slowdown is wrong and not allowed.
.PP
The set handler functions are allowed to run the delivered time backwards,
however this should be avoided. We have to allow it as the native time can run
backwards as the user can fiddle with the system time one way or other. Note
that the insertion of the hooks will not change the behavior of the Tcl core
with regard to this situation, i.e. the existing behavior is retained.
.SH "SEE ALSO"
clock(n)
.SH KEYWORDS
date, time
|
Changes to doc/Hash.3.
1 2 3 4 5 6 7 8 9 10 11 | '\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_Hash 3 "" Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME | | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | '\" '\" Copyright (c) 1989-1993 The Regents of the University of California. '\" Copyright (c) 1994-1996 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_Hash 3 "" Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME Tcl_InitHashTable, Tcl_InitCustomHashTable, Tcl_InitObjHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_DeleteHashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, Tcl_HashStats \- procedures to manage hash tables .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp \fBTcl_InitHashTable\fR(\fItablePtr, keyType\fR) .sp \fBTcl_InitCustomHashTable\fR(\fItablePtr, keyType, typePtr\fR) .sp \fBTcl_InitObjHashTable\fR(\fItablePtr\fR) .sp \fBTcl_DeleteHashTable\fR(\fItablePtr\fR) .sp Tcl_HashEntry * \fBTcl_CreateHashEntry\fR(\fItablePtr, key, newPtr\fR) .sp \fBTcl_DeleteHashEntry\fR(\fIentryPtr\fR) .sp Tcl_HashEntry * \fBTcl_FindHashEntry\fR(\fItablePtr, key\fR) .sp void * \fBTcl_GetHashValue\fR(\fIentryPtr\fR) |
| ︙ | ︙ | |||
169 170 171 172 173 174 175 | \fBTcl_CreateHashEntry\fR locates the entry corresponding to a particular key, creating a new entry in the table if there was not already one with the given key. If an entry already existed with the given key then \fI*newPtr\fR is set to zero. If a new entry was created, then \fI*newPtr\fR is set to a non-zero value and the value of the new entry will be set to zero. | < < < < < < | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | \fBTcl_CreateHashEntry\fR locates the entry corresponding to a particular key, creating a new entry in the table if there was not already one with the given key. If an entry already existed with the given key then \fI*newPtr\fR is set to zero. If a new entry was created, then \fI*newPtr\fR is set to a non-zero value and the value of the new entry will be set to zero. The return value from \fBTcl_CreateHashEntry\fR is a pointer to the entry, which may be used to retrieve and modify the entry's value or to delete the entry from the table. .PP \fBTcl_DeleteHashEntry\fR will remove an existing entry from a table. The memory associated with the entry itself will be freed, but the client is responsible for any cleanup associated with the entry's value, such as freeing a structure that it points to. .PP \fBTcl_FindHashEntry\fR is similar to \fBTcl_CreateHashEntry\fR |
| ︙ | ︙ | |||
281 282 283 284 285 286 287 | custom set of allocation routines might depend on, in order to avoid any circular dependency. .PP The \fIhashKeyProc\fR member contains the address of a function called to calculate a hash value for the key. .PP .CS | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
custom set of allocation routines might depend on, in order to avoid any
circular dependency.
.PP
The \fIhashKeyProc\fR member contains the address of a function called to
calculate a hash value for the key.
.PP
.CS
typedef TCL_HASH_TYPE \fBTcl_HashKeyProc\fR(
Tcl_HashTable *\fItablePtr\fR,
void *\fIkeyPtr\fR);
.CE
.PP
If this is NULL then \fIkeyPtr\fR is used and
\fBTCL_HASH_KEY_RANDOMIZE_HASH\fR is assumed.
.PP
|
| ︙ | ︙ | |||
315 316 317 318 319 320 321 | .CE .PP If this is NULL then \fBTcl_Alloc\fR is used to allocate enough space for a Tcl_HashEntry, the key pointer is assigned to key.oneWordValue and the clientData is set to NULL. String keys and array keys use this function to allocate enough space for the entry and the key in one block, rather than doing it in two blocks. This saves space for a pointer to the key from the | | | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
.CE
.PP
If this is NULL then \fBTcl_Alloc\fR is used to allocate enough space for a
Tcl_HashEntry, the key pointer is assigned to key.oneWordValue and the
clientData is set to NULL. String keys and array keys use this function to
allocate enough space for the entry and the key in one block, rather than
doing it in two blocks. This saves space for a pointer to the key from the
entry and another memory allocation. Tcl_Obj* keys use this function to
allocate enough space for an entry and increment the reference count on the
value.
.PP
The \fIfreeEntryProc\fR member contains the address of a function called to
free space for an entry.
.PP
.CS
typedef void \fBTcl_FreeHashEntryProc\fR(
Tcl_HashEntry *\fIhPtr\fR);
.CE
.PP
If this is NULL then \fBTcl_Free\fR is used to free the space for the entry.
Tcl_Obj* keys use this function to decrement the reference count on the
value.
.SH "REFERENCE COUNT MANAGEMENT"
.PP
When a hash table is created with \fBTcl_InitCustomHashTable\fR, the
\fBTcl_CreateHashEntry\fR function will increment the reference count of its
\fIkey\fR argument when it creates a key (but not if there is an existing
matching key). The reference count of the key will be decremented when the
corresponding hash entry is deleted, whether with \fBTcl_DeleteHashEntry\fR or
with \fBTcl_DeleteHashTable\fR. The \fBTcl_GetHashKey\fR function will return
the key without further modifying its reference count.
.PP
Custom hash tables that use a Tcl_Obj* as key will generally need to do
something similar in their \fIallocEntryProc\fR.
.SH "SEE ALSO"
Dict(3)
.SH KEYWORDS
hash table, key, lookup, search, value
|
Changes to doc/Init.3.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | \fB#include <tcl.h>\fR .sp int \fBTcl_Init\fR(\fIinterp\fR) .sp const char * \fBTcl_SetPreInitScript\fR(\fIscriptPtr\fR) | < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | \fB#include <tcl.h>\fR .sp int \fBTcl_Init\fR(\fIinterp\fR) .sp const char * \fBTcl_SetPreInitScript\fR(\fIscriptPtr\fR) .fi .SH ARGUMENTS .AS Tcl_Interp *interp .AP Tcl_Interp *interp in Interpreter to initialize. .AP "const char" *scriptPtr in Address of the initialization script. .BE .SH DESCRIPTION .PP \fBTcl_Init\fR is a helper procedure that finds and \fBsource\fRs the \fBinit.tcl\fR script, which should exist somewhere on the Tcl library path. .PP \fBTcl_Init\fR is typically called from \fBTcl_AppInit\fR procedures. .PP \fBTcl_SetPreInitScript\fR registers the pre-initialization script and returns the former (now replaced) script pointer. A value of \fINULL\fR may be passed to not register any script. The pre-initialization script is executed by \fBTcl_Init\fR before accessing the file system. The purpose is to typically prepare a custom file system (like an embedded zip-file) to be activated before the search. .PP When used in stub-enabled embedders, the stubs table must be first initialized using one of \fBTcl_InitSubsystems\fR, \fBTcl_SetPanicProc\fR, \fBTcl_FindExecutable\fR or \fBTclZipfs_AppHook\fR before \fBTcl_SetPreInitScript\fR may be called. .SH "SEE ALSO" Tcl_AppInit, Tcl_Main .SH KEYWORDS application, initialization, interpreter |
Changes to doc/InitSubSyst.3.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | .nf \fB#include <tcl.h>\fR .sp const char * \fBTcl_InitSubsystems\fR() .fi .BE | < | < > | < < < < < | < < < > | < < > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | .nf \fB#include <tcl.h>\fR .sp const char * \fBTcl_InitSubsystems\fR() .fi .BE .SH DESCRIPTION .PP The \fBTcl_InitSubsystems\fR procedure initializes the Tcl library. This procedure is typically invoked as the very first thing in the application's main program. .PP The result of \fBTcl_InitSubsystems\fR is the full Tcl version with build information (e.g., \fB9.0.0+abcdef...abcdef.gcc-1002\fR). .PP \fBTcl_InitSubsystems\fR is very similar in use to \fBTcl_FindExecutable\fR. It can be used when Tcl is used as utility library, no other encodings than utf-8, iso8859-1 or utf-16 are used, and no interest exists in the value of \fBinfo nameofexecutable\fR. The system encoding will not be extracted from the environment, but falls back to utf-8. .SH KEYWORDS binary, executable file |
Changes to doc/ListObj.3.
1 2 3 4 5 6 | '\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | '\" '\" Copyright (c) 1996-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_ListObj 3 8.0 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME Tcl_ListObjAppendList, Tcl_ListObjAppendElement, Tcl_NewListObj, Tcl_SetListObj, Tcl_ListObjGetElements, Tcl_ListObjLength, Tcl_ListObjIndex, Tcl_ListObjReplace \- manipulate Tcl values as lists .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp int \fBTcl_ListObjAppendList\fR(\fIinterp, listPtr, elemListPtr\fR) .sp |
| ︙ | ︙ | |||
31 32 33 34 35 36 37 | \fBTcl_ListObjLength\fR(\fIinterp, listPtr, lengthPtr\fR) .sp int \fBTcl_ListObjIndex\fR(\fIinterp, listPtr, index, objPtrPtr\fR) .sp int \fBTcl_ListObjReplace\fR(\fIinterp, listPtr, first, count, objc, objv\fR) | < < < < < < < < < | < < < | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | \fBTcl_ListObjLength\fR(\fIinterp, listPtr, lengthPtr\fR) .sp int \fBTcl_ListObjIndex\fR(\fIinterp, listPtr, index, objPtrPtr\fR) .sp int \fBTcl_ListObjReplace\fR(\fIinterp, listPtr, first, count, objc, objv\fR) .fi .SH ARGUMENTS .AS "Tcl_Obj *const" *elemListPtr in/out .AP Tcl_Interp *interp in If an error occurs while converting a value to be a list value, an error message is left in the interpreter's result value unless \fIinterp\fR is NULL. .AP Tcl_Obj *listPtr in/out Points to the list value to be manipulated. If \fIlistPtr\fR does not already point to a list value, an attempt will be made to convert it to one. .AP Tcl_Obj *elemListPtr in/out For \fBTcl_ListObjAppendList\fR, this points to a list value containing elements to be appended onto \fIlistPtr\fR. Each element of *\fIelemListPtr\fR will become a new element of \fIlistPtr\fR. If *\fIelemListPtr\fR is not NULL and does not already point to a list value, |
| ︙ | ︙ | |||
80 81 82 83 84 85 86 | If your extensions is compiled with \fB\-DTCL_8_API\fR, this function will return NULL for lists with more than INT_MAX elements (which should trigger proper error-handling), otherwise expect it to crash. .AP Tcl_Obj ***objvPtr out A location where \fBTcl_ListObjGetElements\fR stores a pointer to an array of pointers to the element values of \fIlistPtr\fR. .AP Tcl_Size objc in | | > > > > | | > > > | | < | | | | > > | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | If your extensions is compiled with \fB\-DTCL_8_API\fR, this function will return NULL for lists with more than INT_MAX elements (which should trigger proper error-handling), otherwise expect it to crash. .AP Tcl_Obj ***objvPtr out A location where \fBTcl_ListObjGetElements\fR stores a pointer to an array of pointers to the element values of \fIlistPtr\fR. .AP Tcl_Size objc in The number of Tcl values that \fBTcl_NewListObj\fR will insert into a new list value, and \fBTcl_ListObjReplace\fR will insert into \fIlistPtr\fR. For \fBTcl_SetListObj\fR, the number of Tcl values to insert into \fIobjPtr\fR. .AP "Tcl_Obj *const" objv[] in An array of pointers to values. \fBTcl_NewListObj\fR will insert these values into a new list value and \fBTcl_ListObjReplace\fR will insert them into an existing \fIlistPtr\fR. Each value will become a separate list element. .AP "Tcl_Size \&| int" *lengthPtr out Points to location where \fBTcl_ListObjLength\fR stores the length of the list. May be (Tcl_Size *)NULL when not used. If it points to a variable which type is not \fBTcl_Size\fR, a compiler warning will be generated. If your extensions is compiled with \fB-DTCL_8_API\fR, this function will return TCL_ERROR for lists with more than INT_MAX elements (which should trigger proper error-handling), otherwise expect it to crash. .AP Tcl_Size index in Index of the list element that \fBTcl_ListObjIndex\fR is to return. The first element has index 0. .AP Tcl_Obj **objPtrPtr out Points to place where \fBTcl_ListObjIndex\fR is to store a pointer to the resulting list element value. .AP Tcl_Size first in Index of the starting list element that \fBTcl_ListObjReplace\fR is to replace. The list's first element has index 0. .AP Tcl_Size count in The number of elements that \fBTcl_ListObjReplace\fR is to replace. .BE .SH DESCRIPTION .PP Tcl list values have an internal representation that supports the efficient indexing and appending. The procedures described in this man page are used to create, modify, index, and append to Tcl list values from C code. .PP \fBTcl_ListObjAppendList\fR and \fBTcl_ListObjAppendElement\fR both add one or more values to the end of the list value referenced by \fIlistPtr\fR. \fBTcl_ListObjAppendList\fR appends each element of the list value referenced by \fIelemListPtr\fR while \fBTcl_ListObjAppendElement\fR appends the single value |
| ︙ | ︙ | |||
209 210 211 212 213 214 215 216 217 218 219 220 221 222 | of 0. Abstract Lists create a new element Obj on demand, and do not retain any element Obj values. Therefore, the caller is responsible for freeing the element when it is no longer needed. Note that this is a change from Tcl 8 where all list elements always have a reference count of at least 1. (See \fBABSTRACT LIST TYPES\fR, \fBSTORAGE MANAGEMENT OF VALUES\fR, Tcl_BounceRefCount(3), and lseq(n) for more information.) .PP \fBTcl_ListObjReplace\fR replaces zero or more elements of the list referenced by \fIlistPtr\fR with the \fIobjc\fR values in the array referenced by \fIobjv\fR. If \fIlistPtr\fR does not point to a list value, \fBTcl_ListObjReplace\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR | > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | of 0. Abstract Lists create a new element Obj on demand, and do not retain any element Obj values. Therefore, the caller is responsible for freeing the element when it is no longer needed. Note that this is a change from Tcl 8 where all list elements always have a reference count of at least 1. (See \fBABSTRACT LIST TYPES\fR, \fBSTORAGE MANAGEMENT OF VALUES\fR, Tcl_BounceRefCount(3), and lseq(n) for more information.) .PP \fBTcl_ListObjReplace\fR replaces zero or more elements of the list referenced by \fIlistPtr\fR with the \fIobjc\fR values in the array referenced by \fIobjv\fR. If \fIlistPtr\fR does not point to a list value, \fBTcl_ListObjReplace\fR will attempt to convert it to one; if the conversion fails, it returns \fBTCL_ERROR\fR |
| ︙ | ︙ | |||
267 268 269 270 271 272 273 |
by simply calling \fBTcl_ListObjReplace\fR
with a NULL \fIobjvPtr\fR:
.PP
.CS
result = \fBTcl_ListObjReplace\fR(interp, listPtr, first, count,
0, NULL);
.CE
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | | | < | < < < < < | | < < < < < < | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
by simply calling \fBTcl_ListObjReplace\fR
with a NULL \fIobjvPtr\fR:
.PP
.CS
result = \fBTcl_ListObjReplace\fR(interp, listPtr, first, count,
0, NULL);
.CE
.SH "REFERENCE COUNT MANAGEMENT"
.PP
\fBTcl_NewListObj\fR always returns a zero-reference object, much like
\fBTcl_NewObj\fR. If a non-NULL \fIobjv\fR argument is given, the reference
counts of the first \fIobjc\fR values in that array are incremented.
.PP
\fBTcl_SetListObj\fR does not modify the reference count of its \fIobjPtr\fR
argument, but does require that the object be unshared. The reference counts
of the first \fIobjc\fR values in the \fIobjv\fR array are incremented.
.PP
\fBTcl_ListObjGetElements\fR, \fBTcl_ListObjIndex\fR, and
\fBTcl_ListObjLength\fR do not modify the reference count of their
\fIlistPtr\fR arguments; they only read. Note however that these three
functions may set the interpreter result; if that is the only place that is
holding a reference to the object, it will be deleted.
.PP
\fBTcl_ListObjAppendList\fR, \fBTcl_ListObjAppendElement\fR, and
\fBTcl_ListObjReplace\fR require an unshared \fIlistPtr\fR argument.
\fBTcl_ListObjAppendList\fR only reads its \fIelemListPtr\fR argument.
\fBTcl_ListObjAppendElement\fR increments the reference count of its
\fIobjPtr\fR on success. \fBTcl_ListObjReplace\fR increments the reference
count of the first \fIobjc\fR values in the \fIobjv\fR array on success. Note
however that all these three functions may set the interpreter result on
failure; if that is the only place that is holding a reference to the object,
it will be deleted.
.SH "SEE ALSO"
Tcl_NewObj(3), Tcl_DecrRefCount(3), Tcl_IncrRefCount(3), Tcl_GetObjResult(3)
.SH KEYWORDS
append, index, insert, internal representation, length, list, list value,
list type, value, value type, replace, string representation
|
Changes to doc/NRE.3.
| ︙ | ︙ | |||
158 159 160 161 162 163 164 |
stack, to evaluate a script:
.PP
.CS
int
\fITheCmdOldObjProc\fR(
void *clientData,
Tcl_Interp *interp,
| | | | | | | | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
stack, to evaluate a script:
.PP
.CS
int
\fITheCmdOldObjProc\fR(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int result;
Tcl_Obj *objPtr;
\fI... preparation ...\fR
result = \fBTcl_EvalObjEx\fR(interp, objPtr, 0);
\fI... postprocessing ...\fR
return result;
}
\fBTcl_CreateObjCommand\fR(interp, "theCommand",
\fITheCmdOldObjProc\fR, clientData, TheCmdDeleteProc);
.CE
.PP
To avoid consuming space on the C stack, \fITheCmdOldObjProc\fR is renamed to
\fITheCmdNRObjProc\fR and the postprocessing step is split into a separate
function, \fITheCmdPostProc\fR, which is pushed onto the function stack.
\fITcl_EvalObjEx\fR is replaced with \fITcl_NREvalObj\fR, which uses a
trampoline instead of consuming space on the C stack. A new version of
\fITheCmdOldObjProc\fR is just a a wrapper that uses \fBTcl_NRCallObjProc\fR to
call \fITheCmdNRObjProc\fR:
.PP
.CS
int
\fITheCmdOldObjProc\fR(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
return \fBTcl_NRCallObjProc\fR(interp, \fITheCmdNRObjProc\fR,
clientData, objc, objv);
}
.CE
.PP
.CS
int
\fITheCmdNRObjProc\fR
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *objPtr;
\fI... preparation ...\fR
\fBTcl_NRAddCallback\fR(interp, \fITheCmdPostProc\fR,
data0, data1, data2, data3);
|
| ︙ | ︙ |
Changes to doc/Number.3.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 | in any of the numeric formats recognized by Tcl. .AP "const char" *bytes in Points to first byte of the string value to be examined. .AP Tcl_Size numBytes in The number of bytes, starting at \fIbytes\fR, that should be examined. If \fBnumBytes\fR is negative, then all bytes should be examined until the first \fBNUL\fR byte terminates examination. | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | in any of the numeric formats recognized by Tcl. .AP "const char" *bytes in Points to first byte of the string value to be examined. .AP Tcl_Size numBytes in The number of bytes, starting at \fIbytes\fR, that should be examined. If \fBnumBytes\fR is negative, then all bytes should be examined until the first \fBNUL\fR byte terminates examination. .AP "void *" *clientDataPtr out Points to space where a pointer value may be written through which a numeric value is available to read. .AP int *typePtr out Points to space where a value may be written reporting what type of numeric storage is available to read. .AP Tcl_Obj *objPtr in A Tcl value to be examined. |
| ︙ | ︙ |
Changes to doc/ObjectType.3.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | .AP Tcl_Interp *interp in Interpreter to use for error reporting. .AP Tcl_Obj *objPtr in For \fBTcl_AppendAllObjTypes\fR, this points to the value onto which it appends the name of each value type as a list element. For \fBTcl_ConvertToType\fR, this points to a value that must have been the result of a previous call to \fBTcl_NewObj\fR. | | | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | .AP Tcl_Interp *interp in Interpreter to use for error reporting. .AP Tcl_Obj *objPtr in For \fBTcl_AppendAllObjTypes\fR, this points to the value onto which it appends the name of each value type as a list element. For \fBTcl_ConvertToType\fR, this points to a value that must have been the result of a previous call to \fBTcl_NewObj\fR. .AP "const char*" bytes in String representation. .AP "size_t" numBytes in Length of the string representation in bytes. .AP "const Tcl_ObjInternalRep *" irPtr in Internal object representation. .AP "const Tcl_ObjType *" typePtr in Requested internal representation type. .BE .SH DESCRIPTION .PP The procedures in this man page manage Tcl value types (sometimes referred to as object types or \fBTcl_ObjType\fRs for historical reasons). |
| ︙ | ︙ | |||
345 346 347 348 349 350 351 | .PP Additional fields in the Tcl_ObjType descriptor allow for control over how custom data values can be manipulated using Tcl's List commands without converting the value to a List type. This requires the custom type to provide functions that will perform the given operation on the custom data representation. Not all functions are required. In the absence of a particular function (set to NULL), the fallback is to | | | < < < < < < < < < < < < | | < < < | | | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
.PP
Additional fields in the Tcl_ObjType descriptor allow for control over
how custom data values can be manipulated using Tcl's List commands
without converting the value to a List type. This requires the custom
type to provide functions that will perform the given operation on the
custom data representation. Not all functions are required. In the
absence of a particular function (set to NULL), the fallback is to
allow the internal List operation to perform the operation, most
likely causing the value type to be converted to a traditional list.
.SS "SCALAR VALUE TYPES"
.PP
For a custom value type that is scalar or atomic in nature, i.e., not
a divisible collection, version \fBTCL_OBJTYPE_V1\fR is
recommended. In this case, List commands will treat the scalar value
as if it where a list of length 1, and not convert the value to a List
type.
.SS "VERSION 2: ABSTRACT LISTS"
.PP
Version 2, \fBTCL_OBJTYPE_V2\fR, allows full List support when the
functions described below are provided. This allows for script level
use of the List commands without causing the type of the Tcl_Obj value
to be converted to a list.
.SS "THE LENGTHPROC FIELD"
.PP
The \fBLengthProc\fR function correlates with the \fBTcl_ListObjLength\fR
C API. The function returns the number of elements in the list. It
is used in every List operation and is required for all Abstract List
implementations.
.CS
typedef Tcl_Size
(Tcl_ObjTypeLengthProc) (Tcl_Obj *listPtr);
.CE
.PP
.SS "THE INDEXPROC FIELD"
.PP
The \fBIndexProc\fR function correlates with with the
\fBTcl_ListObjIndex\fR C API. The function returns a Tcl_Obj value for
the element at the specified index.
.CS
typedef int (\fBTcl_ObjTypeIndexProc\fR) (
Tcl_Interp *interp,
Tcl_Obj *listPtr,
Tcl_Size index,
Tcl_Obj** elemObj);
.CE
.SS "THE SLICEPROC FIELD"
.PP
The \fBSliceProc\fR correlates with the \fBlrange\fR command,
returning a new List or Abstract List for the portion of the original
list specified.
.CS
typedef int (\fBTcl_ObjTypeSliceProc\fR) (
Tcl_Interp *interp,
Tcl_Obj *listPtr,
Tcl_Size fromIdx,
Tcl_Size toIdx,
Tcl_Obj **newObjPtr);
.CE
.SS "THE REVERSEPROC FIELD"
.PP
The \fBReverseProc\fR correlates with the \fBlreverse\fR command,
returning a List or Abstract List that has the same elements as the
input Abstract List, with the elements in the reverse order.
.CS
typedef int (\fBTcl_ObjTypeReverseProc\fR) (
Tcl_Interp *interp,
Tcl_Obj *listPtr,
Tcl_Obj **newObjPtr);
.CE
.SS "THE GETELEMENTS FIELD"
|
| ︙ | ︙ |
Changes to doc/Panic.3.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 | const char * \fBTcl_SetPanicProc\fR(\fIpanicProc\fR) .sp \fBTcl_ConsolePanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR) .fi .SH ARGUMENTS .AS Tcl_PanicProc *panicProc | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | const char * \fBTcl_SetPanicProc\fR(\fIpanicProc\fR) .sp \fBTcl_ConsolePanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR) .fi .SH ARGUMENTS .AS Tcl_PanicProc *panicProc .AP "const char*" format in A printf-style format string. .AP "" arg in Arguments matching the format string. .AP Tcl_PanicProc *panicProc in Procedure to report fatal error message and abort. .BE .SH DESCRIPTION |
| ︙ | ︙ |
Changes to doc/PkgRequire.3.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | .AP void *clientDataPtr out Pointer to place to store the value associated with the matching package. It is only changed if the pointer is not NULL and the function completed successfully. The storage can be any pointer type with the same size as a void pointer. .AP Tcl_Size objc in Number of requirements. | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | .AP void *clientDataPtr out Pointer to place to store the value associated with the matching package. It is only changed if the pointer is not NULL and the function completed successfully. The storage can be any pointer type with the same size as a void pointer. .AP Tcl_Size objc in Number of requirements. .AP Tcl_Obj* objv[] in Array of requirements. .BE .SH DESCRIPTION .PP These procedures provide C-level interfaces to Tcl's package and version management facilities. .PP |
| ︙ | ︙ |
Changes to doc/SetChanErr.3.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 | .sp \fBTcl_GetChannelErrorInterp\fR(\fIinterp, msgPtr\fR) .fi .SH ARGUMENTS .AS Tcl_Channel chan .AP Tcl_Channel chan in Refers to the Tcl channel whose bypass area is accessed. | | | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | .sp \fBTcl_GetChannelErrorInterp\fR(\fIinterp, msgPtr\fR) .fi .SH ARGUMENTS .AS Tcl_Channel chan .AP Tcl_Channel chan in Refers to the Tcl channel whose bypass area is accessed. .AP Tcl_Interp* interp in Refers to the Tcl interpreter whose bypass area is accessed. .AP Tcl_Obj* msg in Error message put into a bypass area. A list of return options and values, followed by a string message. Both message and the option/value information are optional. This \fImust\fR be a well-formed list. .AP Tcl_Obj** msgPtr out Reference to a place where the message stored in the accessed bypass area can be stored in. .BE .SH DESCRIPTION .PP The standard definition of a Tcl channel driver does not permit the direct return of arbitrary error messages, except for the setting and retrieval of |
| ︙ | ︙ |
Changes to doc/Sleep.3.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | Tcl_Sleep \- delay execution for a given number of milliseconds .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp \fBTcl_Sleep\fR(\fIms\fR) .fi | < < < < < | | < < < | | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | Tcl_Sleep \- delay execution for a given number of milliseconds .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp \fBTcl_Sleep\fR(\fIms\fR) .fi .SH ARGUMENTS .AS int ms .AP int ms in Number of milliseconds to sleep. .BE .SH DESCRIPTION .PP This procedure delays the calling process by the number of milliseconds given by the \fIms\fR parameter and returns after that time has elapsed. It is typically used for things like flashing a button, where the delay is short and the application need not do anything while it waits. For longer delays where the application needs to respond to other events during the delay, the procedure \fBTcl_CreateTimerHandler\fR should be used instead of \fBTcl_Sleep\fR. .SH KEYWORDS sleep, time, wait |
Changes to doc/StringObj.3.
1 2 3 4 5 6 7 8 9 10 | '\" '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_StringObj 3 8.1 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | '\" '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH Tcl_StringObj 3 8.1 Tcl "Tcl Library Procedures" .so man.macros .BS .SH NAME Tcl_NewStringObj, Tcl_NewUnicodeObj, Tcl_SetStringObj, Tcl_SetUnicodeObj, Tcl_GetStringFromObj, Tcl_GetString, Tcl_GetUnicodeFromObj, Tcl_GetUnicode, Tcl_GetUniChar, Tcl_GetCharLength, Tcl_GetRange, Tcl_AppendToObj, Tcl_AppendUnicodeToObj, Tcl_AppendObjToObj, Tcl_AppendStringsToObj, Tcl_AppendLimitedToObj, Tcl_Format, Tcl_AppendFormatToObj, Tcl_ObjPrintf, Tcl_AppendPrintfToObj, Tcl_SetObjLength, Tcl_AttemptSetObjLength, Tcl_ConcatObj \- manipulate Tcl values as strings .SH SYNOPSIS .nf \fB#include <tcl.h>\fR .sp Tcl_Obj * \fBTcl_NewStringObj\fR(\fIbytes, length\fR) .sp |
| ︙ | ︙ | |||
77 78 79 80 81 82 83 | \fBTcl_SetObjLength\fR(\fIobjPtr, newLength\fR) .sp int \fBTcl_AttemptSetObjLength\fR(\fIobjPtr, newLength\fR) .sp Tcl_Obj * \fBTcl_ConcatObj\fR(\fIobjc, objv\fR) | < < < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | \fBTcl_SetObjLength\fR(\fIobjPtr, newLength\fR) .sp int \fBTcl_AttemptSetObjLength\fR(\fIobjPtr, newLength\fR) .sp Tcl_Obj * \fBTcl_ConcatObj\fR(\fIobjc, objv\fR) .fi .SH ARGUMENTS .AS "const Tcl_UniChar" *appendObjPtr in/out .AP "const char" *bytes in Points to a TUTF-8 (Tcl's internal modified UTF-8 encoding) byte sequence bytes used to set or append to a string value. This byte array may contain embedded null characters |
| ︙ | ︙ | |||
140 141 142 143 144 145 146 | If NULL is passed then the suffix .QW "..." is used. .AP "const char" *format in Format control string including % conversion specifiers. .AP Tcl_Size objc in The number of elements to format or concatenate. | | | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | If NULL is passed then the suffix .QW "..." is used. .AP "const char" *format in Format control string including % conversion specifiers. .AP Tcl_Size objc in The number of elements to format or concatenate. .AP Tcl_Obj *objv[] in The array of values to format or concatenate. .AP Tcl_Size newLength in New length for the string value of \fIobjPtr\fR, not including the final null character. .BE .SH DESCRIPTION .PP |
| ︙ | ︙ | |||
403 404 405 406 407 408 409 | array. \fBTcl_ConcatObj\fR eliminates leading and trailing white space as it copies the string representations of the \fIobjv\fR array to the result. If an element of the \fIobjv\fR array consists of nothing but white space, then that value is ignored entirely. This white-space removal was added to make the output of the \fBconcat\fR command cleaner-looking. \fBTcl_ConcatObj\fR returns a pointer to a newly-created value whose ref count is zero. | < < < < < < < | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | array. \fBTcl_ConcatObj\fR eliminates leading and trailing white space as it copies the string representations of the \fIobjv\fR array to the result. If an element of the \fIobjv\fR array consists of nothing but white space, then that value is ignored entirely. This white-space removal was added to make the output of the \fBconcat\fR command cleaner-looking. \fBTcl_ConcatObj\fR returns a pointer to a newly-created value whose ref count is zero. .SH "REFERENCE COUNT MANAGEMENT" .PP \fBTcl_NewStringObj\fR, \fBTcl_NewUnicodeObj\fR, \fBTcl_Format\fR, \fBTcl_ObjPrintf\fR, and \fBTcl_ConcatObj\fR always return a zero-reference object, much like \fBTcl_NewObj\fR. .PP \fBTcl_GetStringFromObj\fR, \fBTcl_GetString\fR, \fBTcl_GetUnicodeFromObj\fR, |
| ︙ | ︙ |
Changes to doc/Tcl_Main.3.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 | .sp \fBTcl_SetMainLoop\fR(\fImainLoopProc\fR) .fi .SH ARGUMENTS .AS Tcl_MainLoopProc *mainLoopProc .AP Tcl_Size argc in Number of elements in \fIargv\fR. | | | | | | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | .sp \fBTcl_SetMainLoop\fR(\fImainLoopProc\fR) .fi .SH ARGUMENTS .AS Tcl_MainLoopProc *mainLoopProc .AP Tcl_Size argc in Number of elements in \fIargv\fR. .AP char *argv[] in Array of strings containing command-line arguments. On Windows, when using \fB\-DUNICODE\fR, the parameter type changes to wchar_t *. .AP char *charargv[] in As argv, but does not change type to wchar_t. .AP char *wideargv[] in As argv, but type is always wchar_t. .AP Tcl_AppInitProc *appInitProc in Address of an application-specific initialization procedure. The value for this argument is usually \fBTcl_AppInit\fR. .AP Tcl_Obj *path in Name of file to use as startup script, or NULL. .AP "const char" *encoding in Encoding of file to use as startup script, or NULL. |
| ︙ | ︙ |
Changes to doc/TraceVar.3.
| ︙ | ︙ | |||
116 117 118 119 120 121 122 | The result of invoking the \fIproc\fR is a dynamically allocated string that will be released by the Tcl library via a call to \fBTcl_Free\fR. Must not be specified at the same time as \fBTCL_TRACE_RESULT_OBJECT\fR. .TP \fBTCL_TRACE_RESULT_OBJECT\fR . | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | The result of invoking the \fIproc\fR is a dynamically allocated string that will be released by the Tcl library via a call to \fBTcl_Free\fR. Must not be specified at the same time as \fBTCL_TRACE_RESULT_OBJECT\fR. .TP \fBTCL_TRACE_RESULT_OBJECT\fR . The result of invoking the \fIproc\fR is a Tcl_Obj* (cast to a char*) with a reference count of at least one. The ownership of that reference will be transferred to the Tcl core for release (when the core has finished with it) via a call to \fBTcl_DecrRefCount\fR. Must not be specified at the same time as \fBTCL_TRACE_RESULT_DYNAMIC\fR. .PP Whenever one of the specified operations occurs on the variable, \fIproc\fR will be invoked. |
| ︙ | ︙ | |||
316 317 318 319 320 321 322 | If \fIproc\fR returns a non-NULL value it signifies that an error occurred. The return value must be a pointer to a static character string containing an error message, unless (\fIexactly\fR one of) the \fBTCL_TRACE_RESULT_DYNAMIC\fR and \fBTCL_TRACE_RESULT_OBJECT\fR flags is set, which specify that the result is either a dynamic string (to be released with \fBTcl_Free\fR) or a | | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | If \fIproc\fR returns a non-NULL value it signifies that an error occurred. The return value must be a pointer to a static character string containing an error message, unless (\fIexactly\fR one of) the \fBTCL_TRACE_RESULT_DYNAMIC\fR and \fBTCL_TRACE_RESULT_OBJECT\fR flags is set, which specify that the result is either a dynamic string (to be released with \fBTcl_Free\fR) or a Tcl_Obj* (cast to char* and to be released with \fBTcl_DecrRefCount\fR) containing the error message. If a trace procedure returns an error, no further traces are invoked for the access and the traced access aborts with the given message. Trace procedures can use this facility to make variables read-only, for example (but note that the value of the variable will already have been modified before the trace procedure is |
| ︙ | ︙ |
Deleted doc/UnicodeNormalize.3.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to doc/WrongNumArgs.3.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | .AS "Tcl_Obj *const" *message .AP Tcl_Interp interp in Interpreter in which error will be reported: error message gets stored in its result value. .AP Tcl_Size objc in Number of leading arguments from \fIobjv\fR to include in error message. | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | .AS "Tcl_Obj *const" *message .AP Tcl_Interp interp in Interpreter in which error will be reported: error message gets stored in its result value. .AP Tcl_Size objc in Number of leading arguments from \fIobjv\fR to include in error message. .AP "Tcl_Obj *const" objv[] in Arguments to command that had the wrong number of arguments. .AP "const char" *message in Additional error information to print after leading arguments from \fIobjv\fR. This typically gives the acceptable syntax of the command. This argument may be NULL. .BE .SH DESCRIPTION |
| ︙ | ︙ |
Changes to doc/after.n.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | \fBafter idle \fR?\fIscript script script ...\fR? \fBafter info \fR?\fIid\fR? .fi .BE .SH DESCRIPTION .PP This command is used to delay execution of the program or to execute | | < | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | \fBafter idle \fR?\fIscript script script ...\fR? \fBafter info \fR?\fIid\fR? .fi .BE .SH DESCRIPTION .PP This command is used to delay execution of the program or to execute a command in the background sometime in the future. It has several forms, depending on the first argument to the command: .\" METHOD: <none> .TP \fBafter \fIms\fR . \fIMs\fR must be an integer giving a time in milliseconds. A negative number is treated as 0. The command sleeps for \fIms\fR milliseconds and then returns. |
| ︙ | ︙ | |||
59 60 61 62 63 64 65 | .\" METHOD: cancel .TP \fBafter cancel \fIid\fR . Cancels the execution of a delayed command that was previously scheduled. \fIId\fR indicates which command should be canceled; it must have | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | .\" METHOD: cancel .TP \fBafter cancel \fIid\fR . Cancels the execution of a delayed command that was previously scheduled. \fIId\fR indicates which command should be canceled; it must have been the return value from a previous \fBafter\fR command. If the command given by \fIid\fR has already been executed then the \fBafter cancel\fR command has no effect. .TP \fBafter cancel \fIscript script ...\fR . This command also cancels the execution of a delayed command. The \fIscript\fR arguments are concatenated together with space |
| ︙ | ︙ | |||
102 103 104 105 106 107 108 | \fIid\fR must have been the return value from some previous call to \fBafter\fR and it must not have triggered yet or been canceled. In this case the command returns a list with two elements. The first element of the list is the script associated with \fIid\fR, and the second element is either \fBidle\fR or \fBtimer\fR to indicate what kind of event handler it is. | < < < < < < < | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
\fIid\fR must have been the return value from some previous call
to \fBafter\fR and it must not have triggered yet or been canceled.
In this case the command returns a list with two elements.
The first element of the list is the script associated
with \fIid\fR, and the second element is either
\fBidle\fR or \fBtimer\fR to indicate what kind of event
handler it is.
.LP
The \fBafter \fIms\fR and \fBafter idle\fR forms of the command
assume that the application is event driven: the delayed commands
will not be executed unless the application enters the event loop.
In applications that are not normally event-driven, such as
\fBtclsh\fR, the event loop can be entered with the \fBvwait\fR
and \fBupdate\fR commands.
.SH "EXAMPLES"
This defines a command to make Tcl do nothing at all for \fIN\fR
seconds:
.PP
.CS
proc sleep {N} {
\fBafter\fR [expr {int($N * 1000)}]
|
| ︙ | ︙ | |||
152 153 154 155 156 157 158 |
proc doOneStep {} {
if {[::my_calc::one_step]} {
\fBafter idle\fR [list \fBafter\fR 0 doOneStep]
}
}
doOneStep
.CE
| < < < < < < < < | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
proc doOneStep {} {
if {[::my_calc::one_step]} {
\fBafter idle\fR [list \fBafter\fR 0 doOneStep]
}
}
doOneStep
.CE
.SH "SEE ALSO"
concat(n), interp(n), update(n), vwait(n)
.SH KEYWORDS
cancel, delay, idle callback, sleep, time
'\" Local Variables:
'\" mode: nroff
'\" End:
|
Changes to doc/clock.n.
1 2 3 4 5 6 7 8 9 10 11 | '\" '\" Generated from file './doc/clock.dt' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2004 Kevin B. Kenny <kennykb@acm.org>. All rights reserved. '\" .TH "clock" n 8.5 Tcl "Tcl Built-In Commands" .so man.macros .BS .SH NAME clock \- Obtain and manipulate dates and times .SH "SYNOPSIS" .nf | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | '\" '\" Generated from file './doc/clock.dt' by tcllib/doctools with format 'nroff' '\" Copyright (c) 2004 Kevin B. Kenny <kennykb@acm.org>. All rights reserved. '\" .TH "clock" n 8.5 Tcl "Tcl Built-In Commands" .so man.macros .BS .SH NAME clock \- Obtain and manipulate dates and times .SH "SYNOPSIS" .nf \fBpackage require Tcl 8.5-\fR \fBclock add\fI timeVal\fR ?\fIcount unit ...\fR? ?\fI\-option value\fR? \fBclock clicks\fR ?\fI\-option\fR? \fBclock format\fI timeVal\fR ?\fI\-option value ...\fR? \fBclock microseconds\fR \fBclock milliseconds\fR \fBclock scan\fI inputString\fR ?\fI\-option value ...\fR? \fBclock seconds\fR .fi .BE .SH "DESCRIPTION" .PP The \fBclock\fR command performs several operations that obtain and |
| ︙ | ︙ | |||
60 61 62 63 64 65 66 | Formats a time that is expressed as an integer number of seconds into a format intended for consumption by users or external programs. See \fBFORMATTING TIMES\fR for a full description. .\" METHOD: microseconds .TP \fBclock microseconds\fR . | | | < < < < < | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | Formats a time that is expressed as an integer number of seconds into a format intended for consumption by users or external programs. See \fBFORMATTING TIMES\fR for a full description. .\" METHOD: microseconds .TP \fBclock microseconds\fR . Returns the current time as an integer number of microseconds. See \fBHIGH RESOLUTION TIMERS\fR for a full description. .\" METHOD: milliseconds .TP \fBclock milliseconds\fR . Returns the current time as an integer number of milliseconds. See \fBHIGH RESOLUTION TIMERS\fR for a full description. .\" METHOD: scan .TP \fBclock scan\fI inputString\fR ?\fI\-option value ...\fR? . Scans a time that is expressed as a character string and produces an integer number of seconds. See \fBSCANNING TIMES\fR for a full description. .\" METHOD: seconds .TP \fBclock seconds\fR . Returns the current time as an integer number of seconds. .SS "PARAMETERS" .TP \fIcount\fR . An integer representing a count of some unit of time. See \fBCLOCK ARITHMETIC\fR for the details. .TP |
| ︙ | ︙ | |||
324 325 326 327 328 329 330 | .PP If multiple \fIcount unit\fR pairs are present on the command, they are evaluated consecutively, from left to right. .SH "HIGH RESOLUTION TIMERS" .PP Most of the subcommands supported by the \fBclock\fR command deal with times represented as a count of seconds from the epoch time, and this is the | | < < | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | .PP If multiple \fIcount unit\fR pairs are present on the command, they are evaluated consecutively, from left to right. .SH "HIGH RESOLUTION TIMERS" .PP Most of the subcommands supported by the \fBclock\fR command deal with times represented as a count of seconds from the epoch time, and this is the representation that \fBclock seconds\fR returns. There are three exceptions, which are all intended for use where higher-resolution times are required. \fBclock milliseconds\fR returns the count of milliseconds from the epoch time, and \fBclock microseconds\fR returns the count of microseconds from the epoch time. In addition, there is a \fBclock clicks\fR command that returns a platform-dependent high-resolution timer. Unlike \fBclock seconds\fR and \fBclock milliseconds\fR, the value of \fBclock clicks\fR is not guaranteed to be tied to any fixed epoch; it is simply intended to be the most precise interval timer available, and is intended only for relative timing studies such as benchmarks. .SH "FORMATTING TIMES" .PP The \fBclock format\fR command produces times for display to a user or writing to an external medium. The command accepts times that are expressed in seconds from the epoch time of 1 January 1970, 00:00 UTC, as returned by \fBclock seconds\fR, \fBclock scan\fR, \fBclock add\fR, \fBfile atime\fR or \fBfile mtime\fR. |
| ︙ | ︙ | |||
438 439 440 441 442 443 444 | .IP [1] If the string contains a \fB%s\fR format group, representing seconds from the epoch, that group is used to determine the date. .IP [2] If the string contains a \fB%J\fR, \fB%EJ\fR or \fB%Ej\fR format groups, representing the Calendar or Astronomical Julian Day Number, that groups are used to determine the date. | | | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | .IP [1] If the string contains a \fB%s\fR format group, representing seconds from the epoch, that group is used to determine the date. .IP [2] If the string contains a \fB%J\fR, \fB%EJ\fR or \fB%Ej\fR format groups, representing the Calendar or Astronomical Julian Day Number, that groups are used to determine the date. Note that in case of \fB%EJ\fR or \fB%Ej\fR format groups, representing the Julian Date with time fraction, this groups may be used to determine the date and time. .IP [3] If the string contains a complete set of format groups specifying century, year, month, and day of month; century, year, and day of year; or ISO8601 fiscal year, week of year, and day of week; those groups are combined and used to determine the date. If more than one complete |
| ︙ | ︙ |
Changes to doc/coroutine.n.
| ︙ | ︙ | |||
79 80 81 82 83 84 85 | determined in the namespace that the \fBcoroutine\fR command was called from. .PP .VS TIP383 A suspended coroutine (i.e., one that has \fByield\fRed or \fByieldto\fR-d) may have its state inspected (or modified) at that point by using \fBcoroprobe\fR to run a command at the point where the coroutine is at. The command takes the name of the coroutine to run the command in, \fIcoroName\fR, | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | determined in the namespace that the \fBcoroutine\fR command was called from. .PP .VS TIP383 A suspended coroutine (i.e., one that has \fByield\fRed or \fByieldto\fR-d) may have its state inspected (or modified) at that point by using \fBcoroprobe\fR to run a command at the point where the coroutine is at. The command takes the name of the coroutine to run the command in, \fIcoroName\fR, and the name of a command (any any arguments it requires) to immediately run at that point. The result of that command is the result of the \fBcoroprobe\fR command, and the gross state of the coroutine remains the same afterwards (i.e., the coroutine is still expecting the results of a \fByield\fR or \fByieldto\fR as before) though variables may have been changed. .PP Similarly, the \fBcoroinject\fR command may be used to place a command to be run inside a suspended coroutine (when it is resumed) to process arguments, |
| ︙ | ︙ |
Deleted doc/divmod.n.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to doc/exec.n.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | .PP This command treats its arguments as the specification of one or more subprocesses to execute. The arguments take the form of a standard shell pipeline where each \fIarg\fR becomes one word of a command, and each distinct command becomes a subprocess. The result of the command is the standard output of the final subprocess in | | < < | > | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | .PP This command treats its arguments as the specification of one or more subprocesses to execute. The arguments take the form of a standard shell pipeline where each \fIarg\fR becomes one word of a command, and each distinct command becomes a subprocess. The result of the command is the standard output of the final subprocess in the pipeline, decoded as per the \fB-encoding\fR option. .PP If the initial arguments to \fBexec\fR start with \fB\-\fR then they are treated as command-line switches and are not part of the pipeline specification. The following switches are currently supported: .\" OPTION: -encoding .TP 13 \fB\-encoding \fIencodingName\fR . Specifies the name of the encoding to use to decode the result of the command when not run in the background. Defaults to that returned by the \fBencoding system\fR command. .\" OPTION: -ignorestderr .TP 13 \fB\-ignorestderr\fR . Stops the \fBexec\fR command from treating the output of messages to the pipeline's standard error channel as an error case. .\" OPTION: -keepnewline |
| ︙ | ︙ | |||
194 195 196 197 198 199 200 | or .QW <@ then the standard input for the first command in the pipeline is taken from the application's current standard input. .PP If the last \fIarg\fR is .QW & | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | or .QW <@ then the standard input for the first command in the pipeline is taken from the application's current standard input. .PP If the last \fIarg\fR is .QW & then the pipeline will be executed in the background. In this case the \fBexec\fR command will return a list whose elements are the process identifiers for all of the subprocesses in the pipeline. The standard output from the last command in the pipeline will go to the application's standard output if it has not been redirected, and error output from all of the commands in the pipeline will go to the application's |
| ︙ | ︙ | |||
315 316 317 318 319 320 321 | .PP \fBexec\fR will not work well with TUI applications when a console is not present, as is done when launching applications under wish. It is desirable to have console applications hidden and detached. This is a designed-in limitation as \fBexec\fR wants to communicate over pipes. The Expect extension addresses this issue when communicating with a TUI application. .PP | | < < < | | > > | > > > > > > > > > > > > < | | > | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | .PP \fBexec\fR will not work well with TUI applications when a console is not present, as is done when launching applications under wish. It is desirable to have console applications hidden and detached. This is a designed-in limitation as \fBexec\fR wants to communicate over pipes. The Expect extension addresses this issue when communicating with a TUI application. .PP When attempting to execute an application, \fBexec\fR first searches for the name as it was specified. Then, in order, \fB.com\fR, \fB.exe\fR, \fB.bat\fR and \fB.cmd\fR are appended to the end of the specified name and it searches for the longer name. If a directory name was not specified as part of the application name, the following directories are automatically searched in order when attempting to locate the application: .IP \(bu 3 The directory from which the Tcl executable was loaded. .IP \(bu 3 The current directory. .IP \(bu 3 The Windows 32-bit system directory. .IP \(bu 3 The Windows home directory. .IP \(bu 3 The directories listed in the path. .PP In order to execute shell built-in commands like \fBdir\fR and \fBcopy\fR, the caller must prepend the desired command with .QW "\fBcmd.exe /c\0\fR" because built-in commands are not implemented using executables. .RE .TP \fBUnix\fR (including macOS) . The \fBexec\fR command is fully functional and works as described. .SH "UNIX EXAMPLES" .PP |
| ︙ | ︙ |
Changes to doc/expr.n.
| ︙ | ︙ | |||
243 244 245 246 247 248 249 | . Logical OR. If both operands are false, the result is 0, or 1 otherwise. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. .TP 20 \fIx \fB?\fI y \fB:\fI z\fR . | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | . Logical OR. If both operands are false, the result is 0, or 1 otherwise. This operator evaluates lazily; it only evaluates its second operand if it must in order to determine its result. .TP 20 \fIx \fB?\fI y \fB:\fI z\fR . If-then-else, as in C. If \fIx\fR is true , the result is the value of \fIy\fR. Otherwise the result is the value of \fIz\fR. This operator evaluates lazily; it evaluates only one of \fIy\fR or \fIz\fR. .PP The exponentiation operator promotes types in the same way that the multiply and divide operators do, and the result is is the same as the result of \fBpow\fR. Exponentiation groups right-to-left within a precedence level. Other binary |
| ︙ | ︙ |
Changes to doc/file.n.
| ︙ | ︙ | |||
409 410 411 412 413 414 415 | \fItarget\fR is an existing directory, then the second form is used. The second form moves each \fIsource\fR file or directory into the directory \fItargetDir\fR. Existing files will not be overwritten unless the \fB\-force\fR option is specified. When operating inside a single filesystem, Tcl will rename symbolic links rather than the things that they point to. Trying to overwrite a non-empty directory, overwrite a directory with a file, or a file with a directory will all | < < | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | \fItarget\fR is an existing directory, then the second form is used. The second form moves each \fIsource\fR file or directory into the directory \fItargetDir\fR. Existing files will not be overwritten unless the \fB\-force\fR option is specified. When operating inside a single filesystem, Tcl will rename symbolic links rather than the things that they point to. Trying to overwrite a non-empty directory, overwrite a directory with a file, or a file with a directory will all result in errors. Arguments are processed in the order specified, halting at the first error, if any. A \fB\-\|\-\fR marks the end of switches; the argument following the \fB\-\|\-\fR will be treated as a \fIsource\fR even if it starts with a \fB\-\fR. .\" METHOD: rootname .TP \fBfile rootname \fIname\fR . |
| ︙ | ︙ | |||
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
# Make sure that where we're going to move to exists...
if {![\fBfile isdirectory\fR [\fBfile dirname\fR $newName]]} {
\fBfile mkdir\fR [\fBfile dirname\fR $newName]
}
\fBfile rename\fR $oldName $newName
\fBfile link\fR -symbolic $oldName $newName
.CE
.SH "SEE ALSO"
filename(n), open(n), close(n), eof(n), gets(n), tell(n), seek(n),
fblocked(n), flush(n)
.SH KEYWORDS
attributes, copy files, delete files, directory, file, move files, name,
rename files, stat, user
'\" Local Variables:
'\" mode: nroff
'\" fill-column: 78
'\" End:
| > > > > > > > > > > | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
# Make sure that where we're going to move to exists...
if {![\fBfile isdirectory\fR [\fBfile dirname\fR $newName]]} {
\fBfile mkdir\fR [\fBfile dirname\fR $newName]
}
\fBfile rename\fR $oldName $newName
\fBfile link\fR -symbolic $oldName $newName
.CE
.PP
On Windows, a file can be
.QW started
easily enough (equivalent to double-clicking on it in the Explorer
interface) but the name passed to the operating system must be in
native format:
.PP
.CS
exec {*}[auto_execok start] {} [\fBfile nativename\fR C:/Users/fred/example.txt]
.CE
.SH "SEE ALSO"
filename(n), open(n), close(n), eof(n), gets(n), tell(n), seek(n),
fblocked(n), flush(n)
.SH KEYWORDS
attributes, copy files, delete files, directory, file, move files, name,
rename files, stat, user
'\" Local Variables:
'\" mode: nroff
'\" fill-column: 78
'\" End:
|
Deleted doc/frexp.n.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to doc/interp.n.
| ︙ | ︙ | |||
386 387 388 389 390 391 392 | The command sets the maximum size of the Tcl call stack only. It cannot by itself prevent stack overflows on the C stack being used by the application. If your machine has a limit on the size of the C stack, you may get stack overflows before reaching the limit set by the command. If this happens, see if there is a mechanism in your system for increasing the maximum size of the C stack. .RE | < < < < < < < < < < | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | The command sets the maximum size of the Tcl call stack only. It cannot by itself prevent stack overflows on the C stack being used by the application. If your machine has a limit on the size of the C stack, you may get stack overflows before reaching the limit set by the command. If this happens, see if there is a mechanism in your system for increasing the maximum size of the C stack. .RE .\" METHOD: share .TP \fBinterp share\fI srcPath channel destPath\fR . Causes the IO channel identified by \fIchannel\fR to become shared between the interpreter identified by \fIsrcPath\fR and the interpreter identified by \fIdestPath\fR. Both interpreters have the same permissions |
| ︙ | ︙ | |||
607 608 609 610 611 612 613 | The command sets the maximum size of the Tcl call stack only. It cannot by itself prevent stack overflows on the C stack being used by the application. If your machine has a limit on the size of the C stack, you may get stack overflows before reaching the limit set by the command. If this happens, see if there is a mechanism in your system for increasing the maximum size of the C stack. .RE | < < < < < < < < < < | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 | The command sets the maximum size of the Tcl call stack only. It cannot by itself prevent stack overflows on the C stack being used by the application. If your machine has a limit on the size of the C stack, you may get stack overflows before reaching the limit set by the command. If this happens, see if there is a mechanism in your system for increasing the maximum size of the C stack. .RE .SH "SAFE INTERPRETERS" .PP A safe interpreter is one with restricted functionality, so that is safe to execute an arbitrary script from your worst enemy without fear of that script damaging the enclosing application or the rest of your computing environment. In order to make an interpreter safe, certain commands and variables are removed from the interpreter. |
| ︙ | ︙ |
Deleted doc/lfilter.n.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to doc/library.n.
| ︙ | ︙ | |||
62 63 64 65 66 67 68 | .SH "COMMAND PROCEDURES" .PP The following procedures are provided in the Tcl library: .\" COMMAND: auto_execok .TP \fBauto_execok \fIcmd\fR . | > | > | > > > > > > | < < > < < < < | < < < < | < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
.SH "COMMAND PROCEDURES"
.PP
The following procedures are provided in the Tcl library:
.\" COMMAND: auto_execok
.TP
\fBauto_execok \fIcmd\fR
.
Determines whether there is an executable file or shell builtin
by the name \fIcmd\fR. If so, it returns a list of arguments to be
passed to \fBexec\fR to execute the executable file or shell builtin
named by \fIcmd\fR. If not, it returns an empty string. This command
examines the directories in the current search path (given by the PATH
environment variable) in its search for an executable file named
\fIcmd\fR. On Windows platforms, the search is expanded with the same
directories and file extensions as used by \fBexec\fR. \fBAuto_execok\fR
remembers information about previous searches in an array named
\fBauto_execs\fR; this avoids the path search in future calls for the
same \fIcmd\fR. The command \fBauto_reset\fR may be used to force
\fBauto_execok\fR to forget its cached information.
.RS
.PP
For example, to run the \fIumask\fR shell builtin on Linux, you would do:
.PP
.CS
exec {*}[\fBauto_execok\fR umask]
.CE
.PP
To run the \fIDIR\fR shell builtin on Windows, you would do:
.PP
.CS
exec {*}[\fBauto_execok\fR dir]
.CE
.PP
To discover if there is a \fIfrobnicate\fR binary on the user's PATH,
you would do:
.PP
.CS
set mayFrob [expr {[llength [\fBauto_execok\fR frobnicate]] > 0}]
.CE
.RE
.\" COMMAND: auto_import
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 | .\" COMMAND: auto_load .TP \fBauto_load \fIcmd\fR . This command attempts to load the definition for a Tcl command named \fIcmd\fR. To do this, it searches an \fIauto-load path\fR, which is a list of one or more directories. The auto-load path is given by the | | < | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | .\" COMMAND: auto_load .TP \fBauto_load \fIcmd\fR . This command attempts to load the definition for a Tcl command named \fIcmd\fR. To do this, it searches an \fIauto-load path\fR, which is a list of one or more directories. The auto-load path is given by the global variable \fBauto_path\fR if it exists. If there is no \fBauto_path\fR variable, then the \fBTCLLIBPATH\fR environment variable is used, if it exists. Otherwise the auto-load path consists of just the Tcl library directory. Within each directory in the auto-load path there must be a file \fBtclIndex\fR that describes one or more commands defined in that directory and a script to evaluate to load each of the commands. The \fBtclIndex\fR file should be generated with the \fBauto_mkindex\fR command. If \fIcmd\fR is found in an |
| ︙ | ︙ | |||
445 446 447 448 449 450 451 452 453 454 455 456 457 458 | any commands. .\" VARIABLE: auto_noload .TP \fBauto_noload\fR . If set to any value, then \fBunknown\fR will not attempt to auto-load any commands. .\" VARIABLE: env(TCL_LIBRARY) .TP \fBenv(TCL_LIBRARY)\fR . If set, then it specifies the location of the directory containing library scripts (the value of this variable will be assigned to the \fBtcl_library\fR variable and therefore returned by | > > > > > > > > > > > > > > > > > > > > > > > > > > | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | any commands. .\" VARIABLE: auto_noload .TP \fBauto_noload\fR . If set to any value, then \fBunknown\fR will not attempt to auto-load any commands. .\" VARIABLE: auto_path .TP \fBauto_path\fR . If set, then it must contain a valid Tcl list giving directories to search during auto-load operations (including for package index files when using the default \fBpackage unknown\fR handler). This variable is initialized during startup to contain, in order: the directories listed in the \fBTCLLIBPATH\fR environment variable, the directory named by the \fBtcl_library\fR global variable, the parent directory of \fBtcl_library\fR, the directories listed in the \fBtcl_pkgPath\fR variable. Additional locations to look for files and package indices should normally be added to this variable using \fBlappend\fR. .RS .PP For example, to add the \fIlib\fR directory next to the running script, you would do: .PP .CS lappend \fBauto_path\fR [file dirname [info script]]/lib .CE .PP Note that if the script uses \fBcd\fR, it is advisable to ensure that entries on the \fBauto_path\fR are \fBfile normalize\fRd. .RE .\" VARIABLE: env(TCL_LIBRARY) .TP \fBenv(TCL_LIBRARY)\fR . If set, then it specifies the location of the directory containing library scripts (the value of this variable will be assigned to the \fBtcl_library\fR variable and therefore returned by |
| ︙ | ︙ | |||
469 470 471 472 473 474 475 | \fBenv(TCLLIBPATH)\fR . If set, then it must contain a valid Tcl list giving directories to search during auto-load operations. Directories must be specified in Tcl format, using .QW / as the path separator, regardless of platform. | | < | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | \fBenv(TCLLIBPATH)\fR . If set, then it must contain a valid Tcl list giving directories to search during auto-load operations. Directories must be specified in Tcl format, using .QW / as the path separator, regardless of platform. This variable is only used when initializing the \fBauto_path\fR variable. .RS .PP A key consequence of this variable is that it gives a way to let the user of a script specify the list of places where that script may use \fBpackage require\fR to read packages from. It is not normally usefully settable within a Tcl script itself \fIexcept\fR to influence where other interpreters load from (whether made with \fBinterp create\fR or launched |
| ︙ | ︙ |
Changes to doc/load.n.
| ︙ | ︙ | |||
146 147 148 149 150 151 152 | .PP The following is a minimal extension: .PP .CS #include <tcl.h> #include <stdio.h> static int fooCmd(void *clientData, | | | | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
.PP
The following is a minimal extension:
.PP
.CS
#include <tcl.h>
#include <stdio.h>
static int fooCmd(void *clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
printf("called with %d arguments\en", objc);
return TCL_OK;
}
int Foo_Init(Tcl_Interp *interp) {
if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
return TCL_ERROR;
}
printf("creating foo command");
Tcl_CreateObjCommand(interp, "foo", fooCmd, NULL, NULL);
return TCL_OK;
}
.CE
.PP
When built into a shared/dynamic library with a suitable name
(e.g. \fBfoo.dll\fR on Windows, \fBlibfoo.so\fR on Solaris and Linux)
it can then be loaded into Tcl with the following:
|
| ︙ | ︙ |
Changes to doc/mathfunc.n.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | mathfunc \- Mathematical functions for Tcl expressions .SH SYNOPSIS .nf \fBpackage require Tcl 8.5-\fR \fB::tcl::mathfunc::abs\fI arg\fR \fB::tcl::mathfunc::acos\fI arg\fR | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < < | | < | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
mathfunc \- Mathematical functions for Tcl expressions
.SH SYNOPSIS
.nf
\fBpackage require Tcl 8.5-\fR
\fB::tcl::mathfunc::abs\fI arg\fR
\fB::tcl::mathfunc::acos\fI arg\fR
\fB::tcl::mathfunc::asin\fI arg\fR
\fB::tcl::mathfunc::atan\fI arg\fR
\fB::tcl::mathfunc::atan2\fI y x\fR
\fB::tcl::mathfunc::bool\fI arg\fR
\fB::tcl::mathfunc::ceil\fI arg\fR
\fB::tcl::mathfunc::cos\fI arg\fR
\fB::tcl::mathfunc::cosh\fI arg\fR
\fB::tcl::mathfunc::double\fI arg\fR
\fB::tcl::mathfunc::entier\fI arg\fR
\fB::tcl::mathfunc::exp\fI arg\fR
\fB::tcl::mathfunc::floor\fI arg\fR
\fB::tcl::mathfunc::fmod\fI x y\fR
\fB::tcl::mathfunc::hypot\fI x y\fR
\fB::tcl::mathfunc::int\fI arg\fR
.VS TIP521
\fB::tcl::mathfunc::isfinite\fI arg\fR
\fB::tcl::mathfunc::isinf\fI arg\fR
\fB::tcl::mathfunc::isnan\fI arg\fR
\fB::tcl::mathfunc::isnormal\fI arg\fR
.VE TIP521
\fB::tcl::mathfunc::isqrt\fI arg\fR
.VS TIP521
\fB::tcl::mathfunc::issubnormal\fI arg\fR
\fB::tcl::mathfunc::isunordered\fI x y\fR
.VE TIP521
\fB::tcl::mathfunc::log\fI arg\fR
\fB::tcl::mathfunc::log10\fI arg\fR
\fB::tcl::mathfunc::max\fI arg\fR ?\fIarg ...\fR?
\fB::tcl::mathfunc::min\fI arg\fR ?\fIarg ...\fR?
\fB::tcl::mathfunc::pow\fI x y\fR
\fB::tcl::mathfunc::rand\fR
\fB::tcl::mathfunc::round\fI arg\fR
\fB::tcl::mathfunc::sin\fI arg\fR
\fB::tcl::mathfunc::sinh\fI arg\fR
\fB::tcl::mathfunc::sqrt\fI arg\fR
\fB::tcl::mathfunc::srand\fI arg\fR
\fB::tcl::mathfunc::tan\fI arg\fR
\fB::tcl::mathfunc::tanh\fI arg\fR
\fB::tcl::mathfunc::wide\fI arg\fR
.fi
.BE
.SH "DESCRIPTION"
.PP
The \fBexpr\fR command handles mathematical functions of the form
\fBsin($x)\fR or \fBatan2($y,$x)\fR by converting them to calls of the
form \fB[tcl::mathfunc::sin [expr {$x}]]\fR or
\fB[tcl::mathfunc::atan2 [expr {$y}] [expr {$x}]]\fR.
A number of math functions are available by default within the
namespace \fB::tcl::mathfunc\fR; these functions are also available
for code apart from \fBexpr\fR, by invoking the given commands
directly.
.PP
Tcl supports the following mathematical functions in expressions, all
of which work solely with floating-point numbers unless otherwise noted:
.DS
.ta 3.2c 6.4c 9.6c
\fBabs\fR \fBacos\fR \fBasin\fR \fBatan\fR
\fBatan2\fR \fBbool\fR \fBceil\fR \fBcos\fR
\fBcosh\fR \fBdouble\fR \fBentier\fR \fBexp\fR
\fBfloor\fR \fBfmod\fR \fBhypot\fR \fBint\fR
\fBisfinite\fR \fBisinf\fR \fBisnan\fR \fBisnormal\fR
\fBisqrt\fR \fBissubnormal\fR \fBisunordered\fR \fBlog\fR
\fBlog10\fR \fBmax\fR \fBmin\fR \fBpow\fR
\fBrand\fR \fBround\fR \fBsin\fR \fBsinh\fR
\fBsqrt\fR \fBsrand\fR \fBtan\fR \fBtanh\fR
\fBwide\fR
.DE
.PP
In addition to these predefined functions, applications may
define additional functions by using \fBproc\fR (or any other method,
such as \fBinterp alias\fR or \fBTcl_CreateObjCommand\fR) to define
new commands in the \fBtcl::mathfunc\fR namespace.
.SS "DETAILED DEFINITIONS"
.\" COMMAND: abs
.TP
\fBabs \fIarg\fR
.
Returns the absolute value of \fIarg\fR. \fIArg\fR may be either
integer or floating-point, and the result is returned in the same form.
.\" COMMAND: acos
.TP
\fBacos \fIarg\fR
.
Returns the arc cosine of \fIarg\fR, in the range [\fI0\fR,\fIpi\fR]
radians. \fIArg\fR should be in the range [\fI\-1\fR,\fI1\fR].
.\" COMMAND: asin
.TP
\fBasin \fIarg\fR
.
Returns the arc sine of \fIarg\fR, in the range [\fI\-pi/2\fR,\fIpi/2\fR]
radians. \fIArg\fR should be in the range [\fI\-1\fR,\fI1\fR].
.\" COMMAND: atan
.TP
\fBatan \fIarg\fR
.
Returns the arc tangent of \fIarg\fR, in the range [\fI\-pi/2\fR,\fIpi/2\fR]
radians.
.\" COMMAND: atan2
.TP
\fBatan2 \fIy x\fR
.
Returns the arc tangent of \fIy\fR/\fIx\fR, in the range [\fI\-pi\fR,\fIpi\fR]
radians. \fIx\fR and \fIy\fR cannot both be 0. If \fIx\fR is greater
than \fI0\fR, this is equivalent to
.QW "\fBatan \fR[\fBexpr\fR {\fIy\fB/\fIx\fR}]" .
.\" COMMAND: bool
.TP
\fBbool \fIarg\fR
.
Accepts any numeric value, or any string acceptable to
\fBstring is boolean\fR, and returns the corresponding
boolean value \fB0\fR or \fB1\fR. Non-zero numbers are true.
Other numbers are false. Non-numeric strings produce boolean value in
agreement with \fBstring is true\fR and \fBstring is false\fR.
.\" COMMAND: ceil
.TP
\fBceil \fIarg\fR
.
Returns the smallest integral floating-point value (i.e. with a zero
fractional part) not less than \fIarg\fR. The argument may be any
numeric value.
.\" COMMAND: cos
.TP
\fBcos \fIarg\fR
.
Returns the cosine of \fIarg\fR, measured in radians.
.\" COMMAND: cosh
.TP
\fBcosh \fIarg\fR
.
Returns the hyperbolic cosine of \fIarg\fR. If the result would cause
an overflow, an error is returned.
.\" COMMAND: double
.TP
\fBdouble \fIarg\fR
.
The argument may be any numeric value,
If \fIarg\fR is a floating-point value, returns \fIarg\fR, otherwise converts
\fIarg\fR to floating-point and returns the converted value. May return
\fBInf\fR or \fB\-Inf\fR when the argument is a numeric value that exceeds
the floating-point range.
.\" COMMAND: entier
.TP
\fBentier \fIarg\fR
.
The argument may be any numeric value. The integer part of \fIarg\fR
is determined and returned. The integer range returned by this function
is unlimited, unlike \fBint\fR and \fBwide\fR which
truncate their range to fit in particular storage widths.
.\" COMMAND: exp
.TP
\fBexp \fIarg\fR
.
Returns the exponential of \fIarg\fR, defined as \fIe\fR**\fIarg\fR.
If the result would cause an overflow, an error is returned.
.\" COMMAND: floor
.TP
\fBfloor \fIarg\fR
.
Returns the largest integral floating-point value (i.e. with a zero
fractional part) not greater than \fIarg\fR. The argument may be
any numeric value.
.\" COMMAND: fmod
.TP
\fBfmod \fIx y\fR
.
Returns the floating-point remainder of the division of \fIx\fR by
\fIy\fR. If \fIy\fR is 0, an error is returned.
.\" COMMAND: hypot
.TP
\fBhypot \fIx y\fR
.
Computes the length of the hypotenuse of a right-angled triangle,
approximately
.QW "\fBsqrt\fR [\fBexpr\fR {\fIx\fB*\fIx\fB+\fIy\fB*\fIy\fR}]"
|
| ︙ | ︙ | |||
398 399 400 401 402 403 404 | .VS TIP521 Returns 1 if \fIx\fR and \fIy\fR cannot be compared for ordering, that is, if either one is NaN. Returns 0 if both values can be ordered, that is, if they are both chosen from among the set of zero, subnormal, normal and infinite values. Throws an error if either \fIx\fR or \fIy\fR cannot be promoted to a floating-point value. .VE TIP521 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | .VS TIP521 Returns 1 if \fIx\fR and \fIy\fR cannot be compared for ordering, that is, if either one is NaN. Returns 0 if both values can be ordered, that is, if they are both chosen from among the set of zero, subnormal, normal and infinite values. Throws an error if either \fIx\fR or \fIy\fR cannot be promoted to a floating-point value. .VE TIP521 .\" COMMAND: log .TP \fBlog \fIarg\fR . Returns the natural logarithm of \fIarg\fR. \fIArg\fR must be a positive value. .\" COMMAND: log10 .TP \fBlog10 \fIarg\fR . Returns the base 10 logarithm of \fIarg\fR. \fIArg\fR must be a positive value. .\" COMMAND: max .TP \fBmax \fIarg\fB \fR... . Accepts one or more numeric arguments. Returns the one argument with the greatest value. .\" COMMAND: min .TP \fBmin \fIarg\fB \fR... . Accepts one or more numeric arguments. Returns the one argument with the least value. .\" COMMAND: pow .TP \fBpow \fIx y\fR . Computes the value of \fIx\fR raised to the power \fIy\fR. If \fIx\fR is negative, \fIy\fR must be an integer value. .\" COMMAND: rand .TP \fBrand\fR . Returns a pseudo-random floating-point value in the range (\fI0\fR,\fI1\fR). The generator algorithm is a simple linear congruential generator that is not cryptographically secure. Each result from \fBrand\fR completely determines all future results from subsequent calls to \fBrand\fR, so \fBrand\fR should not be used to generate a sequence of secrets, such as one-time passwords. The seed of the generator is initialized from the internal clock of the machine or may be set with the \fBsrand\fR function. .\" COMMAND: round .TP \fBround \fIarg\fR . If \fIarg\fR is an integer value, returns \fIarg\fR, otherwise converts \fIarg\fR to integer by rounding and returns the converted value. .\" COMMAND: sin .TP \fBsin \fIarg\fR . Returns the sine of \fIarg\fR, measured in radians. .\" COMMAND: sinh .TP |
| ︙ | ︙ | |||
535 536 537 538 539 540 541 | . Returns the tangent of \fIarg\fR, measured in radians. .\" COMMAND: tanh .TP \fBtanh \fIarg\fR . Returns the hyperbolic tangent of \fIarg\fR. | < < < < < < | < | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | . Returns the tangent of \fIarg\fR, measured in radians. .\" COMMAND: tanh .TP \fBtanh \fIarg\fR . Returns the hyperbolic tangent of \fIarg\fR. .\" COMMAND: wide .TP \fBwide \fIarg\fR . The argument may be any numeric value. The integer part of \fIarg\fR is determined, and then the low order 64 bits of that integer value are returned as an integer value. .SH "SEE ALSO" expr(n), fpclassify(n), mathop(n), namespace(n) .SH "COPYRIGHT" .nf Copyright \(co 1993 The Regents of the University of California. Copyright \(co 1994-2000 Sun Microsystems Incorporated. Copyright \(co 2005-2006 Kevin B. Kenny <kennykb@acm.org>. .fi '\" Local Variables: '\" mode: nroff '\" fill-column: 78 '\" End: |
Deleted doc/modf.n.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to doc/open.n.
| ︙ | ︙ | |||
374 375 376 377 378 379 380 | milliseconds. Normally a receive or transmit data signal stays at the mark (on=1) voltage until the next character is transferred. A BREAK is sometimes used to reset the communications line or change the operating mode of communications hardware. .SS "ERROR CODES (Windows only)" .PP A lot of different errors may occur during serial read operations or during | | | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | milliseconds. Normally a receive or transmit data signal stays at the mark (on=1) voltage until the next character is transferred. A BREAK is sometimes used to reset the communications line or change the operating mode of communications hardware. .SS "ERROR CODES (Windows only)" .PP A lot of different errors may occur during serial read operations or during event polling in the background. The external device may have been switched off, the data lines may be noisy, system buffers may overrun or your mode settings may be wrong. That is why a reliable software should always \fBcatch\fR serial read operations. In cases of an error Tcl returns a general file I/O error. Then \fBfconfigure\fR \fB\-lasterror\fR may help to locate the problem. The following error codes may be returned. .IP \fBRXOVER\fR Windows input buffer overrun. The data comes faster than your scripts reads |
| ︙ | ︙ |
Changes to doc/registry.n.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 | .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME registry \- Manipulate the Windows registry .SH SYNOPSIS .nf | < | > < < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME registry \- Manipulate the Windows registry .SH SYNOPSIS .nf \fBpackage require registry 1.3\fR \fBregistry \fR?\fI\-mode\fR? \fIoption keyName\fR ?\fIarg arg ...\fR? .fi .BE .SH DESCRIPTION .PP The \fBregistry\fR package provides a general set of operations for manipulating the Windows registry. The package implements the \fBregistry\fR Tcl command. This command is only supported on the Windows platform. Warning: this command should be used with caution as a corrupted registry can leave your system in an unusable state. .PP \fIKeyName\fR is the name of a registry key. Registry keys must be one of the following forms: .RS .PP \fB\e\e\fIhostname\fB\e\fIrootname\fB\e\fIkeypath\fR .PP \fIrootname\fB\e\fIkeypath\fR |
| ︙ | ︙ |
Deleted doc/remquo.n.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to doc/subst.n.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 | .TH subst n 7.4 Tcl "Tcl Built-In Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME subst \- Perform backslash, command, and variable substitutions .SH SYNOPSIS | < < < < < < < < < < < < < < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | .TH subst n 7.4 Tcl "Tcl Built-In Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME subst \- Perform backslash, command, and variable substitutions .SH SYNOPSIS \fBsubst \fR?\fB\-nobackslashes\fR? ?\fB\-nocommands\fR? ?\fB\-novariables\fR? \fIstring\fR .BE .SH DESCRIPTION .PP This command performs variable substitutions, command substitutions, and backslash substitutions on its \fIstring\fR argument and returns the fully-substituted result. The substitutions are performed in exactly the same way as for Tcl commands. As a result, the \fIstring\fR argument is actually substituted twice, once by the Tcl parser in the usual fashion for Tcl commands, and again by the \fIsubst\fR command. .PP If any of the \fB\-nobackslashes\fR, \fB\-nocommands\fR, or \fB\-novariables\fR are specified, then the corresponding substitutions are not performed. For example, if \fB\-nocommands\fR is specified, command substitution is not performed: open and close brackets are treated as ordinary characters with no special interpretation. .PP Note that the substitution of one kind can include substitution of other kinds. For example, even when the \fB\-novariables\fR option is specified, command substitution is performed without restriction. This means that any variable substitution necessary to complete the command substitution will still take place. Likewise, any command substitution necessary to complete a variable substitution will take place, even when \fB\-nocommands\fR is specified. See the |
| ︙ | ︙ |
Changes to doc/switch.n.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 | .TH switch n 8.5 Tcl "Tcl Built-In Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME switch \- Evaluate one of several scripts, depending on a given value .SH SYNOPSIS | | | | | | | | | < < < < < < < < < | < | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
.TH switch n 8.5 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note: do not modify the .SH NAME line immediately below!
.SH NAME
switch \- Evaluate one of several scripts, depending on a given value
.SH SYNOPSIS
\fBswitch \fR?\fIoptions\fR?\fI string pattern body \fR?\fIpattern body ...\fR?
.sp
\fBswitch \fR?\fIoptions\fR?\fI string \fR{\fIpattern body \fR?\fIpattern body ...\fR?}
.BE
.SH DESCRIPTION
.PP
The \fBswitch\fR command matches its \fIstring\fR argument against each of
the \fIpattern\fR arguments in order.
As soon as it finds a \fIpattern\fR that matches \fIstring\fR it
evaluates the following \fIbody\fR argument by passing it recursively
to the Tcl interpreter and returns the result of that evaluation.
If the last \fIpattern\fR argument is \fBdefault\fR then it matches
anything.
If no \fIpattern\fR argument
matches \fIstring\fR and no default is given, then the \fBswitch\fR
command returns an empty string.
.PP
If the initial arguments to \fBswitch\fR start with \fB\-\fR then
they are treated as options
unless there are exactly two arguments to \fBswitch\fR (in which case the
first must the \fIstring\fR and the second must be the
\fIpattern\fR/\fIbody\fR list).
The following options are currently supported:
.\" OPTION: -exact
.TP 10
\fB\-exact\fR
.
Use exact matching when comparing \fIstring\fR to a pattern. This
is the default.
.\" OPTION: -glob
.TP 10
\fB\-glob\fR
.
When matching \fIstring\fR to the patterns, use glob-style matching
(i.e. the same as implemented by the \fBstring match\fR command).
.\" OPTION: -regexp
.TP 10
\fB\-regexp\fR
.
When matching \fIstring\fR to the patterns, use regular
expression matching
(as described in the \fBre_syntax\fR reference page).
.\" OPTION: -nocase
.TP 10
\fB\-nocase\fR
.
Causes comparisons to be handled in a case-insensitive manner.
.\" OPTION: -matchvar
.TP 10
\fB\-matchvar\fI varName\fR
.
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of matches
found by the regular expression engine will be written. The first
element of the list written will be the overall substring of the input
string (i.e. the \fIstring\fR argument to \fBswitch\fR) matched, the
second element of the list will be the substring matched by the first
capturing parenthesis in the regular expression that matched, and so
on. When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it. This option may be specified at the same
time as the \fB\-indexvar\fR option.
.\" OPTION: -indexvar
.TP 10
\fB\-indexvar\fI varName\fR
.
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of indices
referring to matching substrings
found by the regular expression engine will be written. The first
element of the list written will be a two-element list specifying the
index of the start and index of the first character after the end of
the overall substring of the input
string (i.e. the \fIstring\fR argument to \fBswitch\fR) matched, in a
similar way to the \fB\-indices\fR option to the \fBregexp\fR can
obtain. Similarly, the second element of the list refers to the first
capturing parenthesis in the regular expression that matched, and so
on. When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it. This option may be specified at the same
time as the \fB\-matchvar\fR option.
.\" OPTION: --
.TP 10
\fB\-\|\-\fR
.
Marks the end of options. The argument following this one will
be treated as \fIstring\fR even if it starts with a \fB\-\fR.
This is not required when the matching patterns and bodies are grouped
together in a single argument.
.PP
Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments.
The first uses a separate argument for each of the patterns and commands;
this form is convenient if substitutions are desired on some of the
patterns or commands.
|
| ︙ | ︙ | |||
190 191 192 193 194 195 196 |
}
d(e*)f(g*)h {
puts "Found [string length [lindex $foo 1]] 'e's and\e
[string length [lindex $foo 2]] 'g's"
}
}
.CE
| < < < < < < < < < < < < < < < < < < < < | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
}
d(e*)f(g*)h {
puts "Found [string length [lindex $foo 1]] 'e's and\e
[string length [lindex $foo 2]] 'g's"
}
}
.CE
.SH "SEE ALSO"
for(n), if(n), regexp(n)
.SH KEYWORDS
switch, match, regular expression
.\" Local Variables:
.\" mode: nroff
.\" End:
|
Changes to doc/tcltest.n.
1 2 3 4 5 6 7 8 9 10 | '\" '\" Copyright (c) 1990-1994 The Regents of the University of California '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-1999 Scriptics Corporation '\" Copyright (c) 2000 Ajuba Solutions '\" Contributions from Don Porter, NIST, 2002. (not subject to US copyright) '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | '\" '\" Copyright (c) 1990-1994 The Regents of the University of California '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" Copyright (c) 1998-1999 Scriptics Corporation '\" Copyright (c) 2000 Ajuba Solutions '\" Contributions from Don Porter, NIST, 2002. (not subject to US copyright) '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH "tcltest" n 2.5 tcltest "Tcl Bundled Packages" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME tcltest \- Test harness support code and utilities .SH SYNOPSIS .nf \fBpackage require tcltest\fR ?\fB2.5\fR? \fBtcltest::test \fIname description\fR ?\fI\-option value ...\fR? \fBtcltest::test \fIname description\fR ?\fIconstraints\fR? \fIbody result\fR \fBtcltest::loadTestedCommands\fR \fBtcltest::makeDirectory \fIname\fR ?\fIdirectory\fR? \fBtcltest::removeDirectory \fIname\fR ?\fIdirectory\fR? |
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | \fBtcltest::outputFile \fR?\fIfilename\fR? \fBtcltest::preserveCore \fR?\fIlevel\fR? \fBtcltest::singleProcess \fR?\fIboolean\fR? \fBtcltest::skip \fR?\fIpatternList\fR? \fBtcltest::skipDirectories \fR?\fIpatternList\fR? \fBtcltest::skipFiles \fR?\fIpatternList\fR? \fBtcltest::temporaryDirectory \fR?\fIdirectory\fR? | < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | \fBtcltest::outputFile \fR?\fIfilename\fR? \fBtcltest::preserveCore \fR?\fIlevel\fR? \fBtcltest::singleProcess \fR?\fIboolean\fR? \fBtcltest::skip \fR?\fIpatternList\fR? \fBtcltest::skipDirectories \fR?\fIpatternList\fR? \fBtcltest::skipFiles \fR?\fIpatternList\fR? \fBtcltest::temporaryDirectory \fR?\fIdirectory\fR? \fBtcltest::testsDirectory \fR?\fIdirectory\fR? \fBtcltest::verbose \fR?\fIlevel\fR? \fBtcltest::test \fIname description optionList\fR \fBtcltest::normalizeMsg \fImsg\fR \fBtcltest::normalizePath \fIpathVar\fR \fBtcltest::workingDirectory \fR?\fIdir\fR? |
| ︙ | ︙ | |||
380 381 382 383 384 385 386 | .QW "\fBconfigure \-notfile\fR ?\fIpatternList\fR?" . .\" COMMAND: temporaryDirectory .TP \fBtemporaryDirectory\fR ?\fIdirectory\fR? . Same as .QW "\fBconfigure \-tmpdir\fR ?\fIdirectory\fR?" . | < < < < < < | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | .QW "\fBconfigure \-notfile\fR ?\fIpatternList\fR?" . .\" COMMAND: temporaryDirectory .TP \fBtemporaryDirectory\fR ?\fIdirectory\fR? . Same as .QW "\fBconfigure \-tmpdir\fR ?\fIdirectory\fR?" . .\" COMMAND: testsDirectory .TP \fBtestsDirectory\fR ?\fIdirectory\fR? . Same as .QW "\fBconfigure \-testdir\fR ?\fIdirectory\fR?" . .\" COMMAND: verbose |
| ︙ | ︙ | |||
1025 1026 1027 1028 1029 1030 1031 | .TP \fB\-errfile \fIfilename\fR . Sets the file to which all error output produced by tcltest should be written. A file named \fIfilename\fR will be \fBopen\fRed for writing, and the resulting channel will be set as the value of \fBerrorChannel\fR. | < < < < < | 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 | .TP \fB\-errfile \fIfilename\fR . Sets the file to which all error output produced by tcltest should be written. A file named \fIfilename\fR will be \fBopen\fRed for writing, and the resulting channel will be set as the value of \fBerrorChannel\fR. .SH "CREATING TEST SUITES WITH TCLTEST" .PP The fundamental element of a test suite is the individual \fBtest\fR command. We begin with several examples. .IP [1] Test of a script that returns normally. .RS |
| ︙ | ︙ | |||
1155 1156 1157 1158 1159 1160 1161 | After all \fBtest\fRs in a test file, the command \fBcleanupTests\fR should be called. .IP [7] Here is a sketch of a sample test file illustrating those points: .RS .PP .CS | | | 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
After all \fBtest\fRs in a test file, the command \fBcleanupTests\fR
should be called.
.IP [7]
Here is a sketch of a sample test file illustrating those points:
.RS
.PP
.CS
\fBpackage require tcltest 2.5\fR
\fB::tcltest::configure\fR {*}$::argv
\fBpackage require example\fR
namespace eval ::example::test {
namespace import ::tcltest::*
\fBtestConstraint\fR X [expr {...}]
variable SETUP {#common setup code}
variable CLEANUP {#common cleanup code}
|
| ︙ | ︙ | |||
1189 1190 1191 1192 1193 1194 1195 | because that is the default name used by \fBrunAllTests\fR when combining multiple test suites into one testing run. .IP [8] Here is a sketch of a sample test suite main script: .RS .PP .CS | | | 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 |
because that is the default name used by \fBrunAllTests\fR when combining
multiple test suites into one testing run.
.IP [8]
Here is a sketch of a sample test suite main script:
.RS
.PP
.CS
\fBpackage require tcltest 2.5\fR
\fBpackage require example\fR
\fB::tcltest::configure\fR -testdir \e
[file dirname [file normalize [info script]]]
\fB::tcltest::configure\fR {*}$::argv
\fB::tcltest::runAllTests\fR
.CE
.RE
|
| ︙ | ︙ |
Changes to doc/tclvars.n.
1 2 3 4 5 6 7 | '\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | '\" '\" Copyright (c) 1993 The Regents of the University of California. '\" Copyright (c) 1994-1997 Sun Microsystems, Inc. '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH tclvars n 8.0 Tcl "Tcl Built-In Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME argc, argv, argv0, auto_path, env, errorCode, errorInfo, tcl_interactive, tcl_library, tcl_patchLevel, tcl_pkgPath, tcl_platform, tcl_rcFileName, tcl_traceCompile, tcl_traceExec, tcl_version \- Variables used by Tcl .BE .SH DESCRIPTION |
| ︙ | ︙ | |||
233 234 235 236 237 238 239 | Its contents take the form of a stack trace showing the various nested Tcl commands that had been invoked at the time of the error. .\" VARIABLE: tcl_library .TP \fBtcl_library\fR . This variable holds the name of a directory containing the | | | < < | | < > | < | < < | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | Its contents take the form of a stack trace showing the various nested Tcl commands that had been invoked at the time of the error. .\" VARIABLE: tcl_library .TP \fBtcl_library\fR . This variable holds the name of a directory containing the system library of Tcl scripts, such as those used for auto-loading. The value of this variable is returned by the \fBinfo library\fR command. See the \fBlibrary\fR manual entry for details of the facilities provided by the Tcl script library. Normally each application or package will have its own application-specific script library in addition to the Tcl script library; each application should set a global variable with a name like \fB$\fIapp\fB_library\fR (where \fIapp\fR is the application's name) to hold the network file name for that application's library directory. The initial value of \fBtcl_library\fR is set when an interpreter is created by searching several different directories until one is found that contains an appropriate Tcl startup script. If the \fBTCL_LIBRARY\fR environment variable exists, then the directory it names is checked first. If \fBTCL_LIBRARY\fR is not set or doesn't refer to an appropriate directory, then Tcl checks several other directories based on a compiled-in default location, the location of the binary containing the application, and the current working directory. .\" VARIABLE: tcl_patchLevel .TP \fBtcl_patchLevel\fR . When an interpreter is created Tcl initializes this variable to hold a string giving the current patch level for Tcl, such as \fB8.4.16\fR for Tcl 8.4 with the first sixteen official patches, or |
| ︙ | ︙ |
Deleted doc/timer.n.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted doc/unicode.n.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to doc/unload.n.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 | .br \fBunload \fR?\fIswitches\fR? \fIfileName prefix interp\fR .BE .SH DESCRIPTION .PP This command tries to unload shared libraries previously loaded with \fBload\fR from the application's address space. \fIfileName\fR | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | .br \fBunload \fR?\fIswitches\fR? \fIfileName prefix interp\fR .BE .SH DESCRIPTION .PP This command tries to unload shared libraries previously loaded with \fBload\fR from the application's address space. \fIfileName\fR is the name of the file containing the library file to be unload; it must be the same as the filename provided to \fBload\fR for loading the library. The \fIprefix\fR argument is the prefix (as determined by or passed to \fBload\fR), and is used to compute the name of the unload procedure; if not supplied, it is computed from \fIfileName\fR in the same manner as \fBload\fR. The \fIinterp\fR argument is the path name of the interpreter from |
| ︙ | ︙ | |||
109 110 111 112 113 114 115 | or \fBTCL_UNLOAD_DETACH_FROM_PROCESS\fR. In case the library will remain attached to the process after the unload procedure returns (i.e. because the library is used by other interpreters), \fBTCL_UNLOAD_DETACH_FROM_INTERPRETER\fR will be defined. However, if the library is used only by the target interpreter and the library will be detached from the application as soon as the unload procedure returns, the \fIflags\fR argument will be set to \fBTCL_UNLOAD_DETACH_FROM_PROCESS\fR. | < < < < | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | or \fBTCL_UNLOAD_DETACH_FROM_PROCESS\fR. In case the library will remain attached to the process after the unload procedure returns (i.e. because the library is used by other interpreters), \fBTCL_UNLOAD_DETACH_FROM_INTERPRETER\fR will be defined. However, if the library is used only by the target interpreter and the library will be detached from the application as soon as the unload procedure returns, the \fIflags\fR argument will be set to \fBTCL_UNLOAD_DETACH_FROM_PROCESS\fR. .SS NOTES .PP The \fBunload\fR command cannot unload libraries that are statically linked with the application. If \fIfileName\fR is an empty string, then the \fIprefix\fR argument must be specified. .PP |
| ︙ | ︙ |
Changes to doc/vwait.n.
| ︙ | ︙ | |||
74 75 76 77 78 79 80 | \fIChannel\fR must name a Tcl channel open for reading. If \fIchannel\fR is or becomes readable the wait operation completes. .\" OPTION: -timeout .TP \fB\-timeout\fI milliseconds\fR . The wait operation is constrained to \fImilliseconds\fR. | < | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | \fIChannel\fR must name a Tcl channel open for reading. If \fIchannel\fR is or becomes readable the wait operation completes. .\" OPTION: -timeout .TP \fB\-timeout\fI milliseconds\fR . The wait operation is constrained to \fImilliseconds\fR. .\" OPTION: -variable .TP \fB\-variable\fI varName\fR . \fIVarName\fR must be the name of a global variable. Writing or unsetting this variable completes the wait operation. .\" OPTION: -writable |
| ︙ | ︙ |
Changes to doc/zipfs.3.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 | .AP int copy in If non-zero, the ZIP archive in the data buffer will be internally copied before mounting, allowing the data buffer to be disposed once \fBTclZipfs_MountBuffer\fR returns. If zero, the caller guarantees that the buffer will be valid to read from for the duration of the mount. .BE .SH DESCRIPTION | | | | | < < | | < > > > > > > > > > > > > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | .AP int copy in If non-zero, the ZIP archive in the data buffer will be internally copied before mounting, allowing the data buffer to be disposed once \fBTclZipfs_MountBuffer\fR returns. If zero, the caller guarantees that the buffer will be valid to read from for the duration of the mount. .BE .SH DESCRIPTION \fBTclZipfs_AppHook\fR is a utility function to perform standard application initialization procedures, taking into account available ZIP archives as follows: .IP [1] If the current application has a mountable ZIP archive, that archive is mounted under \fIZIPFS_VOLUME\fB/app\fR as a read-only Tcl virtual file system (VFS). The value of \fIZIPFS_VOLUME\fR can be retrieved using the Tcl command \fBzipfs root\fR. .IP [2] If a file named \fBmain.tcl\fR is located in the root directory of that file system (i.e., at \fIZIPFS_VOLUME\fB/app/main.tcl\fR after the ZIP archive is mounted as described above) it is treated as the startup script for the process. .IP [3] If the file \fIZIPFS_VOLUME\fB/app/tcl_library/init.tcl\fR is present, the \fBtcl_library\fR global variable in the initial Tcl interpreter is set to \fIZIPFS_VOLUME\fB/app/tcl_library\fR. .IP [4] If the directory \fBtcl_library\fR was not found in the main application mount, the system will then search for it as either a VFS attached to the application dynamic library, or as a zip archive named \fBlibtcl_\fImajor\fB_\fIminor\fB_\fIpatchlevel\fB.zip\fR either in the present working directory or in the standard Tcl install location. (For example, the Tcl 9.0.2 release would be searched for in a file \fBlibtcl_9_0_2.zip\fR.) That archive, if located, is also mounted read-only. .PP On Windows, \fBTclZipfs_AppHook\fR has a slightly different signature, since it uses WCHAR instead of char. As a result, it requires the application to be compiled with the UNICODE preprocessor symbol defined (e.g., via the \fB\-DUNICODE\fR compiler flag). .PP The result of \fBTclZipfs_AppHook\fR is the full Tcl version with build |
| ︙ | ︙ |
Changes to generic/regc_color.c.
| ︙ | ︙ | |||
408 409 410 411 412 413 414 |
pcolor co)
{
color sco; /* new subcolor */
sco = cm->cd[co].sub;
if (sco == NOSUB) { /* color has no open subcolor */
if (cm->cd[co].nchrs == 1) { /* optimization */
| | | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
pcolor co)
{
color sco; /* new subcolor */
sco = cm->cd[co].sub;
if (sco == NOSUB) { /* color has no open subcolor */
if (cm->cd[co].nchrs == 1) { /* optimization */
return co;
}
sco = newcolor(cm); /* must create subcolor */
if (sco == COLORLESS) {
assert(CISERR());
return COLORLESS;
}
cm->cd[co].sub = sco;
|
| ︙ | ︙ |
Changes to generic/regc_locale.c.
| ︙ | ︙ | |||
170 171 172 173 174 175 176 |
{0x19B0, 0x19C9}, {0x1A00, 0x1A16}, {0x1A20, 0x1A54}, {0x1B05, 0x1B33},
{0x1B45, 0x1B4C}, {0x1B83, 0x1BA0}, {0x1BBA, 0x1BE5}, {0x1C00, 0x1C23},
{0x1C4D, 0x1C4F}, {0x1C5A, 0x1C7D}, {0x1C80, 0x1C8A}, {0x1C90, 0x1CBA},
{0x1CBD, 0x1CBF}, {0x1CE9, 0x1CEC}, {0x1CEE, 0x1CF3}, {0x1D00, 0x1DBF},
{0x1E00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
{0x1F50, 0x1F57}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FBC},
{0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB},
| | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
{0x19B0, 0x19C9}, {0x1A00, 0x1A16}, {0x1A20, 0x1A54}, {0x1B05, 0x1B33},
{0x1B45, 0x1B4C}, {0x1B83, 0x1BA0}, {0x1BBA, 0x1BE5}, {0x1C00, 0x1C23},
{0x1C4D, 0x1C4F}, {0x1C5A, 0x1C7D}, {0x1C80, 0x1C8A}, {0x1C90, 0x1CBA},
{0x1CBD, 0x1CBF}, {0x1CE9, 0x1CEC}, {0x1CEE, 0x1CF3}, {0x1D00, 0x1DBF},
{0x1E00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
{0x1F50, 0x1F57}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FBC},
{0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB},
{0x1FE0, 0x1FEC}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x2090, 0x209C},
{0x210A, 0x2113}, {0x2119, 0x211D}, {0x212A, 0x212D}, {0x212F, 0x2139},
{0x213C, 0x213F}, {0x2145, 0x2149}, {0x2C00, 0x2CE4}, {0x2CEB, 0x2CEE},
{0x2D00, 0x2D25}, {0x2D30, 0x2D67}, {0x2D80, 0x2D96}, {0x2DA0, 0x2DA6},
{0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6},
{0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x3031, 0x3035},
{0x3041, 0x3096}, {0x309D, 0x309F}, {0x30A1, 0x30FA}, {0x30FC, 0x30FF},
{0x3105, 0x312F}, {0x3131, 0x318E}, {0x31A0, 0x31BF}, {0x31F0, 0x31FF},
{0x3400, 0x4DBF}, {0x4E00, 0xA48C}, {0xA4D0, 0xA4FD}, {0xA500, 0xA60C},
{0xA610, 0xA61F}, {0xA640, 0xA66E}, {0xA67F, 0xA69D}, {0xA6A0, 0xA6E5},
{0xA717, 0xA71F}, {0xA722, 0xA788}, {0xA78B, 0xA7DC}, {0xA7F1, 0xA801},
{0xA803, 0xA805}, {0xA807, 0xA80A}, {0xA80C, 0xA822}, {0xA840, 0xA873},
{0xA882, 0xA8B3}, {0xA8F2, 0xA8F7}, {0xA90A, 0xA925}, {0xA930, 0xA946},
{0xA960, 0xA97C}, {0xA984, 0xA9B2}, {0xA9E0, 0xA9E4}, {0xA9E6, 0xA9EF},
{0xA9FA, 0xA9FE}, {0xAA00, 0xAA28}, {0xAA40, 0xAA42}, {0xAA44, 0xAA4B},
{0xAA60, 0xAA76}, {0xAA7E, 0xAAAF}, {0xAAB9, 0xAABD}, {0xAADB, 0xAADD},
{0xAAE0, 0xAAEA}, {0xAAF2, 0xAAF4}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E},
{0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E}, {0xAB30, 0xAB5A},
|
| ︙ | ︙ | |||
204 205 206 207 208 209 210 |
{0x10050, 0x1005D}, {0x10080, 0x100FA}, {0x10280, 0x1029C}, {0x102A0, 0x102D0},
{0x10300, 0x1031F}, {0x1032D, 0x10340}, {0x10342, 0x10349}, {0x10350, 0x10375},
{0x10380, 0x1039D}, {0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x10400, 0x1049D},
{0x104B0, 0x104D3}, {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563},
{0x10570, 0x1057A}, {0x1057C, 0x1058A}, {0x1058C, 0x10592}, {0x10597, 0x105A1},
{0x105A3, 0x105B1}, {0x105B3, 0x105B9}, {0x105C0, 0x105F3}, {0x10600, 0x10736},
{0x10740, 0x10755}, {0x10760, 0x10767}, {0x10780, 0x10785}, {0x10787, 0x107B0},
| | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
{0x10050, 0x1005D}, {0x10080, 0x100FA}, {0x10280, 0x1029C}, {0x102A0, 0x102D0},
{0x10300, 0x1031F}, {0x1032D, 0x10340}, {0x10342, 0x10349}, {0x10350, 0x10375},
{0x10380, 0x1039D}, {0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x10400, 0x1049D},
{0x104B0, 0x104D3}, {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563},
{0x10570, 0x1057A}, {0x1057C, 0x1058A}, {0x1058C, 0x10592}, {0x10597, 0x105A1},
{0x105A3, 0x105B1}, {0x105B3, 0x105B9}, {0x105C0, 0x105F3}, {0x10600, 0x10736},
{0x10740, 0x10755}, {0x10760, 0x10767}, {0x10780, 0x10785}, {0x10787, 0x107B0},
{0x107B2, 0x107BA}, {0x10800, 0x10805}, {0x1080A, 0x10835}, {0x1083F, 0x10855},
{0x10860, 0x10876}, {0x10880, 0x1089E}, {0x108E0, 0x108F2}, {0x10900, 0x10915},
{0x10920, 0x10939}, {0x10940, 0x10959}, {0x10980, 0x109B7}, {0x10A10, 0x10A13},
{0x10A15, 0x10A17}, {0x10A19, 0x10A35}, {0x10A60, 0x10A7C}, {0x10A80, 0x10A9C},
{0x10AC0, 0x10AC7}, {0x10AC9, 0x10AE4}, {0x10B00, 0x10B35}, {0x10B40, 0x10B55},
{0x10B60, 0x10B72}, {0x10B80, 0x10B91}, {0x10C00, 0x10C48}, {0x10C80, 0x10CB2},
{0x10CC0, 0x10CF2}, {0x10D00, 0x10D23}, {0x10D4A, 0x10D65}, {0x10D6F, 0x10D85},
{0x10E80, 0x10EA9}, {0x10EC2, 0x10EC7}, {0x10F00, 0x10F1C}, {0x10F30, 0x10F45},
{0x10F70, 0x10F81}, {0x10FB0, 0x10FC4}, {0x10FE0, 0x10FF6}, {0x11003, 0x11037},
{0x11083, 0x110AF}, {0x110D0, 0x110E8}, {0x11103, 0x11126}, {0x11150, 0x11172},
{0x11183, 0x111B2}, {0x111C1, 0x111C4}, {0x11200, 0x11211}, {0x11213, 0x1122B},
{0x11280, 0x11286}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A8},
{0x112B0, 0x112DE}, {0x11305, 0x1130C}, {0x11313, 0x11328}, {0x1132A, 0x11330},
{0x11335, 0x11339}, {0x1135D, 0x11361}, {0x11380, 0x11389}, {0x11390, 0x113B5},
{0x11400, 0x11434}, {0x11447, 0x1144A}, {0x1145F, 0x11461}, {0x11480, 0x114AF},
{0x11580, 0x115AE}, {0x115D8, 0x115DB}, {0x11600, 0x1162F}, {0x11680, 0x116AA},
{0x11700, 0x1171A}, {0x11740, 0x11746}, {0x11800, 0x1182B}, {0x118A0, 0x118DF},
{0x118FF, 0x11906}, {0x1190C, 0x11913}, {0x11918, 0x1192F}, {0x119A0, 0x119A7},
{0x119AA, 0x119D0}, {0x11A0B, 0x11A32}, {0x11A5C, 0x11A89}, {0x11AB0, 0x11AF8},
{0x11BC0, 0x11BE0}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C72, 0x11C8F},
{0x11D00, 0x11D06}, {0x11D0B, 0x11D30}, {0x11D60, 0x11D65}, {0x11D6A, 0x11D89},
{0x11DB0, 0x11DDB}, {0x11EE0, 0x11EF2}, {0x11F04, 0x11F10}, {0x11F12, 0x11F33},
{0x12000, 0x12399}, {0x12480, 0x12543}, {0x12F90, 0x12FF0}, {0x13000, 0x1342F},
{0x13441, 0x13446}, {0x13460, 0x143FA}, {0x14400, 0x14646}, {0x16100, 0x1611D},
{0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A70, 0x16ABE}, {0x16AD0, 0x16AED},
{0x16B00, 0x16B2F}, {0x16B40, 0x16B43}, {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F},
{0x16D40, 0x16D6C}, {0x16E40, 0x16E7F}, {0x16EA0, 0x16EB8}, {0x16EBB, 0x16ED3},
{0x16F00, 0x16F4A}, {0x16F93, 0x16F9F}, {0x17000, 0x18CD5}, {0x18CFF, 0x18D1E},
{0x18D80, 0x18DF2}, {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1B000, 0x1B122},
{0x1B150, 0x1B152}, {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A},
{0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1D400, 0x1D454},
{0x1D456, 0x1D49C}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, {0x1D4BD, 0x1D4C3},
{0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C},
{0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, {0x1D54A, 0x1D550},
{0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D6C0}, {0x1D6C2, 0x1D6DA}, {0x1D6DC, 0x1D6FA},
{0x1D6FC, 0x1D714}, {0x1D716, 0x1D734}, {0x1D736, 0x1D74E}, {0x1D750, 0x1D76E},
{0x1D770, 0x1D788}, {0x1D78A, 0x1D7A8}, {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7CB},
{0x1DF00, 0x1DF1E}, {0x1DF25, 0x1DF2A}, {0x1E030, 0x1E06D}, {0x1E100, 0x1E12C},
{0x1E137, 0x1E13D}, {0x1E290, 0x1E2AD}, {0x1E2C0, 0x1E2EB}, {0x1E4D0, 0x1E4EB},
{0x1E5D0, 0x1E5ED}, {0x1E6C0, 0x1E6DE}, {0x1E6E0, 0x1E6E2}, {0x1E6E7, 0x1E6ED},
{0x1E6F0, 0x1E6F4}, {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB}, {0x1E7F0, 0x1E7FE},
{0x1E800, 0x1E8C4}, {0x1E900, 0x1E943}, {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F},
{0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37}, {0x1EE4D, 0x1EE4F}, {0x1EE67, 0x1EE6A},
{0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, {0x1EE80, 0x1EE89},
{0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB},
{0x20000, 0x2A6DF}, {0x2A700, 0x2B81D}, {0x2B820, 0x2CEAD}, {0x2CEB0, 0x2EBE0},
{0x2EBF0, 0x2EE5D}, {0x2F800, 0x2FA1D}, {0x30000, 0x3134A}, {0x31350, 0x33479}
#endif
};
#define NUM_ALPHA_RANGE ((int)(sizeof(alphaRangeTable)/sizeof(crange)))
static const chr alphaCharTable[] = {
0xAA, 0xB5, 0xBA, 0x2EC, 0x2EE, 0x376, 0x377, 0x37F, 0x386,
0x38C, 0x559, 0x66E, 0x66F, 0x6D5, 0x6E5, 0x6E6, 0x6EE, 0x6EF,
0x6FF, 0x710, 0x7B1, 0x7F4, 0x7F5, 0x7FA, 0x81A, 0x824, 0x828,
0x93D, 0x950, 0x98F, 0x990, 0x9B2, 0x9BD, 0x9CE, 0x9DC, 0x9DD,
0x9F0, 0x9F1, 0x9FC, 0xA0F, 0xA10, 0xA32, 0xA33, 0xA35, 0xA36,
0xA38, 0xA39, 0xA5E, 0xAB2, 0xAB3, 0xABD, 0xAD0, 0xAE0, 0xAE1,
0xAF9, 0xB0F, 0xB10, 0xB32, 0xB33, 0xB3D, 0xB5C, 0xB5D, 0xB71,
0xB83, 0xB99, 0xB9A, 0xB9C, 0xB9E, 0xB9F, 0xBA3, 0xBA4, 0xBD0,
0xC3D, 0xC5C, 0xC5D, 0xC60, 0xC61, 0xC80, 0xCBD, 0xCE0, 0xCE1,
0xCF1, 0xCF2, 0xD3D, 0xD4E, 0xDBD, 0xE32, 0xE33, 0xE81, 0xE82,
0xE84, 0xEA5, 0xEB2, 0xEB3, 0xEBD, 0xEC6, 0xF00, 0x103F, 0x1061,
0x1065, 0x1066, 0x108E, 0x10C7, 0x10CD, 0x1258, 0x12C0, 0x17D7, 0x17DC,
0x18AA, 0x1AA7, 0x1BAE, 0x1BAF, 0x1CF5, 0x1CF6, 0x1CFA, 0x1F59, 0x1F5B,
0x1F5D, 0x1FBE, 0x2071, 0x207F, 0x2102, 0x2107, 0x2115, 0x2124, 0x2126,
0x2128, 0x214E, 0x2183, 0x2184, 0x2CF2, 0x2CF3, 0x2D27, 0x2D2D, 0x2D6F,
0x2E2F, 0x3005, 0x3006, 0x303B, 0x303C, 0xA62A, 0xA62B, 0xA8FB, 0xA8FD,
0xA8FE, 0xA9CF, 0xAA7A, 0xAAB1, 0xAAB5, 0xAAB6, 0xAAC0, 0xAAC2, 0xFB1D,
0xFB3E, 0xFB40, 0xFB41, 0xFB43, 0xFB44
#if CHRBITS > 16
,0x1003C, 0x1003D, 0x10594, 0x10595, 0x105BB, 0x105BC, 0x10808, 0x10837, 0x10838,
0x1083C, 0x108F4, 0x108F5, 0x109BE, 0x109BF, 0x10A00, 0x10EB0, 0x10EB1, 0x10F27,
0x11071, 0x11072, 0x11075, 0x11144, 0x11147, 0x11176, 0x111DA, 0x111DC, 0x1123F,
0x11240, 0x11288, 0x1130F, 0x11310, 0x11332, 0x11333, 0x1133D, 0x11350, 0x1138B,
0x1138E, 0x113B7, 0x113D1, 0x113D3, 0x114C4, 0x114C5, 0x114C7, 0x11644, 0x116B8,
0x11909, 0x11915, 0x11916, 0x1193F, 0x11941, 0x119E1, 0x119E3, 0x11A00, 0x11A3A,
0x11A50, 0x11A9D, 0x11C40, 0x11D08, 0x11D09, 0x11D46, 0x11D67, 0x11D68, 0x11D98,
0x11F02, 0x11FB0, 0x16F50, 0x16FE0, 0x16FE1, 0x16FE3, 0x16FF2, 0x16FF3, 0x1AFFD,
0x1AFFE, 0x1B132, 0x1B155, 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A5, 0x1D4A6, 0x1D4BB,
0x1D546, 0x1E14E, 0x1E5F0, 0x1E6E4, 0x1E6E5, 0x1E6FE, 0x1E6FF, 0x1E7ED, 0x1E7EE,
0x1E94B, 0x1EE21, 0x1EE22, 0x1EE24, 0x1EE27, 0x1EE39, 0x1EE3B, 0x1EE42, 0x1EE47,
0x1EE49, 0x1EE4B, 0x1EE51, 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59, 0x1EE5B, 0x1EE5D,
0x1EE5F, 0x1EE61, 0x1EE62, 0x1EE64, 0x1EE7E
#endif
};
#define NUM_ALPHA_CHAR ((int)(sizeof(alphaCharTable)/sizeof(chr)))
/*
* Unicode: control characters.
|
| ︙ | ︙ | |||
342 343 344 345 346 347 348 |
#if CHRBITS > 16
,{0x104A0, 0x104A9}, {0x10D30, 0x10D39}, {0x10D40, 0x10D49}, {0x11066, 0x1106F},
{0x110F0, 0x110F9}, {0x11136, 0x1113F}, {0x111D0, 0x111D9}, {0x112F0, 0x112F9},
{0x11450, 0x11459}, {0x114D0, 0x114D9}, {0x11650, 0x11659}, {0x116C0, 0x116C9},
{0x116D0, 0x116E3}, {0x11730, 0x11739}, {0x118E0, 0x118E9}, {0x11950, 0x11959},
{0x11BF0, 0x11BF9}, {0x11C50, 0x11C59}, {0x11D50, 0x11D59}, {0x11DA0, 0x11DA9},
{0x11DE0, 0x11DE9}, {0x11F50, 0x11F59}, {0x16130, 0x16139}, {0x16A60, 0x16A69},
| | | | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
#if CHRBITS > 16
,{0x104A0, 0x104A9}, {0x10D30, 0x10D39}, {0x10D40, 0x10D49}, {0x11066, 0x1106F},
{0x110F0, 0x110F9}, {0x11136, 0x1113F}, {0x111D0, 0x111D9}, {0x112F0, 0x112F9},
{0x11450, 0x11459}, {0x114D0, 0x114D9}, {0x11650, 0x11659}, {0x116C0, 0x116C9},
{0x116D0, 0x116E3}, {0x11730, 0x11739}, {0x118E0, 0x118E9}, {0x11950, 0x11959},
{0x11BF0, 0x11BF9}, {0x11C50, 0x11C59}, {0x11D50, 0x11D59}, {0x11DA0, 0x11DA9},
{0x11DE0, 0x11DE9}, {0x11F50, 0x11F59}, {0x16130, 0x16139}, {0x16A60, 0x16A69},
{0x16AC0, 0x16AC9}, {0x16B50, 0x16B59}, {0x16D70, 0x16D79}, {0x1CCF0, 0x1CCF9},
{0x1D7CE, 0x1D7FF}, {0x1E140, 0x1E149}, {0x1E2F0, 0x1E2F9}, {0x1E4F0, 0x1E4F9},
{0x1E5F1, 0x1E5FA}, {0x1E950, 0x1E959}, {0x1FBF0, 0x1FBF9}
#endif
};
#define NUM_DIGIT_RANGE ((int)(sizeof(digitRangeTable)/sizeof(crange)))
/*
* no singletons of digit characters.
|
| ︙ | ︙ | |||
368 369 370 371 372 373 374 |
{0x7F7, 0x7F9}, {0x830, 0x83E}, {0xF04, 0xF12}, {0xF3A, 0xF3D},
{0xFD0, 0xFD4}, {0x104A, 0x104F}, {0x1360, 0x1368}, {0x16EB, 0x16ED},
{0x17D4, 0x17D6}, {0x17D8, 0x17DA}, {0x1800, 0x180A}, {0x1AA0, 0x1AA6},
{0x1AA8, 0x1AAD}, {0x1B5A, 0x1B60}, {0x1B7D, 0x1B7F}, {0x1BFC, 0x1BFF},
{0x1C3B, 0x1C3F}, {0x1CC0, 0x1CC7}, {0x2010, 0x2027}, {0x2030, 0x2043},
{0x2045, 0x2051}, {0x2053, 0x205E}, {0x2308, 0x230B}, {0x2768, 0x2775},
{0x27E6, 0x27EF}, {0x2983, 0x2998}, {0x29D8, 0x29DB}, {0x2CF9, 0x2CFC},
| | | | | | < | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
{0x7F7, 0x7F9}, {0x830, 0x83E}, {0xF04, 0xF12}, {0xF3A, 0xF3D},
{0xFD0, 0xFD4}, {0x104A, 0x104F}, {0x1360, 0x1368}, {0x16EB, 0x16ED},
{0x17D4, 0x17D6}, {0x17D8, 0x17DA}, {0x1800, 0x180A}, {0x1AA0, 0x1AA6},
{0x1AA8, 0x1AAD}, {0x1B5A, 0x1B60}, {0x1B7D, 0x1B7F}, {0x1BFC, 0x1BFF},
{0x1C3B, 0x1C3F}, {0x1CC0, 0x1CC7}, {0x2010, 0x2027}, {0x2030, 0x2043},
{0x2045, 0x2051}, {0x2053, 0x205E}, {0x2308, 0x230B}, {0x2768, 0x2775},
{0x27E6, 0x27EF}, {0x2983, 0x2998}, {0x29D8, 0x29DB}, {0x2CF9, 0x2CFC},
{0x2E00, 0x2E2E}, {0x2E30, 0x2E4F}, {0x2E52, 0x2E5D}, {0x3001, 0x3003},
{0x3008, 0x3011}, {0x3014, 0x301F}, {0xA60D, 0xA60F}, {0xA6F2, 0xA6F7},
{0xA874, 0xA877}, {0xA8F8, 0xA8FA}, {0xA9C1, 0xA9CD}, {0xAA5C, 0xAA5F},
{0xFE10, 0xFE19}, {0xFE30, 0xFE52}, {0xFE54, 0xFE61}, {0xFF01, 0xFF03},
{0xFF05, 0xFF0A}, {0xFF0C, 0xFF0F}, {0xFF3B, 0xFF3D}, {0xFF5F, 0xFF65}
#if CHRBITS > 16
,{0x10100, 0x10102}, {0x10A50, 0x10A58}, {0x10AF0, 0x10AF6}, {0x10B39, 0x10B3F},
{0x10B99, 0x10B9C}, {0x10F55, 0x10F59}, {0x10F86, 0x10F89}, {0x11047, 0x1104D},
{0x110BE, 0x110C1}, {0x11140, 0x11143}, {0x111C5, 0x111C8}, {0x111DD, 0x111DF},
{0x11238, 0x1123D}, {0x1144B, 0x1144F}, {0x115C1, 0x115D7}, {0x11641, 0x11643},
{0x11660, 0x1166C}, {0x1173C, 0x1173E}, {0x11944, 0x11946}, {0x11A3F, 0x11A46},
{0x11A9A, 0x11A9C}, {0x11A9E, 0x11AA2}, {0x11B00, 0x11B09}, {0x11C41, 0x11C45},
|
| ︙ | ︙ | |||
455 456 457 458 459 460 461 |
#if CHRBITS > 16
,{0x10428, 0x1044F}, {0x104D8, 0x104FB}, {0x10597, 0x105A1}, {0x105A3, 0x105B1},
{0x105B3, 0x105B9}, {0x10CC0, 0x10CF2}, {0x10D70, 0x10D85}, {0x118C0, 0x118DF},
{0x16E60, 0x16E7F}, {0x16EBB, 0x16ED3}, {0x1D41A, 0x1D433}, {0x1D44E, 0x1D454},
{0x1D456, 0x1D467}, {0x1D482, 0x1D49B}, {0x1D4B6, 0x1D4B9}, {0x1D4BD, 0x1D4C3},
{0x1D4C5, 0x1D4CF}, {0x1D4EA, 0x1D503}, {0x1D51E, 0x1D537}, {0x1D552, 0x1D56B},
{0x1D586, 0x1D59F}, {0x1D5BA, 0x1D5D3}, {0x1D5EE, 0x1D607}, {0x1D622, 0x1D63B},
| | | < | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
#if CHRBITS > 16
,{0x10428, 0x1044F}, {0x104D8, 0x104FB}, {0x10597, 0x105A1}, {0x105A3, 0x105B1},
{0x105B3, 0x105B9}, {0x10CC0, 0x10CF2}, {0x10D70, 0x10D85}, {0x118C0, 0x118DF},
{0x16E60, 0x16E7F}, {0x16EBB, 0x16ED3}, {0x1D41A, 0x1D433}, {0x1D44E, 0x1D454},
{0x1D456, 0x1D467}, {0x1D482, 0x1D49B}, {0x1D4B6, 0x1D4B9}, {0x1D4BD, 0x1D4C3},
{0x1D4C5, 0x1D4CF}, {0x1D4EA, 0x1D503}, {0x1D51E, 0x1D537}, {0x1D552, 0x1D56B},
{0x1D586, 0x1D59F}, {0x1D5BA, 0x1D5D3}, {0x1D5EE, 0x1D607}, {0x1D622, 0x1D63B},
{0x1D656, 0x1D66F}, {0x1D68A, 0x1D6A5}, {0x1D6C2, 0x1D6DA}, {0x1D6DC, 0x1D6E1},
{0x1D6FC, 0x1D714}, {0x1D716, 0x1D71B}, {0x1D736, 0x1D74E}, {0x1D750, 0x1D755},
{0x1D770, 0x1D788}, {0x1D78A, 0x1D78F}, {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7C9},
{0x1DF00, 0x1DF09}, {0x1DF0B, 0x1DF1E}, {0x1DF25, 0x1DF2A}, {0x1E922, 0x1E943}
#endif
};
#define NUM_LOWER_RANGE ((int)(sizeof(lowerRangeTable)/sizeof(crange)))
static const chr lowerCharTable[] = {
0xB5, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F,
|
| ︙ | ︙ | |||
533 534 535 536 537 538 539 |
0xA761, 0xA763, 0xA765, 0xA767, 0xA769, 0xA76B, 0xA76D, 0xA76F, 0xA77A,
0xA77C, 0xA77F, 0xA781, 0xA783, 0xA785, 0xA787, 0xA78C, 0xA78E, 0xA791,
0xA797, 0xA799, 0xA79B, 0xA79D, 0xA79F, 0xA7A1, 0xA7A3, 0xA7A5, 0xA7A7,
0xA7A9, 0xA7AF, 0xA7B5, 0xA7B7, 0xA7B9, 0xA7BB, 0xA7BD, 0xA7BF, 0xA7C1,
0xA7C3, 0xA7C8, 0xA7CA, 0xA7CD, 0xA7CF, 0xA7D1, 0xA7D3, 0xA7D5, 0xA7D7,
0xA7D9, 0xA7DB, 0xA7F6, 0xA7FA
#if CHRBITS > 16
| | < | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
0xA761, 0xA763, 0xA765, 0xA767, 0xA769, 0xA76B, 0xA76D, 0xA76F, 0xA77A,
0xA77C, 0xA77F, 0xA781, 0xA783, 0xA785, 0xA787, 0xA78C, 0xA78E, 0xA791,
0xA797, 0xA799, 0xA79B, 0xA79D, 0xA79F, 0xA7A1, 0xA7A3, 0xA7A5, 0xA7A7,
0xA7A9, 0xA7AF, 0xA7B5, 0xA7B7, 0xA7B9, 0xA7BB, 0xA7BD, 0xA7BF, 0xA7C1,
0xA7C3, 0xA7C8, 0xA7CA, 0xA7CD, 0xA7CF, 0xA7D1, 0xA7D3, 0xA7D5, 0xA7D7,
0xA7D9, 0xA7DB, 0xA7F6, 0xA7FA
#if CHRBITS > 16
,0x105BB, 0x105BC, 0x1D4BB, 0x1D7CB
#endif
};
#define NUM_LOWER_CHAR ((int)(sizeof(lowerCharTable)/sizeof(chr)))
/*
* Unicode: uppercase characters.
|
| ︙ | ︙ | |||
637 638 639 640 641 642 643 |
0xA742, 0xA744, 0xA746, 0xA748, 0xA74A, 0xA74C, 0xA74E, 0xA750, 0xA752,
0xA754, 0xA756, 0xA758, 0xA75A, 0xA75C, 0xA75E, 0xA760, 0xA762, 0xA764,
0xA766, 0xA768, 0xA76A, 0xA76C, 0xA76E, 0xA779, 0xA77B, 0xA77D, 0xA77E,
0xA780, 0xA782, 0xA784, 0xA786, 0xA78B, 0xA78D, 0xA790, 0xA792, 0xA796,
0xA798, 0xA79A, 0xA79C, 0xA79E, 0xA7A0, 0xA7A2, 0xA7A4, 0xA7A6, 0xA7A8,
0xA7B6, 0xA7B8, 0xA7BA, 0xA7BC, 0xA7BE, 0xA7C0, 0xA7C2, 0xA7C9, 0xA7CB,
0xA7CC, 0xA7CE, 0xA7D0, 0xA7D2, 0xA7D4, 0xA7D6, 0xA7D8, 0xA7DA, 0xA7DC,
| | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
0xA742, 0xA744, 0xA746, 0xA748, 0xA74A, 0xA74C, 0xA74E, 0xA750, 0xA752,
0xA754, 0xA756, 0xA758, 0xA75A, 0xA75C, 0xA75E, 0xA760, 0xA762, 0xA764,
0xA766, 0xA768, 0xA76A, 0xA76C, 0xA76E, 0xA779, 0xA77B, 0xA77D, 0xA77E,
0xA780, 0xA782, 0xA784, 0xA786, 0xA78B, 0xA78D, 0xA790, 0xA792, 0xA796,
0xA798, 0xA79A, 0xA79C, 0xA79E, 0xA7A0, 0xA7A2, 0xA7A4, 0xA7A6, 0xA7A8,
0xA7B6, 0xA7B8, 0xA7BA, 0xA7BC, 0xA7BE, 0xA7C0, 0xA7C2, 0xA7C9, 0xA7CB,
0xA7CC, 0xA7CE, 0xA7D0, 0xA7D2, 0xA7D4, 0xA7D6, 0xA7D8, 0xA7DA, 0xA7DC,
0xA7F5
#if CHRBITS > 16
,0x10594, 0x10595, 0x1D49C, 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A5, 0x1D4A6, 0x1D504,
0x1D505, 0x1D538, 0x1D539, 0x1D546, 0x1D7CA
#endif
};
#define NUM_UPPER_CHAR ((int)(sizeof(upperCharTable)/sizeof(chr)))
/*
* Unicode: unicode print characters excluding space.
*/
static const crange graphRangeTable[] = {
{0x21, 0x7E}, {0xA1, 0xAC}, {0xAE, 0x377}, {0x37A, 0x37F},
{0x384, 0x38A}, {0x38E, 0x3A1}, {0x3A3, 0x52F}, {0x531, 0x556},
{0x559, 0x58A}, {0x58D, 0x58F}, {0x591, 0x5C7}, {0x5D0, 0x5EA},
{0x5EF, 0x5F4}, {0x606, 0x61B}, {0x61D, 0x6DC}, {0x6DE, 0x70D},
{0x710, 0x74A}, {0x74D, 0x7B1}, {0x7C0, 0x7FA}, {0x7FD, 0x82D},
{0x830, 0x83E}, {0x840, 0x85B}, {0x860, 0x86A}, {0x870, 0x88F},
{0x897, 0x8E1}, {0x8E3, 0x983}, {0x985, 0x98C}, {0x993, 0x9A8},
{0x9AA, 0x9B0}, {0x9B6, 0x9B9}, {0x9BC, 0x9C4}, {0x9CB, 0x9CE},
{0x9DF, 0x9E3}, {0x9E6, 0x9FE}, {0xA01, 0xA03}, {0xA05, 0xA0A},
{0xA13, 0xA28}, {0xA2A, 0xA30}, {0xA3E, 0xA42}, {0xA4B, 0xA4D},
{0xA59, 0xA5C}, {0xA66, 0xA76}, {0xA81, 0xA83}, {0xA85, 0xA8D},
{0xA8F, 0xA91}, {0xA93, 0xAA8}, {0xAAA, 0xAB0}, {0xAB5, 0xAB9},
{0xABC, 0xAC5}, {0xAC7, 0xAC9}, {0xACB, 0xACD}, {0xAE0, 0xAE3},
{0xAE6, 0xAF1}, {0xAF9, 0xAFF}, {0xB01, 0xB03}, {0xB05, 0xB0C},
{0xB13, 0xB28}, {0xB2A, 0xB30}, {0xB35, 0xB39}, {0xB3C, 0xB44},
{0xB4B, 0xB4D}, {0xB55, 0xB57}, {0xB5F, 0xB63}, {0xB66, 0xB77},
{0xB85, 0xB8A}, {0xB8E, 0xB90}, {0xB92, 0xB95}, {0xBA8, 0xBAA},
{0xBAE, 0xBB9}, {0xBBE, 0xBC2}, {0xBC6, 0xBC8}, {0xBCA, 0xBCD},
{0xBE6, 0xBFA}, {0xC00, 0xC0C}, {0xC0E, 0xC10}, {0xC12, 0xC28},
{0xC2A, 0xC39}, {0xC3C, 0xC44}, {0xC46, 0xC48}, {0xC4A, 0xC4D},
{0xC58, 0xC5A}, {0xC60, 0xC63}, {0xC66, 0xC6F}, {0xC77, 0xC8C},
{0xC8E, 0xC90}, {0xC92, 0xCA8}, {0xCAA, 0xCB3}, {0xCB5, 0xCB9},
{0xCBC, 0xCC4}, {0xCC6, 0xCC8}, {0xCCA, 0xCCD}, {0xCDC, 0xCDE},
{0xCE0, 0xCE3}, {0xCE6, 0xCEF}, {0xCF1, 0xCF3}, {0xD00, 0xD0C},
{0xD0E, 0xD10}, {0xD12, 0xD44}, {0xD46, 0xD48}, {0xD4A, 0xD4F},
{0xD54, 0xD63}, {0xD66, 0xD7F}, {0xD81, 0xD83}, {0xD85, 0xD96},
{0xD9A, 0xDB1}, {0xDB3, 0xDBB}, {0xDC0, 0xDC6}, {0xDCF, 0xDD4},
{0xDD8, 0xDDF}, {0xDE6, 0xDEF}, {0xDF2, 0xDF4}, {0xE01, 0xE3A},
{0xE3F, 0xE5B}, {0xE86, 0xE8A}, {0xE8C, 0xEA3}, {0xEA7, 0xEBD},
{0xEC0, 0xEC4}, {0xEC8, 0xECE}, {0xED0, 0xED9}, {0xEDC, 0xEDF},
{0xF00, 0xF47}, {0xF49, 0xF6C}, {0xF71, 0xF97}, {0xF99, 0xFBC},
{0xFBE, 0xFCC}, {0xFCE, 0xFDA}, {0x1000, 0x10C5}, {0x10D0, 0x1248},
{0x124A, 0x124D}, {0x1250, 0x1256}, {0x125A, 0x125D}, {0x1260, 0x1288},
{0x128A, 0x128D}, {0x1290, 0x12B0}, {0x12B2, 0x12B5}, {0x12B8, 0x12BE},
{0x12C2, 0x12C5}, {0x12C8, 0x12D6}, {0x12D8, 0x1310}, {0x1312, 0x1315},
{0x1318, 0x135A}, {0x135D, 0x137C}, {0x1380, 0x1399}, {0x13A0, 0x13F5},
{0x13F8, 0x13FD}, {0x1400, 0x167F}, {0x1681, 0x169C}, {0x16A0, 0x16F8},
{0x1700, 0x1715}, {0x171F, 0x1736}, {0x1740, 0x1753}, {0x1760, 0x176C},
{0x176E, 0x1770}, {0x1780, 0x17DD}, {0x17E0, 0x17E9}, {0x17F0, 0x17F9},
{0x1800, 0x180D}, {0x180F, 0x1819}, {0x1820, 0x1878}, {0x1880, 0x18AA},
{0x18B0, 0x18F5}, {0x1900, 0x191E}, {0x1920, 0x192B}, {0x1930, 0x193B},
{0x1944, 0x196D}, {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9},
{0x19D0, 0x19DA}, {0x19DE, 0x1A1B}, {0x1A1E, 0x1A5E}, {0x1A60, 0x1A7C},
{0x1A7F, 0x1A89}, {0x1A90, 0x1A99}, {0x1AA0, 0x1AAD}, {0x1AB0, 0x1ADD},
{0x1AE0, 0x1AEB}, {0x1B00, 0x1B4C}, {0x1B4E, 0x1BF3}, {0x1BFC, 0x1C37},
{0x1C3B, 0x1C49}, {0x1C4D, 0x1C8A}, {0x1C90, 0x1CBA}, {0x1CBD, 0x1CC7},
{0x1CD0, 0x1CFA}, {0x1D00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45},
{0x1F48, 0x1F4D}, {0x1F50, 0x1F57}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4},
{0x1FB6, 0x1FC4}, {0x1FC6, 0x1FD3}, {0x1FD6, 0x1FDB}, {0x1FDD, 0x1FEF},
{0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFE}, {0x2010, 0x2027}, {0x2030, 0x205E},
{0x2074, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20C1}, {0x20D0, 0x20F0},
{0x2100, 0x218B}, {0x2190, 0x2429}, {0x2440, 0x244A}, {0x2460, 0x2B73},
{0x2B76, 0x2CF3}, {0x2CF9, 0x2D25}, {0x2D30, 0x2D67}, {0x2D7F, 0x2D96},
{0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, {0x2DB8, 0x2DBE},
{0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE},
{0x2DE0, 0x2E5D}, {0x2E80, 0x2E99}, {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5},
{0x2FF0, 0x2FFF}, {0x3001, 0x303F}, {0x3041, 0x3096}, {0x3099, 0x30FF},
{0x3105, 0x312F}, {0x3131, 0x318E}, {0x3190, 0x31E5}, {0x31EF, 0x321E},
{0x3220, 0xA48C}, {0xA490, 0xA4C6}, {0xA4D0, 0xA62B}, {0xA640, 0xA6F7},
{0xA700, 0xA7DC}, {0xA7F1, 0xA82C}, {0xA830, 0xA839}, {0xA840, 0xA877},
{0xA880, 0xA8C5}, {0xA8CE, 0xA8D9}, {0xA8E0, 0xA953}, {0xA95F, 0xA97C},
{0xA980, 0xA9CD}, {0xA9CF, 0xA9D9}, {0xA9DE, 0xA9FE}, {0xAA00, 0xAA36},
{0xAA40, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA5C, 0xAAC2}, {0xAADB, 0xAAF6},
{0xAB01, 0xAB06}, {0xAB09, 0xAB0E}, {0xAB11, 0xAB16}, {0xAB20, 0xAB26},
{0xAB28, 0xAB2E}, {0xAB30, 0xAB6B}, {0xAB70, 0xABED}, {0xABF0, 0xABF9},
{0xAC00, 0xD7A3}, {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xF900, 0xFA6D},
{0xFA70, 0xFAD9}, {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, {0xFB1D, 0xFB36},
{0xFB38, 0xFB3C}, {0xFB46, 0xFDCF}, {0xFDF0, 0xFE19}, {0xFE20, 0xFE52},
{0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC},
{0xFF01, 0xFFBE}, {0xFFC2, 0xFFC7}, {0xFFCA, 0xFFCF}, {0xFFD2, 0xFFD7},
{0xFFDA, 0xFFDC}, {0xFFE0, 0xFFE6}, {0xFFE8, 0xFFEE}
#if CHRBITS > 16
,{0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A}, {0x1003F, 0x1004D},
{0x10050, 0x1005D}, {0x10080, 0x100FA}, {0x10100, 0x10102}, {0x10107, 0x10133},
{0x10137, 0x1018E}, {0x10190, 0x1019C}, {0x101D0, 0x101FD}, {0x10280, 0x1029C},
{0x102A0, 0x102D0}, {0x102E0, 0x102FB}, {0x10300, 0x10323}, {0x1032D, 0x1034A},
{0x10350, 0x1037A}, {0x10380, 0x1039D}, {0x1039F, 0x103C3}, {0x103C8, 0x103D5},
{0x10400, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3}, {0x104D8, 0x104FB},
{0x10500, 0x10527}, {0x10530, 0x10563}, {0x1056F, 0x1057A}, {0x1057C, 0x1058A},
{0x1058C, 0x10592}, {0x10597, 0x105A1}, {0x105A3, 0x105B1}, {0x105B3, 0x105B9},
{0x105C0, 0x105F3}, {0x10600, 0x10736}, {0x10740, 0x10755}, {0x10760, 0x10767},
{0x10780, 0x10785}, {0x10787, 0x107B0}, {0x107B2, 0x107BA}, {0x10800, 0x10805},
{0x1080A, 0x10835}, {0x1083F, 0x10855}, {0x10857, 0x1089E}, {0x108A7, 0x108AF},
{0x108E0, 0x108F2}, {0x108FB, 0x1091B}, {0x1091F, 0x10939}, {0x1093F, 0x10959},
{0x10980, 0x109B7}, {0x109BC, 0x109CF}, {0x109D2, 0x10A03}, {0x10A0C, 0x10A13},
{0x10A15, 0x10A17}, {0x10A19, 0x10A35}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A48},
{0x10A50, 0x10A58}, {0x10A60, 0x10A9F}, {0x10AC0, 0x10AE6}, {0x10AEB, 0x10AF6},
{0x10B00, 0x10B35}, {0x10B39, 0x10B55}, {0x10B58, 0x10B72}, {0x10B78, 0x10B91},
{0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF}, {0x10C00, 0x10C48}, {0x10C80, 0x10CB2},
{0x10CC0, 0x10CF2}, {0x10CFA, 0x10D27}, {0x10D30, 0x10D39}, {0x10D40, 0x10D65},
{0x10D69, 0x10D85}, {0x10E60, 0x10E7E}, {0x10E80, 0x10EA9}, {0x10EAB, 0x10EAD},
{0x10EC2, 0x10EC7}, {0x10ED0, 0x10ED8}, {0x10EFA, 0x10F27}, {0x10F30, 0x10F59},
{0x10F70, 0x10F89}, {0x10FB0, 0x10FCB}, {0x10FE0, 0x10FF6}, {0x11000, 0x1104D},
{0x11052, 0x11075}, {0x1107F, 0x110BC}, {0x110BE, 0x110C2}, {0x110D0, 0x110E8},
{0x110F0, 0x110F9}, {0x11100, 0x11134}, {0x11136, 0x11147}, {0x11150, 0x11176},
{0x11180, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211}, {0x11213, 0x11241},
{0x11280, 0x11286}, {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A9},
{0x112B0, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11303}, {0x11305, 0x1130C},
{0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11335, 0x11339}, {0x1133B, 0x11344},
{0x1134B, 0x1134D}, {0x1135D, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374},
{0x11380, 0x11389}, {0x11390, 0x113B5}, {0x113B7, 0x113C0}, {0x113C7, 0x113CA},
{0x113CC, 0x113D5}, {0x11400, 0x1145B}, {0x1145D, 0x11461}, {0x11480, 0x114C7},
{0x114D0, 0x114D9}, {0x11580, 0x115B5}, {0x115B8, 0x115DD}, {0x11600, 0x11644},
{0x11650, 0x11659}, {0x11660, 0x1166C}, {0x11680, 0x116B9}, {0x116C0, 0x116C9},
{0x116D0, 0x116E3}, {0x11700, 0x1171A}, {0x1171D, 0x1172B}, {0x11730, 0x11746},
{0x11800, 0x1183B}, {0x118A0, 0x118F2}, {0x118FF, 0x11906}, {0x1190C, 0x11913},
{0x11918, 0x11935}, {0x1193B, 0x11946}, {0x11950, 0x11959}, {0x119A0, 0x119A7},
{0x119AA, 0x119D7}, {0x119DA, 0x119E4}, {0x11A00, 0x11A47}, {0x11A50, 0x11AA2},
{0x11AB0, 0x11AF8}, {0x11B00, 0x11B09}, {0x11B60, 0x11B67}, {0x11BC0, 0x11BE1},
{0x11BF0, 0x11BF9}, {0x11C00, 0x11C08}, {0x11C0A, 0x11C36}, {0x11C38, 0x11C45},
{0x11C50, 0x11C6C}, {0x11C70, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6},
{0x11D00, 0x11D06}, {0x11D0B, 0x11D36}, {0x11D3F, 0x11D47}, {0x11D50, 0x11D59},
{0x11D60, 0x11D65}, {0x11D6A, 0x11D8E}, {0x11D93, 0x11D98}, {0x11DA0, 0x11DA9},
{0x11DB0, 0x11DDB}, {0x11DE0, 0x11DE9}, {0x11EE0, 0x11EF8}, {0x11F00, 0x11F10},
{0x11F12, 0x11F3A}, {0x11F3E, 0x11F5A}, {0x11FC0, 0x11FF1}, {0x11FFF, 0x12399},
{0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543}, {0x12F90, 0x12FF2},
{0x13000, 0x1342F}, {0x13440, 0x13455}, {0x13460, 0x143FA}, {0x14400, 0x14646},
{0x16100, 0x16139}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, {0x16A60, 0x16A69},
{0x16A6E, 0x16ABE}, {0x16AC0, 0x16AC9}, {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF5},
{0x16B00, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, {0x16B63, 0x16B77},
{0x16B7D, 0x16B8F}, {0x16D40, 0x16D79}, {0x16E40, 0x16E9A}, {0x16EA0, 0x16EB8},
{0x16EBB, 0x16ED3}, {0x16F00, 0x16F4A}, {0x16F4F, 0x16F87}, {0x16F8F, 0x16F9F},
{0x16FE0, 0x16FE4}, {0x16FF0, 0x16FF6}, {0x17000, 0x18CD5}, {0x18CFF, 0x18D1E},
{0x18D80, 0x18DF2}, {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1B000, 0x1B122},
{0x1B150, 0x1B152}, {0x1B164, 0x1B167}, {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A},
{0x1BC70, 0x1BC7C}, {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BC9F},
{0x1CC00, 0x1CCFC}, {0x1CD00, 0x1CEB3}, {0x1CEBA, 0x1CED0}, {0x1CEE0, 0x1CEF0},
{0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, {0x1CF50, 0x1CFC3}, {0x1D000, 0x1D0F5},
{0x1D100, 0x1D126}, {0x1D129, 0x1D172}, {0x1D17B, 0x1D1EA}, {0x1D200, 0x1D245},
{0x1D2C0, 0x1D2D3}, {0x1D2E0, 0x1D2F3}, {0x1D300, 0x1D356}, {0x1D360, 0x1D378},
{0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9},
{0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514},
{0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544},
{0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D7CB}, {0x1D7CE, 0x1DA8B},
{0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1DF00, 0x1DF1E}, {0x1DF25, 0x1DF2A},
{0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E026, 0x1E02A},
{0x1E030, 0x1E06D}, {0x1E100, 0x1E12C}, {0x1E130, 0x1E13D}, {0x1E140, 0x1E149},
{0x1E290, 0x1E2AE}, {0x1E2C0, 0x1E2F9}, {0x1E4D0, 0x1E4F9}, {0x1E5D0, 0x1E5FA},
{0x1E6C0, 0x1E6DE}, {0x1E6E0, 0x1E6F5}, {0x1E7E0, 0x1E7E6}, {0x1E7E8, 0x1E7EB},
{0x1E7F0, 0x1E7FE}, {0x1E800, 0x1E8C4}, {0x1E8C7, 0x1E8D6}, {0x1E900, 0x1E94B},
{0x1E950, 0x1E959}, {0x1EC71, 0x1ECB4}, {0x1ED01, 0x1ED3D}, {0x1EE00, 0x1EE03},
{0x1EE05, 0x1EE1F}, {0x1EE29, 0x1EE32}, {0x1EE34, 0x1EE37}, {0x1EE4D, 0x1EE4F},
{0x1EE67, 0x1EE6A}, {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C},
{0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9},
{0x1EEAB, 0x1EEBB}, {0x1F000, 0x1F02B}, {0x1F030, 0x1F093}, {0x1F0A0, 0x1F0AE},
{0x1F0B1, 0x1F0BF}, {0x1F0C1, 0x1F0CF}, {0x1F0D1, 0x1F0F5}, {0x1F100, 0x1F1AD},
{0x1F1E6, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248}, {0x1F260, 0x1F265},
{0x1F300, 0x1F6D8}, {0x1F6DC, 0x1F6EC}, {0x1F6F0, 0x1F6FC}, {0x1F700, 0x1F7D9},
{0x1F7E0, 0x1F7EB}, {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859},
{0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0x1F8B0, 0x1F8BB}, {0x1F8D0, 0x1F8D8},
{0x1F900, 0x1FA57}, {0x1FA60, 0x1FA6D}, {0x1FA70, 0x1FA7C}, {0x1FA80, 0x1FA8A},
{0x1FA8E, 0x1FAC6}, {0x1FACD, 0x1FADC}, {0x1FADF, 0x1FAEA}, {0x1FAEF, 0x1FAF8},
{0x1FB00, 0x1FB92}, {0x1FB94, 0x1FBFA}, {0x20000, 0x2A6DF}, {0x2A700, 0x2B81D},
{0x2B820, 0x2CEAD}, {0x2CEB0, 0x2EBE0}, {0x2EBF0, 0x2EE5D}, {0x2F800, 0x2FA1D},
{0x30000, 0x3134A}, {0x31350, 0x33479}, {0xE0100, 0xE01EF}
#endif
};
#define NUM_GRAPH_RANGE ((int)(sizeof(graphRangeTable)/sizeof(crange)))
static const chr graphCharTable[] = {
0x38C, 0x85E, 0x98F, 0x990, 0x9B2, 0x9C7, 0x9C8, 0x9D7, 0x9DC,
0x9DD, 0xA0F, 0xA10, 0xA32, 0xA33, 0xA35, 0xA36, 0xA38, 0xA39,
0xA3C, 0xA47, 0xA48, 0xA51, 0xA5E, 0xAB2, 0xAB3, 0xAD0, 0xB0F,
0xB10, 0xB32, 0xB33, 0xB47, 0xB48, 0xB5C, 0xB5D, 0xB82, 0xB83,
0xB99, 0xB9A, 0xB9C, 0xB9E, 0xB9F, 0xBA3, 0xBA4, 0xBD0, 0xBD7,
0xC55, 0xC56, 0xC5C, 0xC5D, 0xCD5, 0xCD6, 0xDBD, 0xDCA, 0xDD6,
0xE81, 0xE82, 0xE84, 0xEA5, 0xEC6, 0x10C7, 0x10CD, 0x1258, 0x12C0,
0x1772, 0x1773, 0x1940, 0x1F59, 0x1F5B, 0x1F5D, 0x2070, 0x2071, 0x2D27,
0x2D2D, 0x2D6F, 0x2D70, 0xFB3E, 0xFB40, 0xFB41, 0xFB43, 0xFB44, 0xFFFC,
0xFFFD
#if CHRBITS > 16
,0x1003C, 0x1003D, 0x101A0, 0x10594, 0x10595, 0x105BB, 0x105BC, 0x10808, 0x10837,
0x10838, 0x1083C, 0x108F4, 0x108F5, 0x10A05, 0x10A06, 0x10D8E, 0x10D8F, 0x10EB0,
0x10EB1, 0x11288, 0x1130F, 0x11310, 0x11332, 0x11333, 0x11347, 0x11348, 0x11350,
0x11357, 0x1138B, 0x1138E, 0x113C2, 0x113C5, 0x113D7, 0x113D8, 0x113E1, 0x113E2,
0x11909, 0x11915, 0x11916, 0x11937, 0x11938, 0x11D08, 0x11D09, 0x11D3A, 0x11D3C,
0x11D3D, 0x11D67, 0x11D68, 0x11D90, 0x11D91, 0x11FB0, 0x1AFFD, 0x1AFFE, 0x1B132,
0x1B155, 0x1D49E, 0x1D49F, 0x1D4A2, 0x1D4A5, 0x1D4A6, 0x1D4BB, 0x1D546, 0x1E023,
0x1E024, 0x1E08F, 0x1E14E, 0x1E14F, 0x1E2FF, 0x1E5FF, 0x1E6FE, 0x1E6FF, 0x1E7ED,
0x1E7EE, 0x1E95E, 0x1E95F, 0x1EE21, 0x1EE22, 0x1EE24, 0x1EE27, 0x1EE39, 0x1EE3B,
0x1EE42, 0x1EE47, 0x1EE49, 0x1EE4B, 0x1EE51, 0x1EE52, 0x1EE54, 0x1EE57, 0x1EE59,
0x1EE5B, 0x1EE5D, 0x1EE5F, 0x1EE61, 0x1EE62, 0x1EE64, 0x1EE7E, 0x1EEF0, 0x1EEF1,
0x1F250, 0x1F251, 0x1F7F0, 0x1F8C0, 0x1F8C1, 0x1FAC8
#endif
};
#define NUM_GRAPH_CHAR ((int)(sizeof(graphCharTable)/sizeof(chr)))
/*
* End of auto-generated Unicode character ranges declarations.
|
| ︙ | ︙ |
Changes to generic/regc_nfa.c.
| ︙ | ︙ | |||
588 589 590 591 592 593 594 |
static void
sortins(
struct nfa * nfa,
struct state * s)
{
struct arc **sortarray;
struct arc *a;
| | | | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
static void
sortins(
struct nfa * nfa,
struct state * s)
{
struct arc **sortarray;
struct arc *a;
int n = s->nins;
int i;
if (n <= 1) {
return; /* nothing to do */
}
/* make an array of arc pointers ... */
sortarray = (struct arc **) MALLOC(n * sizeof(struct arc *));
if (sortarray == NULL) {
|
| ︙ | ︙ | |||
629 630 631 632 633 634 635 |
}
static int
sortins_cmp(
const void *a,
const void *b)
{
| | | | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
}
static int
sortins_cmp(
const void *a,
const void *b)
{
const struct arc *aa = *((const struct arc * const *) a);
const struct arc *bb = *((const struct arc * const *) b);
/* we check the fields in the order they are most likely to be different */
if (aa->from->no < bb->from->no) {
return -1;
}
if (aa->from->no > bb->from->no) {
return 1;
|
| ︙ | ︙ | |||
664 665 666 667 668 669 670 |
static void
sortouts(
struct nfa * nfa,
struct state * s)
{
struct arc **sortarray;
struct arc *a;
| | | | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
static void
sortouts(
struct nfa * nfa,
struct state * s)
{
struct arc **sortarray;
struct arc *a;
int n = s->nouts;
int i;
if (n <= 1) {
return; /* nothing to do */
}
/* make an array of arc pointers ... */
sortarray = (struct arc **) MALLOC(n * sizeof(struct arc *));
if (sortarray == NULL) {
|
| ︙ | ︙ | |||
705 706 707 708 709 710 711 |
}
static int
sortouts_cmp(
const void *a,
const void *b)
{
| | | | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 |
}
static int
sortouts_cmp(
const void *a,
const void *b)
{
const struct arc *aa = *((const struct arc * const *) a);
const struct arc *bb = *((const struct arc * const *) b);
/* we check the fields in the order they are most likely to be different */
if (aa->to->no < bb->to->no) {
return -1;
}
if (aa->to->no > bb->to->no) {
return 1;
|
| ︙ | ︙ | |||
924 925 926 927 928 929 930 |
* and are not guaranteed unique. It's okay to clobber the array contents.
*/
static void
mergeins(
struct nfa * nfa,
struct state * s,
struct arc ** arcarray,
| | | | | 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 |
* and are not guaranteed unique. It's okay to clobber the array contents.
*/
static void
mergeins(
struct nfa * nfa,
struct state * s,
struct arc ** arcarray,
int arccount)
{
struct arc *na;
int i;
int j;
if (arccount <= 0) {
return;
}
/*
* Because we bypass newarc() in this code path, we'd better include a
|
| ︙ | ︙ | |||
1868 1869 1870 1871 1872 1873 1874 |
FILE *f) /* for debug output; NULL none */
{
struct state *s;
struct state *s2;
struct state *nexts;
struct arc *a;
struct arc *nexta;
| | | | | | 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 |
FILE *f) /* for debug output; NULL none */
{
struct state *s;
struct state *s2;
struct state *nexts;
struct arc *a;
struct arc *nexta;
int totalinarcs;
struct arc **inarcsorig;
struct arc **arcarray;
int arccount;
int prevnins;
int nskip;
/*
* First, get rid of any states whose sole out-arc is an EMPTY,
* since they're basically just aliases for their successor. The
* parsing algorithm creates enough of these that it's worth
* special-casing this.
*/
|
| ︙ | ︙ |
Changes to generic/regcomp.c.
| ︙ | ︙ | |||
44 45 46 47 48 49 50 | static void makesearch(struct vars *, struct nfa *); static struct subre *parse(struct vars *, int, int, struct state *, struct state *); static struct subre *parsebranch(struct vars *, int, int, struct state *, struct state *, int); static void parseqatom(struct vars *, int, int, struct state *, struct state *, struct subre *); static void nonword(struct vars *, int, struct state *, struct state *); static void word(struct vars *, int, struct state *, struct state *); static int scannum(struct vars *); | | | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | static void makesearch(struct vars *, struct nfa *); static struct subre *parse(struct vars *, int, int, struct state *, struct state *); static struct subre *parsebranch(struct vars *, int, int, struct state *, struct state *, int); static void parseqatom(struct vars *, int, int, struct state *, struct state *, struct subre *); static void nonword(struct vars *, int, struct state *, struct state *); static void word(struct vars *, int, struct state *, struct state *); static int scannum(struct vars *); static void repeat(struct vars *, struct state *, struct state *, int, int); static void bracket(struct vars *, struct state *, struct state *); static void cbracket(struct vars *, struct state *, struct state *); static void brackpart(struct vars *, struct state *, struct state *); static const chr *scanplain(struct vars *); static void onechr(struct vars *, pchr, struct state *, struct state *); static void dovec(struct vars *, struct cvec *, struct state *, struct state *); static void wordchrs(struct vars *); static struct subre *sub_re(struct vars *, int, int, struct state *, struct state *); static void freesubre(struct vars *, struct subre *); static void freesrnode(struct vars *, struct subre *); static size_t numst(struct subre *, size_t); static void markst(struct subre *); static void cleanst(struct vars *); static long nfatree(struct vars *, struct subre *, FILE *); static long nfanode(struct vars *, struct subre *, FILE *); static int newlacon(struct vars *, struct state *, struct state *, int); static void freelacons(struct subre *, int); static void rfree(regex_t *); static void dump(regex_t *, FILE *); static void dumpst(struct subre *, FILE *, int); static void stdump(struct subre *, FILE *, int); static const char *stid(struct subre *, char *, size_t); /* === regc_lex.c === */ static void lexstart(struct vars *); |
| ︙ | ︙ | |||
124 125 126 127 128 129 130 | static void cparc(struct nfa *, struct arc *, struct state *, struct state *); static void sortins(struct nfa *, struct state *); static int sortins_cmp(const void *, const void *); static void sortouts(struct nfa *, struct state *); static int sortouts_cmp(const void *, const void *); static void moveins(struct nfa *, struct state *, struct state *); static void copyins(struct nfa *, struct state *, struct state *); | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | static void cparc(struct nfa *, struct arc *, struct state *, struct state *); static void sortins(struct nfa *, struct state *); static int sortins_cmp(const void *, const void *); static void sortouts(struct nfa *, struct state *); static int sortouts_cmp(const void *, const void *); static void moveins(struct nfa *, struct state *, struct state *); static void copyins(struct nfa *, struct state *, struct state *); static void mergeins(struct nfa *, struct state *, struct arc **, int); static void moveouts(struct nfa *, struct state *, struct state *); static void copyouts(struct nfa *, struct state *, struct state *); static void cloneouts(struct nfa *, struct state *, struct state *, struct state *, int); static void delsub(struct nfa *, struct state *, struct state *); static void deltraverse(struct nfa *, struct state *, struct state *); static void dupnfa(struct nfa *, struct state *, struct state *, struct state *, struct state *); static void duptraverse(struct nfa *, struct state *, struct state *, int); |
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
const chr *stop; /* end of string */
const chr *savenow; /* saved now and stop for "subroutine call" */
const chr *savestop;
int err; /* error code (0 if none) */
int cflags; /* copy of compile flags */
int lasttype; /* type of previous token */
int nexttype; /* type of next token */
| | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
const chr *stop; /* end of string */
const chr *savenow; /* saved now and stop for "subroutine call" */
const chr *savestop;
int err; /* error code (0 if none) */
int cflags; /* copy of compile flags */
int lasttype; /* type of previous token */
int nexttype; /* type of next token */
size_t nextvalue; /* value (if any) of next token */
int lexcon; /* lexical context type (see lex.c) */
size_t nsubexp; /* subexpression count */
struct subre **subs; /* subRE pointer vector */
size_t nsubs; /* length of vector */
struct subre *sub10[10]; /* initial vector, enough for most */
struct nfa *nfa; /* the NFA */
struct colormap *cm; /* character color map */
|
| ︙ | ︙ | |||
681 682 683 684 685 686 687 | right = newstate(v->nfa); NOERRN(); EMPTYARC(init, left); EMPTYARC(right, final); NOERRN(); branch->left = parsebranch(v, stopper, type, left, right, 0); NOERRN(); | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 |
right = newstate(v->nfa);
NOERRN();
EMPTYARC(init, left);
EMPTYARC(right, final);
NOERRN();
branch->left = parsebranch(v, stopper, type, left, right, 0);
NOERRN();
branch->flags |= UP(branch->flags | branch->left->flags);
if ((branch->flags &~ branches->flags) != 0) { /* new flags */
for (t = branches; t != branch; t = t->right) {
t->flags |= branch->flags;
}
}
} while (EAT('|'));
assert(SEE(stopper) || SEE(EOS));
|
| ︙ | ︙ | |||
784 785 786 787 788 789 790 |
int type, /* LACON (lookahead subRE) or PLAIN */
struct state *lp, /* left state to hang it on */
struct state *rp, /* right state to hang it on */
struct subre *top) /* subtree top */
{
struct state *s; /* temporaries for new states */
struct state *s2;
| | | | | | 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 |
int type, /* LACON (lookahead subRE) or PLAIN */
struct state *lp, /* left state to hang it on */
struct state *rp, /* right state to hang it on */
struct subre *top) /* subtree top */
{
struct state *s; /* temporaries for new states */
struct state *s2;
#define ARCV(t, val) newarc(v->nfa, t, val, lp, rp)
int m, n;
struct subre *atom; /* atom's subtree */
struct subre *t;
int cap; /* capturing parens? */
int pos; /* positive lookahead? */
size_t subno; /* capturing-parens or backref number */
int atomtype;
int qprefer; /* quantifier short/long preference */
int f;
struct subre **atomp; /* where the pointer to atom is */
/*
|
| ︙ | ︙ | |||
986 987 988 989 990 991 992 |
/*
* Postpone everything else pending possible {0}.
*/
break;
case BACKREF: /* the Feature From The Black Lagoon */
INSIST(type != LACON, REG_ESUBREG);
| | | 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 |
/*
* Postpone everything else pending possible {0}.
*/
break;
case BACKREF: /* the Feature From The Black Lagoon */
INSIST(type != LACON, REG_ESUBREG);
INSIST(v->nextvalue < v->nsubs, REG_ESUBREG);
INSIST(v->subs[v->nextvalue] != NULL, REG_ESUBREG);
NOERR();
assert(v->nextvalue > 0);
atom = sub_re(v, 'b', BACKR, lp, rp);
NOERR();
subno = v->nextvalue;
atom->subno = subno;
|
| ︙ | ︙ | |||
1090 1091 1092 1093 1094 1095 1096 |
if (atomtype != '(' && atomtype != BACKREF && !MESSY(UP(f))) {
if (!(m == 1 && n == 1)) {
repeat(v, lp, rp, m, n);
}
if (atom != NULL) {
freesubre(v, atom);
}
| | | 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 |
if (atomtype != '(' && atomtype != BACKREF && !MESSY(UP(f))) {
if (!(m == 1 && n == 1)) {
repeat(v, lp, rp, m, n);
}
if (atom != NULL) {
freesubre(v, atom);
}
top->flags = f;
return;
}
/*
* hard part: something messy
* That is, capturing parens, back reference, short/long clash, or an atom
* with substructure containing one of those.
|
| ︙ | ︙ | |||
1200 1201 1202 1203 1204 1205 1206 | /* * Just stuff everything into atom. */ repeat(v, atom->begin, atom->end, m, n); atom->min = (short) m; atom->max = (short) n; | | | 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 |
/*
* Just stuff everything into atom.
*/
repeat(v, atom->begin, atom->end, m, n);
atom->min = (short) m;
atom->max = (short) n;
atom->flags |= COMBINE(qprefer, atom->flags);
/* rest of branch can be strung starting from atom->end */
s2 = atom->end;
} else if (m == 1 && n == 1) {
/*
* No/vacuous quantifier: done.
*/
|
| ︙ | ︙ | |||
1264 1265 1266 1267 1268 1269 1270 |
t->right = parsebranch(v, stopper, type, s2, rp, 1);
} else {
EMPTYARC(s2, rp);
t->right = sub_re(v, '=', 0, s2, rp);
}
NOERR();
assert(SEE('|') || SEE(stopper) || SEE(EOS));
| | | | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 |
t->right = parsebranch(v, stopper, type, s2, rp, 1);
} else {
EMPTYARC(s2, rp);
t->right = sub_re(v, '=', 0, s2, rp);
}
NOERR();
assert(SEE('|') || SEE(stopper) || SEE(EOS));
t->flags |= COMBINE(t->flags, t->right->flags);
top->flags |= COMBINE(top->flags, t->flags);
}
/*
- nonword - generate arcs for non-word-character ahead or behind
^ static void nonword(struct vars *, int, struct state *, struct state *);
*/
static void
|
| ︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 |
^ static void repeat(struct vars *, struct state *, struct state *, int, int);
*/
static void
repeat(
struct vars *v,
struct state *lp,
struct state *rp,
| | | | | 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 |
^ static void repeat(struct vars *, struct state *, struct state *, int, int);
*/
static void
repeat(
struct vars *v,
struct state *lp,
struct state *rp,
int m,
int n)
{
#define SOME 2
#define INF 3
#define PAIR(x, y) ((x)*4 + (y))
#define REDUCE(x) ( ((x) == DUPINF) ? INF : (((x) > 1) ? SOME : (x)) )
const int rm = REDUCE(m);
const int rn = REDUCE(n);
struct state *s, *s2;
switch (PAIR(rm, rn)) {
case PAIR(0, 0): /* empty string */
delsub(v->nfa, lp, rp);
|
| ︙ | ︙ | |||
1656 1657 1658 1659 1660 1661 1662 |
struct vars *v,
struct cvec *cv,
struct state *lp,
struct state *rp)
{
chr ch, from, to;
const chr *p;
| | | 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 |
struct vars *v,
struct cvec *cv,
struct state *lp,
struct state *rp)
{
chr ch, from, to;
const chr *p;
int i;
for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) {
ch = *p;
newarc(v->nfa, PLAIN, subcolor(v->cm, ch), lp, rp);
}
for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) {
|
| ︙ | ︙ | |||
1740 1741 1742 1743 1744 1745 1746 |
}
ret->chain = v->treechain;
v->treechain = ret;
}
assert(strchr("=b|.*(", op) != NULL);
| | | | 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 |
}
ret->chain = v->treechain;
v->treechain = ret;
}
assert(strchr("=b|.*(", op) != NULL);
ret->op = op;
ret->flags = flags;
ret->id = 0; /* will be assigned later */
ret->subno = 0;
ret->min = ret->max = 1;
ret->left = NULL;
ret->right = NULL;
ret->begin = begin;
ret->end = end;
|
| ︙ | ︙ | |||
1940 1941 1942 1943 1944 1945 1946 |
freenfa(nfa);
return ret;
}
/*
- newlacon - allocate a lookahead-constraint subRE
| | | | | | 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 |
freenfa(nfa);
return ret;
}
/*
- newlacon - allocate a lookahead-constraint subRE
^ static int newlacon(struct vars *, struct state *, struct state *, int);
*/
static int /* lacon number */
newlacon(
struct vars *v,
struct state *begin,
struct state *end,
int pos)
{
int n;
struct subre *newlacons;
struct subre *sub;
if (v->nlacons == 0) {
n = 1; /* skip 0th */
newlacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
} else {
|
| ︙ | ︙ | |||
1984 1985 1986 1987 1988 1989 1990 |
/*
- freelacons - free lookahead-constraint subRE vector
^ static void freelacons(struct subre *, int);
*/
static void
freelacons(
struct subre *subs,
| | | | 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 |
/*
- freelacons - free lookahead-constraint subRE vector
^ static void freelacons(struct subre *, int);
*/
static void
freelacons(
struct subre *subs,
int n)
{
struct subre *sub;
int i;
assert(n > 0);
for (sub=subs+1, i=n-1; i>0; sub++, i--) { /* no 0th */
if (!NULLCNFA(sub->cnfa)) {
freecnfa(&sub->cnfa);
}
}
|
| ︙ | ︙ | |||
2131 2132 2133 2134 2135 2136 2137 |
if (t->flags&BACKR) {
fprintf(f, " hasbackref");
}
if (!(t->flags&INUSE)) {
fprintf(f, " UNUSED");
}
if (t->subno != 0) {
| | | 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 |
if (t->flags&BACKR) {
fprintf(f, " hasbackref");
}
if (!(t->flags&INUSE)) {
fprintf(f, " UNUSED");
}
if (t->subno != 0) {
fprintf(f, " (#%d)", t->subno);
}
if (t->min != 1 || t->max != 1) {
fprintf(f, " {%d,", t->min);
if (t->max != DUPINF) {
fprintf(f, "%d", t->max);
}
fprintf(f, "}");
|
| ︙ | ︙ |
Changes to generic/regcustom.h.
1 | /* | | | 1 2 3 4 5 6 7 8 9 | /* * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms - with or without |
| ︙ | ︙ |
Changes to generic/rege_dfa.c.
| ︙ | ︙ | |||
410 411 412 413 414 415 416 |
FREE(d->mallocarea);
}
}
/*
- hash - construct a hash code for a bitvector
* There are probably better ways, but they're more expensive.
| | | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
FREE(d->mallocarea);
}
}
/*
- hash - construct a hash code for a bitvector
* There are probably better ways, but they're more expensive.
^ static unsigned hash(unsigned *, int);
*/
static unsigned
hash(
unsigned *const uv,
int n)
{
int i;
unsigned h;
h = 0;
for (i = 0; i < n; i++) {
h ^= uv[i];
}
return h;
|
| ︙ | ︙ |
Changes to generic/regex.h.
1 2 3 4 5 6 7 8 | #ifndef _REGEX_H_ #define _REGEX_H_ /* never again */ #include "tclInt.h" /* * regular expressions * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #ifndef _REGEX_H_ #define _REGEX_H_ /* never again */ #include "tclInt.h" /* * regular expressions * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without |
| ︙ | ︙ |
Changes to generic/regexec.c.
| ︙ | ︙ | |||
141 142 143 144 145 146 147 | static int creviterdissect(struct vars *, struct subre *, chr *, chr *); /* === rege_dfa.c === */ static chr *longest(struct vars *const, struct dfa *const, chr *const, chr *const, int *const); static chr *shortest(struct vars *const, struct dfa *const, chr *const, chr *const, chr *const, chr **const, int *const); static chr *lastCold(struct vars *const, struct dfa *const); static struct dfa *newDFA(struct vars *const, struct cnfa *const, struct colormap *const, struct smalldfa *); static void freeDFA(struct dfa *const); | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | static int creviterdissect(struct vars *, struct subre *, chr *, chr *); /* === rege_dfa.c === */ static chr *longest(struct vars *const, struct dfa *const, chr *const, chr *const, int *const); static chr *shortest(struct vars *const, struct dfa *const, chr *const, chr *const, chr *const, chr **const, int *const); static chr *lastCold(struct vars *const, struct dfa *const); static struct dfa *newDFA(struct vars *const, struct cnfa *const, struct colormap *const, struct smalldfa *); static void freeDFA(struct dfa *const); static unsigned hash(unsigned *const, int); static struct sset *initialize(struct vars *const, struct dfa *const, chr *const); static struct sset *miss(struct vars *const, struct dfa *const, struct sset *const, const pcolor, chr *const, chr *const); static int checkLAConstraint(struct vars *const, struct cnfa *const, chr *const, const pcolor); static struct sset *getVacantSS(struct vars *const, struct dfa *const, chr *const, chr *const); static struct sset *pickNextSS(struct vars *const, struct dfa *const, chr *const, chr *const); /* automatically gathered by fwd; do not hand-edit */ /* =====^!^===== end forwards =====^!^===== */ |
| ︙ | ︙ | |||
167 168 169 170 171 172 173 |
rm_detail_t *details,
size_t nmatch,
regmatch_t pmatch[],
int flags)
{
AllocVars(v);
int st, backref;
| | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
rm_detail_t *details,
size_t nmatch,
regmatch_t pmatch[],
int flags)
{
AllocVars(v);
int st, backref;
int n;
int i;
#define LOCALMAT 20
regmatch_t mat[LOCALMAT];
#define LOCALDFAS 40
struct dfa *subdfas[LOCALDFAS];
/*
* Sanity checks.
|
| ︙ | ︙ | |||
587 588 589 590 591 592 593 |
static void
subset(
struct vars *const v,
struct subre *const sub,
chr *const begin,
chr *const end)
{
| | | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
static void
subset(
struct vars *const v,
struct subre *const sub,
chr *const begin,
chr *const end)
{
int n = sub->subno;
assert(n > 0);
if ((size_t)n >= v->nmatch) {
return;
}
MDEBUG(("setting %d\n", n));
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 |
static int /* regexec return code */
cbrdissect(
struct vars *v,
struct subre *t,
chr *begin, /* beginning of relevant substring */
chr *end) /* end of same */
{
| < | > | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 |
static int /* regexec return code */
cbrdissect(
struct vars *v,
struct subre *t,
chr *begin, /* beginning of relevant substring */
chr *end) /* end of same */
{
int n = t->subno, min = t->min, max = t->max;
size_t numreps;
size_t tlen;
size_t brlen;
chr *brstring;
chr *p;
assert(t != NULL);
assert(t->op == 'b');
assert(n >= 0);
assert((size_t)n < v->nmatch);
MDEBUG(("cbackref n%d %d{%d-%d}\n", t->id, n, min, max));
/* get the backreferenced string */
if (v->pmatch[n].rm_so == FREESTATE) {
return REG_NOMATCH;
|
| ︙ | ︙ |
Changes to generic/regguts.h.
1 2 3 | /* * Internal interface definitions, etc., for the reg package * | | | 1 2 3 4 5 6 7 8 9 10 11 | /* * Internal interface definitions, etc., for the reg package * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without |
| ︙ | ︙ | |||
360 361 362 363 364 365 366 |
#define SMIX(f) ((f)<<1) /* SHORTER -> MIXED */
#define UP(f) (((f)&~NOPROP) | (LMIX(f) & SMIX(f) & MIXED))
#define MESSY(f) ((f)&(MIXED|CAP|BACKR))
#define PREF(f) ((f)&NOPROP)
#define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2))
#define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2))
short id; /* ID of subre (1..ntree-1) */
| | | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
#define SMIX(f) ((f)<<1) /* SHORTER -> MIXED */
#define UP(f) (((f)&~NOPROP) | (LMIX(f) & SMIX(f) & MIXED))
#define MESSY(f) ((f)&(MIXED|CAP|BACKR))
#define PREF(f) ((f)&NOPROP)
#define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2))
#define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2))
short id; /* ID of subre (1..ntree-1) */
int subno; /* subexpression number (for 'b' and '(') */
short min; /* min repetitions for iteration or backref */
short max; /* max repetitions for iteration or backref */
struct subre *left; /* left child, if any (also freelist chain) */
struct subre *right; /* right child, if any */
struct state *begin; /* outarcs from here... */
struct state *end; /* ...ending in inarcs here */
struct cnfa cnfa; /* compacted NFA, if any */
|
| ︙ | ︙ |
Changes to generic/tcl.decls.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 |
const char *name, const char *version, int exact,
void *clientDataPtr)
}
declare 2 {
TCL_NORETURN void Tcl_Panic(const char *format, ...)
}
declare 3 {
| | | | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
const char *name, const char *version, int exact,
void *clientDataPtr)
}
declare 2 {
TCL_NORETURN void Tcl_Panic(const char *format, ...)
}
declare 3 {
void *Tcl_Alloc(TCL_HASH_TYPE size)
}
declare 4 {
void Tcl_Free(void *ptr)
}
declare 5 {
void *Tcl_Realloc(void *ptr, TCL_HASH_TYPE size)
}
declare 6 {
void *Tcl_DbCkalloc(TCL_HASH_TYPE size, const char *file, int line)
}
declare 7 {
void Tcl_DbCkfree(void *ptr, const char *file, int line)
}
declare 8 {
void *Tcl_DbCkrealloc(void *ptr, TCL_HASH_TYPE size,
const char *file, int line)
}
# Tcl_CreateFileHandler and Tcl_DeleteFileHandler are only available on Unix,
# but they are part of the old generic interface, so we include them here for
# compatibility reasons.
|
| ︙ | ︙ | |||
112 113 114 115 116 117 118 |
Tcl_Obj *Tcl_DbNewDoubleObj(double doubleValue, const char *file,
int line)
}
declare 25 {
Tcl_Obj *Tcl_DbNewListObj(Tcl_Size objc, Tcl_Obj *const *objv,
const char *file, int line)
}
| < < < > > > > > > > > > > > < < < | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
Tcl_Obj *Tcl_DbNewDoubleObj(double doubleValue, const char *file,
int line)
}
declare 25 {
Tcl_Obj *Tcl_DbNewListObj(Tcl_Size objc, Tcl_Obj *const *objv,
const char *file, int line)
}
declare 27 {
Tcl_Obj *Tcl_DbNewObj(const char *file, int line)
}
declare 28 {
Tcl_Obj *Tcl_DbNewStringObj(const char *bytes, Tcl_Size length,
const char *file, int line)
}
declare 29 {
Tcl_Obj *Tcl_DuplicateObj(Tcl_Obj *objPtr)
}
declare 30 {
void TclFreeObj(Tcl_Obj *objPtr)
}
declare 31 {
int Tcl_GetBoolean(Tcl_Interp *interp, const char *src, int *intPtr)
}
declare 32 {
int Tcl_GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
int *intPtr)
}
# Only available in Tcl 8.x, NULL in Tcl 9.0
declare 33 {
unsigned char *Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr, Tcl_Size *numBytesPtr)
}
declare 34 {
int Tcl_GetDouble(Tcl_Interp *interp, const char *src, double *doublePtr)
}
declare 35 {
int Tcl_GetDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
double *doublePtr)
}
declare 37 {
int Tcl_GetInt(Tcl_Interp *interp, const char *src, int *intPtr)
}
declare 38 {
int Tcl_GetIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr)
}
declare 39 {
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 |
int TclListObjLength(Tcl_Interp *interp, Tcl_Obj *listPtr,
void *lengthPtr)
}
declare 48 {
int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size first,
Tcl_Size count, Tcl_Size objc, Tcl_Obj *const objv[])
}
| < < < < < < < | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
int TclListObjLength(Tcl_Interp *interp, Tcl_Obj *listPtr,
void *lengthPtr)
}
declare 48 {
int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size first,
Tcl_Size count, Tcl_Size objc, Tcl_Obj *const objv[])
}
declare 50 {
Tcl_Obj *Tcl_NewByteArrayObj(const unsigned char *bytes, Tcl_Size numBytes)
}
declare 51 {
Tcl_Obj *Tcl_NewDoubleObj(double doubleValue)
}
declare 53 {
Tcl_Obj *Tcl_NewListObj(Tcl_Size objc, Tcl_Obj *const objv[])
}
declare 55 {
Tcl_Obj *Tcl_NewObj(void)
}
declare 56 {
|
| ︙ | ︙ | |||
215 216 217 218 219 220 221 |
}
declare 60 {
void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue)
}
declare 62 {
void Tcl_SetListObj(Tcl_Obj *objPtr, Tcl_Size objc, Tcl_Obj *const objv[])
}
| < < < | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
}
declare 60 {
void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue)
}
declare 62 {
void Tcl_SetListObj(Tcl_Obj *objPtr, Tcl_Size objc, Tcl_Obj *const objv[])
}
declare 64 {
void Tcl_SetObjLength(Tcl_Obj *objPtr, Tcl_Size length)
}
declare 65 {
void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, Tcl_Size length)
}
declare 68 {
|
| ︙ | ︙ | |||
249 250 251 252 253 254 255 |
}
declare 74 {
void Tcl_AsyncMark(Tcl_AsyncHandler async)
}
declare 75 {
int Tcl_AsyncReady(void)
}
| < < < < < < > > > > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
}
declare 74 {
void Tcl_AsyncMark(Tcl_AsyncHandler async)
}
declare 75 {
int Tcl_AsyncReady(void)
}
declare 78 {
int Tcl_BadChannelOption(Tcl_Interp *interp, const char *optionName,
const char *optionList)
}
declare 79 {
void Tcl_CallWhenDeleted(Tcl_Interp *interp, Tcl_InterpDeleteProc *proc,
void *clientData)
}
declare 80 {
void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc, void *clientData)
}
# Only available in Tcl 8.x, NULL in Tcl 9.0
declare 81 {
int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan)
}
declare 82 {
int Tcl_CommandComplete(const char *cmd)
}
declare 83 {
char *Tcl_Concat(Tcl_Size argc, const char *const *argv)
}
declare 84 {
|
| ︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 |
declare 338 {
Tcl_Size Tcl_WriteChars(Tcl_Channel chan, const char *src, Tcl_Size srcLen)
}
declare 339 {
Tcl_Size Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr)
}
declare 340 {
| | < < < < < < < | 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 |
declare 338 {
Tcl_Size Tcl_WriteChars(Tcl_Channel chan, const char *src, Tcl_Size srcLen)
}
declare 339 {
Tcl_Size Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr)
}
declare 340 {
char *Tcl_GetString(Tcl_Obj *objPtr)
}
declare 343 {
void Tcl_AlertNotifier(void *clientData)
}
declare 344 {
void Tcl_ServiceModeHook(int mode)
}
|
| ︙ | ︙ | |||
1143 1144 1145 1146 1147 1148 1149 |
}
# These 4 functions are obsolete, use Tcl_FSGetCwd, Tcl_FSChdir,
# Tcl_FSAccess and Tcl_FSStat
declare 365 {
char *Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr)
}
declare 366 {
| | | | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 |
}
# These 4 functions are obsolete, use Tcl_FSGetCwd, Tcl_FSChdir,
# Tcl_FSAccess and Tcl_FSStat
declare 365 {
char *Tcl_GetCwd(Tcl_Interp *interp, Tcl_DString *cwdPtr)
}
declare 366 {
int Tcl_Chdir(const char *dirName)
}
declare 367 {
int Tcl_Access(const char *path, int mode)
}
declare 368 {
int Tcl_Stat(const char *path, struct stat *bufPtr)
}
declare 369 {
int TclUtfNcmp(const char *s1, const char *s2, size_t n)
}
|
| ︙ | ︙ | |||
1227 1228 1229 1230 1231 1232 1233 |
void Tcl_ConditionFinalize(Tcl_Condition *condPtr)
}
declare 392 {
void Tcl_MutexFinalize(Tcl_Mutex *mutex)
}
declare 393 {
int Tcl_CreateThread(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc,
| | | 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 |
void Tcl_ConditionFinalize(Tcl_Condition *condPtr)
}
declare 392 {
void Tcl_MutexFinalize(Tcl_Mutex *mutex)
}
declare 393 {
int Tcl_CreateThread(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc,
void *clientData, TCL_HASH_TYPE stackSize, int flags)
}
# Introduced in 8.3.2
declare 394 {
Tcl_Size Tcl_ReadRaw(Tcl_Channel chan, char *dst, Tcl_Size bytesToRead)
}
declare 395 {
|
| ︙ | ︙ | |||
1313 1314 1315 1316 1317 1318 1319 |
}
declare 417 {
void Tcl_ClearChannelHandlers(Tcl_Channel channel)
}
declare 418 {
int Tcl_IsChannelExisting(const char *channelName)
}
| < < < < | 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 |
}
declare 417 {
void Tcl_ClearChannelHandlers(Tcl_Channel channel)
}
declare 418 {
int Tcl_IsChannelExisting(const char *channelName)
}
declare 422 {
Tcl_HashEntry *Tcl_CreateHashEntry(Tcl_HashTable *tablePtr,
const void *key, int *newPtr)
}
declare 423 {
void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr, int keyType,
const Tcl_HashKeyType *typePtr)
|
| ︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 |
Tcl_CommandTraceProc *proc, void *clientData)
}
declare 427 {
void Tcl_UntraceCommand(Tcl_Interp *interp, const char *varName,
int flags, Tcl_CommandTraceProc *proc, void *clientData)
}
declare 428 {
| | | | | | 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 |
Tcl_CommandTraceProc *proc, void *clientData)
}
declare 427 {
void Tcl_UntraceCommand(Tcl_Interp *interp, const char *varName,
int flags, Tcl_CommandTraceProc *proc, void *clientData)
}
declare 428 {
void *Tcl_AttemptAlloc(TCL_HASH_TYPE size)
}
declare 429 {
void *Tcl_AttemptDbCkalloc(TCL_HASH_TYPE size, const char *file, int line)
}
declare 430 {
void *Tcl_AttemptRealloc(void *ptr, TCL_HASH_TYPE size)
}
declare 431 {
void *Tcl_AttemptDbCkrealloc(void *ptr, TCL_HASH_TYPE size,
const char *file, int line)
}
declare 432 {
int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, Tcl_Size length)
}
# TIP#10 (thread-aware channels) akupries
|
| ︙ | ︙ | |||
1799 1800 1801 1802 1803 1804 1805 |
}
declare 551 {
int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, Tcl_Command token,
Tcl_Namespace **namespacePtrPtr)
}
# TIP#233 (virtualized time) akupries
| | | | 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 |
}
declare 551 {
int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, Tcl_Command token,
Tcl_Namespace **namespacePtrPtr)
}
# TIP#233 (virtualized time) akupries
declare 552 {
void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
void *clientData)
}
declare 553 {
void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc,
Tcl_ScaleTimeProc **scaleProc,
void **clientData)
}
# TIP#218 (driver thread actions) davygrvy/akupries ChannelType ver 4
declare 554 {
|
| ︙ | ︙ | |||
2114 2115 2116 2117 2118 2119 2120 |
declare 626 {
int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)
}
# TIP #357 (Export TclLoadFile and TclpFindSymbol) kbk
declare 627 {
int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
| | | | | 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 |
declare 626 {
int Tcl_NRSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags)
}
# TIP #357 (Export TclLoadFile and TclpFindSymbol) kbk
declare 627 {
int Tcl_LoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
const char *const symv[], int flags, void *procPtrs,
Tcl_LoadHandle *handlePtr)
}
declare 628 {
void *Tcl_FindSymbol(Tcl_Interp *interp, Tcl_LoadHandle handle,
const char *symbol)
}
declare 629 {
int Tcl_FSUnloadFile(Tcl_Interp *interp, Tcl_LoadHandle handlePtr)
}
# TIP #400
declare 630 {
|
| ︙ | ︙ | |||
2162 2163 2164 2165 2166 2167 2168 |
# TIP #445
declare 636 {
void Tcl_FreeInternalRep(Tcl_Obj *objPtr)
}
declare 637 {
char *Tcl_InitStringRep(Tcl_Obj *objPtr, const char *bytes,
| | | 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 |
# TIP #445
declare 636 {
void Tcl_FreeInternalRep(Tcl_Obj *objPtr)
}
declare 637 {
char *Tcl_InitStringRep(Tcl_Obj *objPtr, const char *bytes,
TCL_HASH_TYPE numBytes)
}
declare 638 {
Tcl_ObjInternalRep *Tcl_FetchInternalRep(Tcl_Obj *objPtr, const Tcl_ObjType *typePtr)
}
declare 639 {
void Tcl_StoreInternalRep(Tcl_Obj *objPtr, const Tcl_ObjType *typePtr,
const Tcl_ObjInternalRep *irPtr)
|
| ︙ | ︙ | |||
2364 2365 2366 2367 2368 2369 2370 |
# TIP #220.
declare 682 {
int Tcl_RemoveChannelMode(Tcl_Interp *interp, Tcl_Channel chan, int mode)
}
# TIP 643
declare 683 {
| | | 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 |
# TIP #220.
declare 682 {
int Tcl_RemoveChannelMode(Tcl_Interp *interp, Tcl_Channel chan, int mode)
}
# TIP 643
declare 683 {
Tcl_Size Tcl_GetEncodingNulLength(Tcl_Encoding encoding)
}
# TIP #650
declare 684 {
int Tcl_GetWideUIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
Tcl_WideUInt *uwidePtr)
}
|
| ︙ | ︙ | |||
2395 2396 2397 2398 2399 2400 2401 |
}
declare 689 {
void Tcl_SetWideUIntObj(Tcl_Obj *objPtr, Tcl_WideUInt uwideValue)
}
# ----- BASELINE -- FOR -- 9.0.0 ----- #
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 |
}
declare 689 {
void Tcl_SetWideUIntObj(Tcl_Obj *objPtr, Tcl_WideUInt uwideValue)
}
# ----- BASELINE -- FOR -- 9.0.0 ----- #
declare 690 {
void TclUnusedStubEntry(void)
}
##############################################################################
# Define the platform specific public Tcl interface. These functions are only
# available on the designated platform.
|
| ︙ | ︙ | |||
2525 2526 2527 2528 2529 2530 2531 |
const char *Tcl_FindExecutable(const char *argv0)
}
export {
const char *Tcl_InitStubs(Tcl_Interp *interp, const char *version,
int exact)
}
export {
| | | 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 |
const char *Tcl_FindExecutable(const char *argv0)
}
export {
const char *Tcl_InitStubs(Tcl_Interp *interp, const char *version,
int exact)
}
export {
const char *TclTomMathInitializeStubs(Tcl_Interp* interp,
const char* version, int epoch, int revision)
}
export {
const char *Tcl_PkgInitStubsCheck(Tcl_Interp *interp, const char *version,
int exact)
}
export {
|
| ︙ | ︙ |
Changes to generic/tcl.h.
1 2 3 4 5 6 | /* * tcl.h -- * * This header file describes the externally-visible facilities of the * Tcl interpreter. * | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* * tcl.h -- * * This header file describes the externally-visible facilities of the * Tcl interpreter. * * Copyright (c) 1987-1994 The Regents of the University of California. * Copyright (c) 1993-1996 Lucent Technologies. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * Copyright (c) 2002 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCL #define _TCL |
| ︙ | ︙ | |||
45 46 47 48 49 50 51 | * win/README (not patchlevel) (sections 0 and 2) * unix/tcl.spec (1 LOC patch) */ #if !defined(TCL_MAJOR_VERSION) # define TCL_MAJOR_VERSION 9 #endif | | < < | | | | | > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | * win/README (not patchlevel) (sections 0 and 2) * unix/tcl.spec (1 LOC patch) */ #if !defined(TCL_MAJOR_VERSION) # define TCL_MAJOR_VERSION 9 #endif #if TCL_MAJOR_VERSION == 9 # define TCL_MINOR_VERSION 0 # define TCL_RELEASE_LEVEL TCL_FINAL_RELEASE # define TCL_RELEASE_SERIAL 5 # define TCL_VERSION "9.0" # define TCL_PATCH_LEVEL "9.0.5" #endif /* TCL_MAJOR_VERSION */ #if defined(RC_INVOKED) /* * Utility macros: STRINGIFY takes an argument and wraps it in "" (double * quotation marks), JOIN joins two arguments. */ |
| ︙ | ︙ | |||
318 319 320 321 322 323 324 | #endif /* !TCL_T_MODIFIER */ #define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val))) #define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val))) #define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val))) #define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val))) | > > > > > > > > | | | > > | > > > > > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
#endif /* !TCL_T_MODIFIER */
#define Tcl_WideAsLong(val) ((long)((Tcl_WideInt)(val)))
#define Tcl_LongAsWide(val) ((Tcl_WideInt)((long)(val)))
#define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val)))
#define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val)))
#if TCL_MAJOR_VERSION < 9
# ifndef Tcl_Size
# define Tcl_Size int
# define Tcl_ObjCmdProc2 Tcl_ObjCmdProc
# define Tcl_CmdObjTraceProc2 Tcl_CmdObjTraceProc
# define _TCLSIZEHANDLED
# endif
#else
typedef ptrdiff_t Tcl_Size;
# define TCL_SIZE_MAX ((Tcl_Size)(((size_t)-1)>>1))
# define TCL_SIZE_MODIFIER TCL_T_MODIFIER
#endif /* TCL_MAJOR_VERSION */
#ifdef _WIN32
# if TCL_MAJOR_VERSION > 8 || defined(_WIN64) || defined(_USE_64BIT_TIME_T)
typedef struct __stat64 Tcl_StatBuf;
# elif defined(_USE_32BIT_TIME_T)
typedef struct _stati64 Tcl_StatBuf;
# else
typedef struct _stat32i64 Tcl_StatBuf;
# endif
#elif defined(__CYGWIN__)
typedef struct {
unsigned st_dev;
unsigned short st_ino;
unsigned short st_mode;
short st_nlink;
short st_uid;
|
| ︙ | ︙ | |||
404 405 406 407 408 409 410 | #endif /* * Definition of values for default stacksize and the possible flags to be * given to Tcl_CreateThread. */ | | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | #endif /* * Definition of values for default stacksize and the possible flags to be * given to Tcl_CreateThread. */ #define TCL_THREAD_STACK_DEFAULT (0) /* Use default size for stack. */ #define TCL_THREAD_NOFLAGS (0000) /* Standard flags, default * behaviour. */ #define TCL_THREAD_JOINABLE (0001) /* Mark the thread as joinable. */ /* * Flag values passed to Tcl_StringCaseMatch. */ |
| ︙ | ︙ | |||
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 |
/*
* Structures filled in by Tcl_RegExpInfo. Note that all offset values are
* relative to the start of the match string, not the beginning of the entire
* string.
*/
typedef struct Tcl_RegExpIndices {
Tcl_Size start; /* Character offset of first character in
* match. */
Tcl_Size end; /* Character offset of first character after
* the match. */
} Tcl_RegExpIndices;
typedef struct Tcl_RegExpInfo {
Tcl_Size nsubs; /* Number of subexpressions in the compiled
* expression. */
Tcl_RegExpIndices *matches; /* Array of nsubs match offset pairs. */
Tcl_Size extendStart; /* The offset at which a subsequent match
* might begin. */
} Tcl_RegExpInfo;
/*
* Picky compilers complain if this typdef doesn't appear before the struct's
* reference in tclDecls.h.
*/
| > > > > > > > > > > | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
/*
* Structures filled in by Tcl_RegExpInfo. Note that all offset values are
* relative to the start of the match string, not the beginning of the entire
* string.
*/
typedef struct Tcl_RegExpIndices {
#if TCL_MAJOR_VERSION > 8
Tcl_Size start; /* Character offset of first character in
* match. */
Tcl_Size end; /* Character offset of first character after
* the match. */
#else
long start;
long end;
#endif
} Tcl_RegExpIndices;
typedef struct Tcl_RegExpInfo {
Tcl_Size nsubs; /* Number of subexpressions in the compiled
* expression. */
Tcl_RegExpIndices *matches; /* Array of nsubs match offset pairs. */
#if TCL_MAJOR_VERSION > 8
Tcl_Size extendStart; /* The offset at which a subsequent match
* might begin. */
#else
long extendStart;
long reserved; /* Reserved for later use. */
#endif
} Tcl_RegExpInfo;
/*
* Picky compilers complain if this typdef doesn't appear before the struct's
* reference in tclDecls.h.
*/
|
| ︙ | ︙ | |||
499 500 501 502 503 504 505 | #define TCL_OK 0 #define TCL_ERROR 1 #define TCL_RETURN 2 #define TCL_BREAK 3 #define TCL_CONTINUE 4 #define TCL_CODE_USER_MIN 5 | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | #define TCL_OK 0 #define TCL_ERROR 1 #define TCL_RETURN 2 #define TCL_BREAK 3 #define TCL_CONTINUE 4 #define TCL_CODE_USER_MIN 5 #define TCL_CODE_USER_MAX 0x3fffffff /* 1073741823 */ /* *---------------------------------------------------------------------------- * Flags to control what substitutions are performed by Tcl_SubstObj(): */ #define TCL_SUBST_COMMANDS 001 |
| ︙ | ︙ | |||
530 531 532 533 534 535 536 | typedef int (Tcl_AppInitProc) (Tcl_Interp *interp); typedef int (Tcl_AsyncProc) (void *clientData, Tcl_Interp *interp, int code); typedef void (Tcl_ChannelProc) (void *clientData, int mask); typedef void (Tcl_CloseProc) (void *data); typedef void (Tcl_CmdDeleteProc) (void *clientData); typedef int (Tcl_CmdProc) (void *clientData, Tcl_Interp *interp, | | < | < < | > > > < > | | > | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | typedef int (Tcl_AppInitProc) (Tcl_Interp *interp); typedef int (Tcl_AsyncProc) (void *clientData, Tcl_Interp *interp, int code); typedef void (Tcl_ChannelProc) (void *clientData, int mask); typedef void (Tcl_CloseProc) (void *data); typedef void (Tcl_CmdDeleteProc) (void *clientData); typedef int (Tcl_CmdProc) (void *clientData, Tcl_Interp *interp, int argc, const char *argv[]); typedef void (Tcl_CmdTraceProc) (void *clientData, Tcl_Interp *interp, int level, char *command, Tcl_CmdProc *proc, void *cmdClientData, int argc, const char *argv[]); typedef int (Tcl_CmdObjTraceProc) (void *clientData, Tcl_Interp *interp, int level, const char *command, Tcl_Command commandInfo, int objc, struct Tcl_Obj *const *objv); typedef void (Tcl_CmdObjTraceDeleteProc) (void *clientData); typedef void (Tcl_DupInternalRepProc) (struct Tcl_Obj *srcPtr, struct Tcl_Obj *dupPtr); typedef int (Tcl_EncodingConvertProc) (void *clientData, const char *src, int srcLen, int flags, Tcl_EncodingState *statePtr, char *dst, int dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr); typedef void (Tcl_EncodingFreeProc) (void *clientData); typedef int (Tcl_EventProc) (Tcl_Event *evPtr, int flags); typedef void (Tcl_EventCheckProc) (void *clientData, int flags); typedef int (Tcl_EventDeleteProc) (Tcl_Event *evPtr, void *clientData); typedef void (Tcl_EventSetupProc) (void *clientData, int flags); typedef void (Tcl_ExitProc) (void *clientData); typedef void (Tcl_FileProc) (void *clientData, int mask); typedef void (Tcl_FileFreeProc) (void *clientData); typedef void (Tcl_FreeInternalRepProc) (struct Tcl_Obj *objPtr); typedef void (Tcl_IdleProc) (void *clientData); typedef void (Tcl_InterpDeleteProc) (void *clientData, Tcl_Interp *interp); typedef void (Tcl_NamespaceDeleteProc) (void *clientData); typedef int (Tcl_ObjCmdProc) (void *clientData, Tcl_Interp *interp, int objc, struct Tcl_Obj *const *objv); #if TCL_MAJOR_VERSION > 8 typedef int (Tcl_ObjCmdProc2) (void *clientData, Tcl_Interp *interp, Tcl_Size objc, struct Tcl_Obj *const *objv); typedef int (Tcl_CmdObjTraceProc2) (void *clientData, Tcl_Interp *interp, Tcl_Size level, const char *command, Tcl_Command commandInfo, Tcl_Size objc, struct Tcl_Obj *const *objv); typedef void (Tcl_FreeProc) (void *blockPtr); #define Tcl_ExitProc Tcl_FreeProc #define Tcl_FileFreeProc Tcl_FreeProc #define Tcl_FileFreeProc Tcl_FreeProc #define Tcl_EncodingFreeProc Tcl_FreeProc #else typedef void (Tcl_FreeProc) (char *blockPtr); #endif typedef int (Tcl_LibraryInitProc) (Tcl_Interp *interp); typedef int (Tcl_LibraryUnloadProc) (Tcl_Interp *interp, int flags); typedef void (Tcl_PanicProc) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); typedef void (Tcl_TcpAcceptProc) (void *callbackData, Tcl_Channel chan, char *address, int port); typedef void (Tcl_TimerProc) (void *clientData); typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr); typedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr); typedef char * (Tcl_VarTraceProc) (void *clientData, Tcl_Interp *interp, const char *part1, const char *part2, int flags); typedef void (Tcl_CommandTraceProc) (void *clientData, Tcl_Interp *interp, const char *oldName, const char *newName, int flags); typedef void (Tcl_CreateFileHandlerProc) (int fd, int mask, Tcl_FileProc *proc, void *clientData); typedef void (Tcl_DeleteFileHandlerProc) (int fd); typedef void (Tcl_AlertNotifierProc) (void *clientData); typedef void (Tcl_ServiceModeHookProc) (int mode); typedef void *(Tcl_InitNotifierProc) (void); typedef void (Tcl_FinalizeNotifierProc) (void *clientData); typedef void (Tcl_MainLoopProc) (void); /* Abstract List functions */ #if TCL_MAJOR_VERSION > 8 typedef Tcl_Size (Tcl_ObjTypeLengthProc) (struct Tcl_Obj *listPtr); typedef int (Tcl_ObjTypeIndexProc) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, Tcl_Size index, struct Tcl_Obj** elemObj); typedef int (Tcl_ObjTypeSliceProc) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, Tcl_Size fromIdx, Tcl_Size toIdx, struct Tcl_Obj **newObjPtr); typedef int (Tcl_ObjTypeReverseProc) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, struct Tcl_Obj **newObjPtr); typedef int (Tcl_ObjTypeGetElements) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, Tcl_Size *objcptr, struct Tcl_Obj ***objvptr); typedef struct Tcl_Obj *(Tcl_ObjTypeSetElement) (Tcl_Interp *interp, struct Tcl_Obj *listPtr, Tcl_Size indexCount, struct Tcl_Obj *const indexArray[], struct Tcl_Obj *valueObj); typedef int (Tcl_ObjTypeReplaceProc) (Tcl_Interp *interp, struct Tcl_Obj *listObj, Tcl_Size first, Tcl_Size numToDelete, Tcl_Size numToInsert, struct Tcl_Obj *const insertObjs[]); typedef int (Tcl_ObjTypeInOperatorProc) (Tcl_Interp *interp, struct Tcl_Obj *valueObj, struct Tcl_Obj *listObj, int *boolResult); #endif #ifndef TCL_NO_DEPRECATED # define Tcl_PackageInitProc Tcl_LibraryInitProc # define Tcl_PackageUnloadProc Tcl_LibraryUnloadProc #endif /* |
| ︙ | ︙ | |||
641 642 643 644 645 646 647 648 649 650 651 652 653 654 |
Tcl_UpdateStringProc *updateStringProc;
/* Called to update the string rep from the
* type's internal representation. */
Tcl_SetFromAnyProc *setFromAnyProc;
/* Called to convert the object's internal rep
* to this type. Frees the internal rep of the
* old type. Returns TCL_ERROR on failure. */
size_t version; /* Version field for future-proofing. */
/* List emulation functions - ObjType Version 1 */
Tcl_ObjTypeLengthProc *lengthProc;
/* Return the [llength] of the AbstractList */
Tcl_ObjTypeIndexProc *indexProc;
/* Return a value (Tcl_Obj) at a given index */
| > | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
Tcl_UpdateStringProc *updateStringProc;
/* Called to update the string rep from the
* type's internal representation. */
Tcl_SetFromAnyProc *setFromAnyProc;
/* Called to convert the object's internal rep
* to this type. Frees the internal rep of the
* old type. Returns TCL_ERROR on failure. */
#if TCL_MAJOR_VERSION > 8
size_t version; /* Version field for future-proofing. */
/* List emulation functions - ObjType Version 1 */
Tcl_ObjTypeLengthProc *lengthProc;
/* Return the [llength] of the AbstractList */
Tcl_ObjTypeIndexProc *indexProc;
/* Return a value (Tcl_Obj) at a given index */
|
| ︙ | ︙ | |||
664 665 666 667 668 669 670 671 672 |
* given valueObj. */
Tcl_ObjTypeReplaceProc *replaceProc;
/* Replace sublist with another sublist */
Tcl_ObjTypeInOperatorProc *inOperProc;
/* "in" and "ni" expr list operation.
* Determine if the given string value matches
* an element in the list. */
} Tcl_ObjType;
| > > | | | | | | > | > > | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 |
* given valueObj. */
Tcl_ObjTypeReplaceProc *replaceProc;
/* Replace sublist with another sublist */
Tcl_ObjTypeInOperatorProc *inOperProc;
/* "in" and "ni" expr list operation.
* Determine if the given string value matches
* an element in the list. */
#endif
} Tcl_ObjType;
#if TCL_MAJOR_VERSION > 8
# define TCL_OBJTYPE_V0 0, \
0,0,0,0,0,0,0,0 /* Pre-Tcl 9 */
# define TCL_OBJTYPE_V1(a) offsetof(Tcl_ObjType, indexProc), \
a,0,0,0,0,0,0,0 /* Tcl 9 Version 1 */
# define TCL_OBJTYPE_V2(a,b,c,d,e,f,g,h) sizeof(Tcl_ObjType), \
a,b,c,d,e,f,g,h /* Tcl 9 - AbstractLists */
#endif
/*
* The following structure stores an internal representation (internalrep) for
* a Tcl value. An internalrep is associated with an Tcl_ObjType when both
* are stored in the same Tcl_Obj. The routines of the Tcl_ObjType govern
* the handling of the internalrep.
*/
typedef union Tcl_ObjInternalRep { /* The internal representation: */
long longValue; /* - an long integer value. */
double doubleValue; /* - a double-precision floating value. */
void *otherValuePtr; /* - another, type-specific value, */
/* not used internally any more. */
Tcl_WideInt wideValue; /* - an integer value >= 64bits */
struct { /* - internal rep as two pointers. */
void *ptr1;
void *ptr2;
} twoPtrValue;
struct { /* - internal rep as a pointer and a long, */
void *ptr; /* not used internally any more. */
unsigned long value;
} ptrAndLongRep;
#if TCL_MAJOR_VERSION > 8
struct { /* - use for pointer and length reps */
void *ptr;
Tcl_Size size;
} ptrAndSize;
#endif
} Tcl_ObjInternalRep;
/*
* One of the following structures exists for each object in the Tcl system.
* An object stores a value as either a string, some internal representation,
* or both.
*/
|
| ︙ | ︙ | |||
814 815 816 817 818 819 820 |
*/
typedef struct {
int isNativeObjectProc; /* 1 if objProc was registered by a call to
* Tcl_CreateObjCommand; 2 if objProc was registered by
* a call to Tcl_CreateObjCommand2; 0 otherwise.
* Tcl_SetCmdInfo does not modify this field. */
| < < < < < > > | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 |
*/
typedef struct {
int isNativeObjectProc; /* 1 if objProc was registered by a call to
* Tcl_CreateObjCommand; 2 if objProc was registered by
* a call to Tcl_CreateObjCommand2; 0 otherwise.
* Tcl_SetCmdInfo does not modify this field. */
Tcl_ObjCmdProc *objProc; /* Command's object-based function. */
void *objClientData; /* ClientData for object proc. */
Tcl_CmdProc *proc; /* Command's string-based function. */
void *clientData; /* ClientData for string proc. */
Tcl_CmdDeleteProc *deleteProc;
/* Function to call when command is
* deleted. */
void *deleteData; /* Value to pass to deleteProc (usually the
* same as clientData). */
Tcl_Namespace *namespacePtr;/* Points to the namespace that contains this
* command. Note that Tcl_SetCmdInfo will not
* change a command's namespace; use
* TclRenameCommand or Tcl_Eval (of 'rename')
* to do that. */
#if TCL_MAJOR_VERSION > 8
Tcl_ObjCmdProc2 *objProc2; /* Command's object2-based function. */
void *objClientData2; /* ClientData for object2 proc. */
#endif
} Tcl_CmdInfo;
/*
*----------------------------------------------------------------------------
* The structure defined below is used to hold dynamic strings. The only
* fields that clients should use are string and length, accessible via the
* macros Tcl_DStringValue and Tcl_DStringLength.
|
| ︙ | ︙ | |||
886 887 888 889 890 891 892 | * Type values returned by Tcl_GetNumberFromObj * TCL_NUMBER_INT Representation is a Tcl_WideInt * TCL_NUMBER_BIG Representation is an mp_int * TCL_NUMBER_DOUBLE Representation is a double * TCL_NUMBER_NAN Value is NaN. */ | | | | | | 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 | * Type values returned by Tcl_GetNumberFromObj * TCL_NUMBER_INT Representation is a Tcl_WideInt * TCL_NUMBER_BIG Representation is an mp_int * TCL_NUMBER_DOUBLE Representation is a double * TCL_NUMBER_NAN Value is NaN. */ #define TCL_NUMBER_INT 2 #define TCL_NUMBER_BIG 3 #define TCL_NUMBER_DOUBLE 4 #define TCL_NUMBER_NAN 5 /* * Flag values passed to Tcl_ConvertElement. * TCL_DONT_USE_BRACES forces it not to enclose the element in braces, but to * use backslash quoting instead. * TCL_DONT_QUOTE_HASH disables the default quoting of the '#' character. It * is safe to leave the hash unquoted when the element is not the first |
| ︙ | ︙ | |||
922 923 924 925 926 927 928 | #define TCL_INDEX_TEMP_TABLE 64 /* * Flags that may be passed to Tcl_UniCharToUtf. * TCL_COMBINE Combine surrogates */ | > | > > > | 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 | #define TCL_INDEX_TEMP_TABLE 64 /* * Flags that may be passed to Tcl_UniCharToUtf. * TCL_COMBINE Combine surrogates */ #if TCL_MAJOR_VERSION > 8 # define TCL_COMBINE 0x1000000 #else # define TCL_COMBINE 0 #endif /* *---------------------------------------------------------------------------- * Flag values passed to Tcl_RecordAndEval, Tcl_EvalObj, Tcl_EvalObjv. * WARNING: these bit choices must not conflict with the bit choices for * evalFlag bits in tclInt.h! * * Meanings: |
| ︙ | ︙ | |||
950 951 952 953 954 955 956 | */ #define TCL_NO_EVAL 0x010000 #define TCL_EVAL_GLOBAL 0x020000 #define TCL_EVAL_DIRECT 0x040000 #define TCL_EVAL_INVOKE 0x080000 #define TCL_CANCEL_UNWIND 0x100000 | | | 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 | */ #define TCL_NO_EVAL 0x010000 #define TCL_EVAL_GLOBAL 0x020000 #define TCL_EVAL_DIRECT 0x040000 #define TCL_EVAL_INVOKE 0x080000 #define TCL_CANCEL_UNWIND 0x100000 #define TCL_EVAL_NOERR 0x200000 /* * Special freeProc values that may be passed to Tcl_SetResult (see the man * page for details): */ #define TCL_VOLATILE ((Tcl_FreeProc *) 1) |
| ︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | #define TCL_LINK_READ_ONLY 0x80 /* *---------------------------------------------------------------------------- * Forward declarations of Tcl_HashTable and related types. */ | | > | > > > | | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 | #define TCL_LINK_READ_ONLY 0x80 /* *---------------------------------------------------------------------------- * Forward declarations of Tcl_HashTable and related types. */ #ifndef TCL_HASH_TYPE #if TCL_MAJOR_VERSION > 8 # define TCL_HASH_TYPE size_t #else # define TCL_HASH_TYPE unsigned #endif #endif typedef struct Tcl_HashKeyType Tcl_HashKeyType; typedef struct Tcl_HashTable Tcl_HashTable; typedef struct Tcl_HashEntry Tcl_HashEntry; typedef TCL_HASH_TYPE (Tcl_HashKeyProc) (Tcl_HashTable *tablePtr, void *keyPtr); typedef int (Tcl_CompareHashKeysProc) (void *keyPtr, Tcl_HashEntry *hPtr); typedef Tcl_HashEntry * (Tcl_AllocHashEntryProc) (Tcl_HashTable *tablePtr, void *keyPtr); typedef void (Tcl_FreeHashEntryProc) (Tcl_HashEntry *hPtr); /* * Structure definition for an entry in a hash table. No-one outside Tcl |
| ︙ | ︙ | |||
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 |
* avoid mallocs and frees). */
Tcl_Size numBuckets; /* Total number of buckets allocated at
* **bucketPtr. */
Tcl_Size numEntries; /* Total number of entries present in
* table. */
Tcl_Size rebuildSize; /* Enlarge table when numEntries gets to be
* this large. */
size_t mask; /* Mask value used in hashing function. */
int downShift; /* Shift count used in hashing function.
* Designed to use high-order bits of
* randomized keys. */
int keyType; /* Type of keys used in this table. It's
* either TCL_CUSTOM_KEYS, TCL_STRING_KEYS,
* TCL_ONE_WORD_KEYS, or an integer giving the
* number of ints that is the size of the
* key. */
| > > > > > < < < < | 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 |
* avoid mallocs and frees). */
Tcl_Size numBuckets; /* Total number of buckets allocated at
* **bucketPtr. */
Tcl_Size numEntries; /* Total number of entries present in
* table. */
Tcl_Size rebuildSize; /* Enlarge table when numEntries gets to be
* this large. */
#if TCL_MAJOR_VERSION > 8
size_t mask; /* Mask value used in hashing function. */
#endif
int downShift; /* Shift count used in hashing function.
* Designed to use high-order bits of
* randomized keys. */
#if TCL_MAJOR_VERSION < 9
int mask; /* Mask value used in hashing function. */
#endif
int keyType; /* Type of keys used in this table. It's
* either TCL_CUSTOM_KEYS, TCL_STRING_KEYS,
* TCL_ONE_WORD_KEYS, or an integer giving the
* number of ints that is the size of the
* key. */
Tcl_HashEntry *(*findProc) (Tcl_HashTable *tablePtr, const char *key);
Tcl_HashEntry *(*createProc) (Tcl_HashTable *tablePtr, const char *key,
int *newPtr);
const Tcl_HashKeyType *typePtr;
/* Type of the keys used in the
* Tcl_HashTable. */
};
|
| ︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 |
* dictionaries. These fields should not be accessed by code outside
* tclDictObj.c
*/
typedef struct {
void *next; /* Search position for underlying hash
* table. */
| | | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 |
* dictionaries. These fields should not be accessed by code outside
* tclDictObj.c
*/
typedef struct {
void *next; /* Search position for underlying hash
* table. */
TCL_HASH_TYPE epoch; /* Epoch marker for dictionary being searched,
* or 0 if search has terminated. */
Tcl_Dict dictionaryPtr; /* Reference to dictionary being searched. */
} Tcl_DictSearch;
/*
*----------------------------------------------------------------------------
* Flag values to pass to Tcl_DoOneEvent to disable searches for some kinds of
|
| ︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 1284 |
/*
* The following structure keeps is used to hold a time value, either as an
* absolute time (the number of seconds from the epoch) or as an elapsed time.
* On Unix systems the epoch is Midnight Jan 1, 1970 GMT.
*/
typedef struct Tcl_Time {
long long sec; /* Seconds. */
| > > > > | < < < < < < < < < | 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 |
/*
* The following structure keeps is used to hold a time value, either as an
* absolute time (the number of seconds from the epoch) or as an elapsed time.
* On Unix systems the epoch is Midnight Jan 1, 1970 GMT.
*/
typedef struct Tcl_Time {
#if TCL_MAJOR_VERSION > 8
long long sec; /* Seconds. */
#else
long sec; /* Seconds. */
#endif
#if defined(_CYGWIN_) && TCL_MAJOR_VERSION > 8
int usec; /* Microseconds. */
#else
long usec; /* Microseconds. */
#endif
} Tcl_Time;
typedef void (Tcl_SetTimerProc) (const Tcl_Time *timePtr);
typedef int (Tcl_WaitForEventProc) (const Tcl_Time *timePtr);
/*
* TIP #233 (Virtualized Time)
*/
typedef void (Tcl_GetTimeProc) (Tcl_Time *timebuf, void *clientData);
typedef void (Tcl_ScaleTimeProc) (Tcl_Time *timebuf, void *clientData);
/*
*----------------------------------------------------------------------------
* Bits to pass to Tcl_CreateFileHandler and Tcl_CreateChannelHandler to
* indicate what sorts of events are of interest:
*/
|
| ︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 | #define TCL_CLOSE_WRITE (1<<2) /* * Value to use as the closeProc for a channel that supports the close2Proc * interface. */ | > | > > > | 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 | #define TCL_CLOSE_WRITE (1<<2) /* * Value to use as the closeProc for a channel that supports the close2Proc * interface. */ #if TCL_MAJOR_VERSION > 8 # define TCL_CLOSE2PROC NULL #else # define TCL_CLOSE2PROC ((void *) 1) #endif /* * Channel version tag. This was introduced in 8.3.2/8.4. */ #define TCL_CHANNEL_VERSION_5 ((Tcl_ChannelTypeVersion) 0x5) |
| ︙ | ︙ | |||
1636 1637 1638 1639 1640 1641 1642 |
/* Called by 'Tcl_FSOpenFileChannel()'.
* Provided by any reasonable filesystem. */
Tcl_FSMatchInDirectoryProc *matchInDirectoryProc;
/* Called by 'Tcl_FSMatchInDirectory()'. NULL
* if the filesystem does not support glob or
* recursive copy. */
Tcl_FSUtimeProc *utimeProc; /* Called by 'Tcl_FSUtime()', by 'file
| | | | | | 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 |
/* Called by 'Tcl_FSOpenFileChannel()'.
* Provided by any reasonable filesystem. */
Tcl_FSMatchInDirectoryProc *matchInDirectoryProc;
/* Called by 'Tcl_FSMatchInDirectory()'. NULL
* if the filesystem does not support glob or
* recursive copy. */
Tcl_FSUtimeProc *utimeProc; /* Called by 'Tcl_FSUtime()', by 'file
* mtime' to set (not read) times, 'file
* atime', and the open-r/open-w/fcopy variant
* of 'file copy'. */
Tcl_FSLinkProc *linkProc; /* Called by 'Tcl_FSLink()'. NULL if reading or
* creating links is not supported. */
Tcl_FSListVolumesProc *listVolumesProc;
/* Lists filesystem volumes added by this
* filesystem. NULL if the filesystem does not
* use volumes. */
Tcl_FSFileAttrStringsProc *fileAttrStringsProc;
/* List all valid attributes strings. NULL if
* the filesystem does not support the 'file
|
| ︙ | ︙ | |||
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 |
* malloc-ed space if command exceeds space in
* staticTokens. */
Tcl_Size numTokens; /* Total number of tokens in command. */
Tcl_Size tokensAvailable; /* Total number of tokens available at
* *tokenPtr. */
int errorType; /* One of the parsing error types defined
* above. */
int incomplete; /* This field is set to 1 by Tcl_ParseCommand
* if the command appears to be incomplete.
* This information is used by
* Tcl_CommandComplete. */
/*
* The fields below are intended only for the private use of the parser.
* They should not be used by functions that invoke Tcl_ParseCommand.
*/
const char *string; /* The original command string passed to
* Tcl_ParseCommand. */
const char *end; /* Points to the character just after the last
* one in the command string. */
Tcl_Interp *interp; /* Interpreter to use for error reporting, or
* NULL. */
const char *term; /* Points to character in string that
* terminated most recent token. Filled in by
* ParseTokens. If an error occurs, points to
* beginning of region where the error
* occurred (e.g. the open brace if the close
* brace is missing). */
Tcl_Token staticTokens[NUM_STATIC_TOKENS];
/* Initial space for tokens for command. This
* space should be large enough to accommodate
* most commands; dynamic space is allocated
* for very large commands that don't fit
* here. */
} Tcl_Parse;
| > > > > > | 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 |
* malloc-ed space if command exceeds space in
* staticTokens. */
Tcl_Size numTokens; /* Total number of tokens in command. */
Tcl_Size tokensAvailable; /* Total number of tokens available at
* *tokenPtr. */
int errorType; /* One of the parsing error types defined
* above. */
#if TCL_MAJOR_VERSION > 8
int incomplete; /* This field is set to 1 by Tcl_ParseCommand
* if the command appears to be incomplete.
* This information is used by
* Tcl_CommandComplete. */
#endif
/*
* The fields below are intended only for the private use of the parser.
* They should not be used by functions that invoke Tcl_ParseCommand.
*/
const char *string; /* The original command string passed to
* Tcl_ParseCommand. */
const char *end; /* Points to the character just after the last
* one in the command string. */
Tcl_Interp *interp; /* Interpreter to use for error reporting, or
* NULL. */
const char *term; /* Points to character in string that
* terminated most recent token. Filled in by
* ParseTokens. If an error occurs, points to
* beginning of region where the error
* occurred (e.g. the open brace if the close
* brace is missing). */
#if TCL_MAJOR_VERSION < 9
int incomplete;
#endif
Tcl_Token staticTokens[NUM_STATIC_TOKENS];
/* Initial space for tokens for command. This
* space should be large enough to accommodate
* most commands; dynamic space is allocated
* for very large commands that don't fit
* here. */
} Tcl_Parse;
|
| ︙ | ︙ | |||
1988 1989 1990 1991 1992 1993 1994 | * NOTE: THESE BIT DEFINITIONS SHOULD NOT OVERLAP WITH INTERNAL USE BITS * DEFINED IN tclEncoding.c (ENCODING_INPUT et al). Be cognizant of this * when adding bits. */ #define TCL_ENCODING_START 0x01 #define TCL_ENCODING_END 0x02 | > | > > > | | 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 | * NOTE: THESE BIT DEFINITIONS SHOULD NOT OVERLAP WITH INTERNAL USE BITS * DEFINED IN tclEncoding.c (ENCODING_INPUT et al). Be cognizant of this * when adding bits. */ #define TCL_ENCODING_START 0x01 #define TCL_ENCODING_END 0x02 #if TCL_MAJOR_VERSION > 8 # define TCL_ENCODING_STOPONERROR 0x0 /* Not used any more */ #else # define TCL_ENCODING_STOPONERROR 0x04 #endif #define TCL_ENCODING_NO_TERMINATE 0x08 #define TCL_ENCODING_CHAR_LIMIT 0x10 /* Internal use bits, do not define bits in this space. See above comment */ #define TCL_ENCODING_INTERNAL_USE_MASK 0xFF00 /* * Reserve top byte for profile values (disjoint, not a mask). In case of * changes, ensure ENCODING_PROFILE_* macros in tclInt.h are modified if * necessary. */ #define TCL_ENCODING_PROFILE_STRICT TCL_ENCODING_STOPONERROR #define TCL_ENCODING_PROFILE_TCL8 0x01000000 #define TCL_ENCODING_PROFILE_REPLACE 0x02000000 /* * The following definitions are the error codes returned by the conversion * routines: * |
| ︙ | ︙ | |||
2041 2042 2043 2044 2045 2046 2047 | * Unicode character in UTF-8. The valid values are 3 and 4. If > 3, * then Tcl_UniChar must be 4-bytes in size (UCS-4) (the default). If == 3, * then Tcl_UniChar must be 2-bytes in size (UTF-16). Since Tcl 9.0, UCS-4 * mode is the default and recommended mode. */ #ifndef TCL_UTF_MAX | > | > > > | < < < < < < < | 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 |
* Unicode character in UTF-8. The valid values are 3 and 4. If > 3,
* then Tcl_UniChar must be 4-bytes in size (UCS-4) (the default). If == 3,
* then Tcl_UniChar must be 2-bytes in size (UTF-16). Since Tcl 9.0, UCS-4
* mode is the default and recommended mode.
*/
#ifndef TCL_UTF_MAX
# if defined(BUILD_tcl) || TCL_MAJOR_VERSION > 8
# define TCL_UTF_MAX 4
# else
# define TCL_UTF_MAX 3
# endif
#endif
/*
* This represents a Unicode character. Any changes to this should also be
* reflected in regcustom.h.
*/
#if TCL_UTF_MAX == 4 && TCL_MAJOR_VERSION > 8
/*
* int isn't 100% accurate as it should be a strict 4-byte value
* (perhaps int32_t). ILP64/SILP64 systems may have troubles. The
* size of this value must be reflected correctly in regcustom.h.
*/
typedef int Tcl_UniChar;
#elif TCL_UTF_MAX == 3 && !defined(BUILD_tcl)
typedef unsigned short Tcl_UniChar;
#else
# error "This TCL_UTF_MAX value is not supported"
#endif
/*
*----------------------------------------------------------------------------
* TIP #59: The following structure is used in calls 'Tcl_RegisterConfig' to
* provide the system with the embedded configuration data.
*/
|
| ︙ | ︙ | |||
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 | /* * Structure containing information about a limit handler to be called when a * command- or time-limit is exceeded by an interpreter. */ typedef void (Tcl_LimitHandlerProc) (void *clientData, Tcl_Interp *interp); #define Tcl_LimitHandlerDeleteProc Tcl_FreeProc #if 0 /* *---------------------------------------------------------------------------- * We would like to provide an anonymous structure "mp_int" here, which is * compatible with libtommath's "mp_int", but without duplicating anything * from <tommath.h> or including <tommath.h> here. But the libtommath project | > > > > | 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 | /* * Structure containing information about a limit handler to be called when a * command- or time-limit is exceeded by an interpreter. */ typedef void (Tcl_LimitHandlerProc) (void *clientData, Tcl_Interp *interp); #if TCL_MAJOR_VERSION > 8 #define Tcl_LimitHandlerDeleteProc Tcl_FreeProc #else typedef void (Tcl_LimitHandlerDeleteProc) (void *clientData); #endif #if 0 /* *---------------------------------------------------------------------------- * We would like to provide an anonymous structure "mp_int" here, which is * compatible with libtommath's "mp_int", but without duplicating anything * from <tommath.h> or including <tommath.h> here. But the libtommath project |
| ︙ | ︙ | |||
2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 | #define TCL_TCPSERVER_REUSEADDR (1<<0) #define TCL_TCPSERVER_REUSEPORT (1<<1) /* * Constants for special Tcl_Size-typed values, see TIP #494 */ #define TCL_IO_FAILURE ((Tcl_Size)-1) #define TCL_AUTO_LENGTH ((Tcl_Size)-1) #define TCL_INDEX_NONE ((Tcl_Size)-1) /* *---------------------------------------------------------------------------- * Single public declaration for NRE. */ | > > | > > | > > > | 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 | #define TCL_TCPSERVER_REUSEADDR (1<<0) #define TCL_TCPSERVER_REUSEPORT (1<<1) /* * Constants for special Tcl_Size-typed values, see TIP #494 */ #if TCL_MAJOR_VERSION > 8 #define TCL_IO_FAILURE ((Tcl_Size)-1) #define TCL_AUTO_LENGTH ((Tcl_Size)-1) #define TCL_INDEX_NONE ((Tcl_Size)-1) #endif /* *---------------------------------------------------------------------------- * Single public declaration for NRE. */ typedef int (Tcl_NRPostProc) (void *data[], Tcl_Interp *interp, int result); /* *---------------------------------------------------------------------------- * The following constant is used to test for older versions of Tcl in the * stubs tables. */ #if TCL_MAJOR_VERSION > 8 # define TCL_STUB_MAGIC ((int) 0xFCA3BACB + (int) sizeof(void *)) #else # define TCL_STUB_MAGIC ((int) 0xFCA3BACF) #endif /* * The following function is required to be defined in all stubs aware * extensions. The function is actually implemented in the stub library, not * the main Tcl library, although there is a trivial implementation in the * main library in case an extension is statically linked into an application. */ |
| ︙ | ︙ | |||
2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 |
#if defined(_WIN32)
TCL_NORETURN void Tcl_ConsolePanic(const char *format, ...);
#else
# define Tcl_ConsolePanic ((Tcl_PanicProc *)NULL)
#endif
#ifdef USE_TCL_STUBS
# define Tcl_InitStubs(interp, version, exact) \
(Tcl_InitStubs)(interp, version, \
(exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16), \
TCL_STUB_MAGIC)
#else
# define Tcl_InitStubs(interp, version, exact) \
Tcl_PkgInitStubsCheck(interp, version, \
(exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16))
#endif
/*
* Public functions that are not accessible via the stubs table.
* Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171]
*/
| > > > > > > > > > > > > > | 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 |
#if defined(_WIN32)
TCL_NORETURN void Tcl_ConsolePanic(const char *format, ...);
#else
# define Tcl_ConsolePanic ((Tcl_PanicProc *)NULL)
#endif
#ifdef USE_TCL_STUBS
#if TCL_MAJOR_VERSION < 9
# define Tcl_InitStubs(interp, version, exact) \
(Tcl_InitStubs)(interp, version, \
(exact)|(TCL_MAJOR_VERSION<<8)|(0xFF<<16), \
TCL_STUB_MAGIC)
#else
# define Tcl_InitStubs(interp, version, exact) \
(Tcl_InitStubs)(interp, version, \
(exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16), \
TCL_STUB_MAGIC)
#endif
#else
#if TCL_MAJOR_VERSION < 9
# define Tcl_InitStubs(interp, version, exact) \
Tcl_Panic(((void)interp, (void)version, \
(void)exact, "Please define -DUSE_TCL_STUBS"))
#else
# define Tcl_InitStubs(interp, version, exact) \
Tcl_PkgInitStubsCheck(interp, version, \
(exact)|(TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16))
#endif
#endif
/*
* Public functions that are not accessible via the stubs table.
* Tcl_GetMemoryInfo is needed for AOLserver. [Bug 1868171]
*/
|
| ︙ | ︙ | |||
2311 2312 2313 2314 2315 2316 2317 | Tcl_LibraryInitProc *initProc, Tcl_LibraryInitProc *safeInitProc); #ifndef TCL_NO_DEPRECATED # define Tcl_StaticPackage Tcl_StaticLibrary #endif EXTERN Tcl_ExitProc * Tcl_SetExitProc(Tcl_ExitProc *proc); #ifdef _WIN32 | | | | | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 |
Tcl_LibraryInitProc *initProc,
Tcl_LibraryInitProc *safeInitProc);
#ifndef TCL_NO_DEPRECATED
# define Tcl_StaticPackage Tcl_StaticLibrary
#endif
EXTERN Tcl_ExitProc * Tcl_SetExitProc(Tcl_ExitProc *proc);
#ifdef _WIN32
EXTERN const char *TclZipfs_AppHook(int *argc, unsigned short ***argv);
#else
EXTERN const char *TclZipfs_AppHook(int *argc, char ***argv);
#endif
#if defined(_WIN32) && defined(UNICODE)
#ifndef USE_TCL_STUBS
# define Tcl_FindExecutable(arg) ((Tcl_FindExecutable)((const char *)(arg)))
#endif
# define Tcl_MainEx Tcl_MainExW
EXTERN TCL_NORETURN void Tcl_MainExW(Tcl_Size argc, unsigned short **argv,
Tcl_AppInitProc *appInitProc, Tcl_Interp *interp);
#endif
#if defined(USE_TCL_STUBS) && (TCL_MAJOR_VERSION > 8)
#define Tcl_SetPanicProc(panicProc) \
TclInitStubTable(((const char *(*)(Tcl_PanicProc *))TclStubCall((void *)panicProc))(panicProc))
#define Tcl_InitSubsystems() \
TclInitStubTable(((const char *(*)(void))TclStubCall((void *)1))())
#define Tcl_FindExecutable(argv0) \
TclInitStubTable(((const char *(*)(const char *))TclStubCall((void *)2))(argv0))
#define TclZipfs_AppHook(argcp, argvp) \
|
| ︙ | ︙ | |||
2433 2434 2435 2436 2437 2438 2439 |
* This will free the obj if there are no references to the obj.
*/
# define Tcl_BounceRefCount(objPtr) \
TclBounceRefCount(objPtr, __FILE__, __LINE__)
static inline void
TclBounceRefCount(
| | | | | 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 |
* This will free the obj if there are no references to the obj.
*/
# define Tcl_BounceRefCount(objPtr) \
TclBounceRefCount(objPtr, __FILE__, __LINE__)
static inline void
TclBounceRefCount(
Tcl_Obj* objPtr,
const char* fn,
int line)
{
if (objPtr) {
if ((objPtr)->refCount == 0) {
Tcl_DbDecrRefCount(objPtr, fn, line);
}
}
}
#else
# undef Tcl_IncrRefCount
# define Tcl_IncrRefCount(objPtr) \
((void)++(objPtr)->refCount)
|
| ︙ | ︙ | |||
2472 2473 2474 2475 2476 2477 2478 |
* This will free the obj if there are no references to the obj.
*/
# define Tcl_BounceRefCount(objPtr) \
TclBounceRefCount(objPtr);
static inline void
TclBounceRefCount(
| | | 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 |
* This will free the obj if there are no references to the obj.
*/
# define Tcl_BounceRefCount(objPtr) \
TclBounceRefCount(objPtr);
static inline void
TclBounceRefCount(
Tcl_Obj* objPtr)
{
if (objPtr) {
if ((objPtr)->refCount == 0) {
Tcl_DecrRefCount(objPtr);
}
}
}
|
| ︙ | ︙ | |||
2535 2536 2537 2538 2539 2540 2541 | /* * Macros to use for clients to use to invoke find and create functions for * hash tables: */ #define Tcl_FindHashEntry(tablePtr, key) \ | | | | < < < | > > > > > | | 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 | /* * Macros to use for clients to use to invoke find and create functions for * hash tables: */ #define Tcl_FindHashEntry(tablePtr, key) \ (*((tablePtr)->findProc))(tablePtr, (const char *)(key)) #define Tcl_CreateHashEntry(tablePtr, key, newPtr) \ (*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr) #endif /* RC_INVOKED */ #ifdef _TCLSIZEHANDLED # undef _TCLSIZEHANDLED # undef Tcl_CmdObjTraceProc2 # undef Tcl_ObjCmdProc2 # undef Tcl_Size #endif /* * end block for C++ */ #ifdef __cplusplus } |
| ︙ | ︙ |
Changes to generic/tclAlloc.c.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 | #define realBlockSize ovu.size }; #define MAGIC 0xEF /* magic # on accounting info */ #define RMAGIC 0x5555 /* magic # on range info */ #ifndef NDEBUG | | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #define realBlockSize ovu.size }; #define MAGIC 0xEF /* magic # on accounting info */ #define RMAGIC 0x5555 /* magic # on range info */ #ifndef NDEBUG #define RSLOP sizeof(unsigned short) #else #define RSLOP 0 #endif #define OVERHEAD (sizeof(union overhead) + RSLOP) /* * Macro to make it easier to refer to the end-of-block guard magic. */ |
| ︙ | ︙ | |||
121 122 123 124 125 126 127 | * in Tcl, we make this module self-initializing after all with the allocInit * variable. */ #if TCL_THREADS static Tcl_Mutex *allocMutexPtr; #endif | | | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | * in Tcl, we make this module self-initializing after all with the allocInit * variable. */ #if TCL_THREADS static Tcl_Mutex *allocMutexPtr; #endif static int allocInit = 0; #ifdef MSTATS /* * numMallocs[i] is the difference between the number of mallocs and frees for * a given block size. */ static size_t numMallocs[NBUCKETS+1]; #endif #if !defined(NDEBUG) #define ASSERT(p) if (!(p)) Tcl_Panic(# p) #define RANGE_ASSERT(p) if (!(p)) Tcl_Panic(# p) #else #define ASSERT(p) #define RANGE_ASSERT(p) #endif /* * Prototypes for functions used only in this file. */ |
| ︙ | ︙ | |||
167 168 169 170 171 172 173 |
*-------------------------------------------------------------------------
*/
void
TclInitAlloc(void)
{
if (!allocInit) {
| | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
*-------------------------------------------------------------------------
*/
void
TclInitAlloc(void)
{
if (!allocInit) {
allocInit = 1;
#if TCL_THREADS
allocMutexPtr = Tcl_GetAllocMutex();
#endif
}
}
/*
|
| ︙ | ︙ | |||
513 514 515 516 517 518 519 |
TclpRealloc(
void *oldPtr, /* Pointer to alloc'ed block. */
size_t numBytes) /* New size of memory. */
{
int i;
union overhead *overPtr;
struct block *bigBlockPtr;
| | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
TclpRealloc(
void *oldPtr, /* Pointer to alloc'ed block. */
size_t numBytes) /* New size of memory. */
{
int i;
union overhead *overPtr;
struct block *bigBlockPtr;
int expensive;
size_t maxSize;
if (oldPtr == NULL) {
return TclpAlloc(numBytes);
}
Tcl_MutexLock(allocMutexPtr);
|
| ︙ | ︙ | |||
580 581 582 583 584 585 586 |
BLOCK_END(overPtr) = RMAGIC;
#endif
Tcl_MutexUnlock(allocMutexPtr);
return (void *)(overPtr+1);
}
maxSize = (size_t)1 << (i+3);
| | | | | 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
BLOCK_END(overPtr) = RMAGIC;
#endif
Tcl_MutexUnlock(allocMutexPtr);
return (void *)(overPtr+1);
}
maxSize = (size_t)1 << (i+3);
expensive = 0;
if (numBytes+OVERHEAD > maxSize) {
expensive = 1;
} else if (i>0 && numBytes+OVERHEAD < maxSize/2) {
expensive = 1;
}
if (expensive) {
void *newPtr;
Tcl_MutexUnlock(allocMutexPtr);
|
| ︙ | ︙ | |||
662 663 664 665 666 667 668 |
fprintf(stderr, "\nused:\t");
for (i = 0; i < NBUCKETS; i++) {
fprintf(stderr, " %" TCL_Z_MODIFIER "u", numMallocs[i]);
totalUsed += numMallocs[i] * ((size_t)1 << (i + 3));
}
fprintf(stderr, "\n\tTotal small in use: %" TCL_Z_MODIFIER "u, total free: %" TCL_Z_MODIFIER "u\n",
| | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
fprintf(stderr, "\nused:\t");
for (i = 0; i < NBUCKETS; i++) {
fprintf(stderr, " %" TCL_Z_MODIFIER "u", numMallocs[i]);
totalUsed += numMallocs[i] * ((size_t)1 << (i + 3));
}
fprintf(stderr, "\n\tTotal small in use: %" TCL_Z_MODIFIER "u, total free: %" TCL_Z_MODIFIER "u\n",
totalUsed, totalFree);
fprintf(stderr, "\n\tNumber of big (>%" TCL_Z_MODIFIER "u) blocks in use: %" TCL_Z_MODIFIER "u\n",
MAXMALLOC, numMallocs[NBUCKETS]);
Tcl_MutexUnlock(allocMutexPtr);
}
#endif
|
| ︙ | ︙ | |||
691 692 693 694 695 696 697 | * *---------------------------------------------------------------------- */ #undef TclpAlloc void * TclpAlloc( | | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
*
*----------------------------------------------------------------------
*/
#undef TclpAlloc
void *
TclpAlloc(
size_t numBytes) /* Number of bytes to allocate. */
{
return malloc(numBytes);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ |
Changes to generic/tclArithSeries.c.
| ︙ | ︙ | |||
43 44 45 46 47 48 49 |
/*
* The structure used for the ArithSeries internal representation.
* Note that the len can in theory be always computed by start,end,step
* but it's faster to cache it inside the internal representation.
*/
typedef struct {
| | | | | | | | | | < < < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
/*
* The structure used for the ArithSeries internal representation.
* Note that the len can in theory be always computed by start,end,step
* but it's faster to cache it inside the internal representation.
*/
typedef struct {
Tcl_Size len;
Tcl_Obj **elements;
int isDouble;
Tcl_Size refCount;
} ArithSeries;
typedef struct {
ArithSeries base;
Tcl_WideInt start;
Tcl_WideInt step;
} ArithSeriesInt;
typedef struct {
ArithSeries base;
double start;
double step;
unsigned precision; /* Number of decimal places to render. */
} ArithSeriesDbl;
/* Forward declarations. */
static int TclArithSeriesObjIndex(TCL_UNUSED(Tcl_Interp *),
Tcl_Obj *arithSeriesObj, Tcl_Size index,
Tcl_Obj **elemObj);
static Tcl_Size ArithSeriesObjLength(Tcl_Obj *arithSeriesObj);
static int TclArithSeriesObjRange(Tcl_Interp *interp,
Tcl_Obj *arithSeriesObj, Tcl_Size fromIdx,
Tcl_Size toIdx, Tcl_Obj **newObjPtr);
|
| ︙ | ︙ | |||
90 91 92 93 94 95 96 |
static int ArithSeriesInOperation(Tcl_Interp *interp,
Tcl_Obj *valueObj, Tcl_Obj *arithSeriesObj,
int *boolResult);
/* ------------------------ ArithSeries object type -------------------------- */
static const Tcl_ObjType arithSeriesType = {
| | | | | | | | | | | | | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
static int ArithSeriesInOperation(Tcl_Interp *interp,
Tcl_Obj *valueObj, Tcl_Obj *arithSeriesObj,
int *boolResult);
/* ------------------------ ArithSeries object type -------------------------- */
static const Tcl_ObjType arithSeriesType = {
"arithseries", /* name */
FreeArithSeriesInternalRep, /* freeIntRepProc */
DupArithSeriesInternalRep, /* dupIntRepProc */
UpdateStringOfArithSeries, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V2(
ArithSeriesObjLength,
TclArithSeriesObjIndex,
TclArithSeriesObjRange,
TclArithSeriesObjReverse,
TclArithSeriesGetElements,
NULL, // SetElement
NULL, // Replace
ArithSeriesInOperation) // "in" operator
};
/*
* Helper functions
*
* - power10 -- Fast version of pow(10, (int) n) for common cases.
* - ArithRound -- Round doubles to the number of significant fractional
|
| ︙ | ︙ | |||
164 165 166 167 168 169 170 |
ArithSeriesEndDbl(
ArithSeriesDbl *dblRepPtr)
{
double d;
if (!dblRepPtr->base.len) {
return dblRepPtr->start;
}
| | | | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
ArithSeriesEndDbl(
ArithSeriesDbl *dblRepPtr)
{
double d;
if (!dblRepPtr->base.len) {
return dblRepPtr->start;
}
d = dblRepPtr->start + ((double)(dblRepPtr->base.len-1) * dblRepPtr->step);
return ArithRound(d, dblRepPtr->precision);
}
static inline Tcl_WideInt
ArithSeriesEndInt(
ArithSeriesInt *intRepPtr)
{
if (!intRepPtr->base.len) {
return intRepPtr->start;
}
return intRepPtr->start + ((intRepPtr->base.len-1) * intRepPtr->step);
}
static inline double
ArithSeriesIndexDbl(
ArithSeries *arithSeriesRepPtr,
Tcl_WideInt index)
{
ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl *)arithSeriesRepPtr;
assert(arithSeriesRepPtr->isDouble);
double d = dblRepPtr->start;
if (index) {
d += ((double)index * dblRepPtr->step);
}
return ArithRound(d, dblRepPtr->precision);
}
static inline Tcl_WideInt
ArithSeriesIndexInt(
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 |
{
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objPtr,
&arithSeriesType);
return irPtr ? (ArithSeries *) irPtr->twoPtrValue.ptr1 : NULL;
}
/*
| | | > | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
{
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objPtr,
&arithSeriesType);
return irPtr ? (ArithSeries *) irPtr->twoPtrValue.ptr1 : NULL;
}
/*
* Compute number of significant fractional digits
*/
static inline unsigned
ObjPrecision(
Tcl_Obj *numObj)
{
void *ptr;
int type;
if (TclHasInternalRep(numObj, &tclDoubleType) || (
Tcl_GetNumberFromObj(NULL, numObj, &ptr, &type) == TCL_OK
&& type == TCL_NUMBER_DOUBLE)
) { /* TCL_NUMBER_DOUBLE */
const char *str = TclGetString(numObj);
if (strchr(str, 'e') == NULL && strchr(str, 'E') == NULL) {
str = strchr(str, '.');
return (str ? (unsigned)strlen(str + 1) : 0);
}
/* don't calculate precision for e-notation */
}
/* no fraction for TCL_NUMBER_NAN, TCL_NUMBER_INT, TCL_NUMBER_BIG */
return 0;
}
/*
* Find longest number of digits after the decimal point.
*/
static inline unsigned
|
| ︙ | ︙ | |||
446 447 448 449 450 451 452 |
arithSeriesObjPtr->internalRep.twoPtrValue.ptr1;
if (arithSeriesRepPtr && arithSeriesRepPtr->refCount-- <= 1) {
FreeElements(arithSeriesRepPtr);
Tcl_Free((void *)arithSeriesRepPtr);
}
}
| | | > | < | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
arithSeriesObjPtr->internalRep.twoPtrValue.ptr1;
if (arithSeriesRepPtr && arithSeriesRepPtr->refCount-- <= 1) {
FreeElements(arithSeriesRepPtr);
Tcl_Free((void *)arithSeriesRepPtr);
}
}
/*
*----------------------------------------------------------------------
*
* NewArithSeriesInt --
*
* Creates a new ArithSeries object. The returned object has
* refcount = 0.
*
* Results:
* A Tcl_Obj pointer to the created ArithSeries object.
* A NULL pointer of the range is invalid.
*
* Side Effects:
* None.
*
*----------------------------------------------------------------------
*/
|
| ︙ | ︙ | |||
500 501 502 503 504 505 506 |
/* -step and abs(step) are both undefined behavior */
absoluteStep = 1 + (Tcl_WideUInt)WIDE_MAX;
} else {
absoluteStep = -step;
}
/* First, step*number of intervals should not overflow */
if (absoluteStep && (UWIDE_MAX / absoluteStep) < (Tcl_WideUInt) numIntervals) {
| | | | | | | | > | < < | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
/* -step and abs(step) are both undefined behavior */
absoluteStep = 1 + (Tcl_WideUInt)WIDE_MAX;
} else {
absoluteStep = -step;
}
/* First, step*number of intervals should not overflow */
if (absoluteStep && (UWIDE_MAX / absoluteStep) < (Tcl_WideUInt) numIntervals) {
goto invalid_range;
}
if (step > 0) {
/*
* Because of check above and UWIDE_MAX=2*WIDE_MAX+1,
* second term will not underflow a Tcl_WideInt
*/
if (start > (WIDE_MAX - (step * numIntervals))) {
goto invalid_range;
}
} else if (step == WIDE_MIN) {
if (numIntervals > 0 || start < 0) {
goto invalid_range;
}
} else if (step < 0) {
/*
* Because of check above and UWIDE_MAX=2*WIDE_MAX+1 and
* step != WIDE_MIN second term will not underflow a Tcl_WideInt.
* DON'T use absoluteStep here because of unsigned type promotion
*/
if (start < (WIDE_MIN + ((-step) * numIntervals))) {
goto invalid_range;
}
} else /* step == 0 */ {
/* TODO - step == 0 && length > 1 should be error? */
}
}
arithSeriesRepPtr = (ArithSeriesInt *) Tcl_Alloc(sizeof(ArithSeriesInt));
arithSeriesRepPtr->base.len = length;
arithSeriesRepPtr->base.elements = NULL;
arithSeriesRepPtr->base.isDouble = 0;
arithSeriesRepPtr->base.refCount = 1;
arithSeriesRepPtr->start = start;
arithSeriesRepPtr->step = step;
arithSeriesObj->internalRep.twoPtrValue.ptr1 = arithSeriesRepPtr;
arithSeriesObj->internalRep.twoPtrValue.ptr2 = NULL;
arithSeriesObj->typePtr = &arithSeriesType;
Tcl_InvalidateStringRep(arithSeriesObj);
return arithSeriesObj;
invalid_range:
Tcl_BounceRefCount(arithSeriesObj);
return NULL;
}
/*
*----------------------------------------------------------------------
*
* NewArithSeriesDbl --
*
* Creates a new ArithSeries object with doubles. The returned object has
* refcount = 0.
*
* Results:
* A Tcl_Obj pointer to the created ArithSeries object.
* A NULL pointer of the range is invalid.
*
* Side Effects:
* None.
*----------------------------------------------------------------------
*/
static Tcl_Obj *
NewArithSeriesDbl(
double start,
double step,
Tcl_WideInt len,
|
| ︙ | ︙ | |||
589 590 591 592 593 594 595 |
if (length <= 0) {
return arithSeriesObj;
}
arithSeriesRepPtr = (ArithSeriesDbl *) Tcl_Alloc(sizeof(ArithSeriesDbl));
arithSeriesRepPtr->base.len = length;
arithSeriesRepPtr->base.elements = NULL;
| | | | | | < | < | | | | | | | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
if (length <= 0) {
return arithSeriesObj;
}
arithSeriesRepPtr = (ArithSeriesDbl *) Tcl_Alloc(sizeof(ArithSeriesDbl));
arithSeriesRepPtr->base.len = length;
arithSeriesRepPtr->base.elements = NULL;
arithSeriesRepPtr->base.isDouble = 1;
arithSeriesRepPtr->base.refCount = 1;
arithSeriesRepPtr->start = start;
arithSeriesRepPtr->step = step;
arithSeriesRepPtr->precision = precision;
arithSeriesObj->internalRep.twoPtrValue.ptr1 = arithSeriesRepPtr;
arithSeriesObj->internalRep.twoPtrValue.ptr2 = NULL;
arithSeriesObj->typePtr = &arithSeriesType;
if (length > 0) {
Tcl_InvalidateStringRep(arithSeriesObj);
}
return arithSeriesObj;
}
/*
*----------------------------------------------------------------------
*
* assignNumber --
*
* Create the appropriate Tcl_Obj value for the given numeric values.
* Used locally only for decoding [lseq] numeric arguments.
* refcount = 0.
*
* Results:
* A Tcl_Obj pointer. No assignment on error.
*
* Side Effects:
* None.
*----------------------------------------------------------------------
*/
static int
assignNumber(
Tcl_Interp *interp,
int useDoubles,
Tcl_WideInt *intNumberPtr,
double *dblNumberPtr,
Tcl_Obj *numberObj)
{
void *ptr;
int type;
if (Tcl_GetNumberFromObj(interp, numberObj, &ptr, &type) != TCL_OK) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
674 675 676 677 678 679 680 | /* *---------------------------------------------------------------------- * * TclNewArithSeriesObj -- * * Creates a new ArithSeries object. Some arguments may be NULL and will * be computed based on the other given arguments. | | < | | < | | | | | < < < < < | | > | > > | > > > > > > > > > | | | | | | | > | > > > > | | > > | < < < < < | < < < < < < | < | < < < < < < < | | 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 |
/*
*----------------------------------------------------------------------
*
* TclNewArithSeriesObj --
*
* Creates a new ArithSeries object. Some arguments may be NULL and will
* be computed based on the other given arguments.
* refcount = 0.
*
* Results:
* A Tcl_Obj pointer to the created ArithSeries object.
* NULL if the range is invalid.
*
* Side Effects:
* None.
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclNewArithSeriesObj(
Tcl_Interp *interp, /* For error reporting */
int useDoubles, /* Flag indicates values start,
* end, step, are treated as doubles */
Tcl_Obj *startObj, /* Starting value */
Tcl_Obj *endObj, /* Ending limit */
Tcl_Obj *stepObj, /* increment value */
Tcl_Obj *lenObj) /* Number of elements */
{
double dstart, dend, dstep = 1.0;
Tcl_WideInt start, end, step = 1;
Tcl_WideInt len;
Tcl_Obj *objPtr;
unsigned precision = (unsigned)-1; /* unknown precision */
if (lenObj) {
if (Tcl_GetWideIntFromObj(interp, lenObj, &len) != TCL_OK) {
return NULL;
}
} else {
// Default
len = -1;
}
if (stepObj) {
if (assignNumber(interp, useDoubles, &step, &dstep, stepObj) != TCL_OK) {
return NULL;
}
} else {
// Default
step = 1;
dstep = step;
}
if (startObj) {
if (assignNumber(interp, useDoubles, &start, &dstart, startObj) != TCL_OK) {
return NULL;
}
} else {
// Default
start = 0;
dstart = start;
}
if (endObj) {
if (assignNumber(interp, useDoubles, &end, &dend, endObj) != TCL_OK) {
return NULL;
}
}
if (endObj) {
if (!stepObj) {
if (useDoubles) {
if (dstart > dend) {
step = -1;
dstep = step;
}
} else {
if (start > end) {
step = -1;
dstep = step;
}
}
}
if (!lenObj) {
if (useDoubles) {
if (isinf(dstart) || isinf(dend)) {
goto exceeded;
}
if (isnan(dstart) || isnan(dend)) {
const char *description = "non-numeric floating-point value";
char tmp[TCL_DOUBLE_SPACE + 2];
tmp[0] = '\0';
Tcl_PrintDouble(NULL, isnan(dstart)?dstart:dend, tmp);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"cannot use %s \"%s\" to estimate length of arith-series",
description, tmp));
Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", description,
(char *)NULL);
return NULL;
}
precision = maxObjPrecision(startObj, endObj, stepObj);
len = ArithSeriesLenDbl(dstart, dend, dstep, precision);
} else {
len = ArithSeriesLenInt(start, end, step);
}
}
} else {
if (useDoubles) {
// Compute precision based on given command argument values
precision = maxObjPrecision(startObj, NULL, stepObj);
dend = dstart + (dstep * (double)(len-1));
// Make computed end value match argument(s) precision
dend = ArithRound(dend, precision);
end = dend;
}
}
/*
* todo: check whether the boundary must be rather LIST_MAX, to be more
* similar to plain lists, otherwise it'd generate an error or panic later
* (0x0ffffffffffffffa instead of 0x7fffffffffffffff by 64bit)
*/
/*
* Comment for future reference: The size concern would only be triggered
* via a shimmer or getElements of the abstract list. Otherwise, the
* abstract list is only limited by the max index value. Even then,
* indexing with a bignum is theoretically possible. This is because
* individual values are not stored. They are created upon request.
*/
if (len > TCL_SIZE_MAX) {
exceeded:
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"max length of a Tcl list exceeded", TCL_AUTO_LENGTH));
Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
return NULL;
}
if (useDoubles) {
/* ensure we'll not get NaN somewhere in the arith-series,
* so simply check the end of it and behave like [expr {Inf - Inf}] */
double d = dstart + (double)(len - 1) * dstep;
if (isnan(d)) {
const char *s = "domain error: argument not in valid range";
Tcl_SetObjResult(interp, Tcl_NewStringObj(s, -1));
Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", s, (char *)NULL);
return NULL;
}
if (precision == (unsigned)-1) {
precision = maxObjPrecision(startObj, endObj, stepObj);
}
objPtr = NewArithSeriesDbl(dstart, dstep, len, precision);
} else {
objPtr = NewArithSeriesInt(start, step, len);
}
if (objPtr == NULL && interp) {
const char *description = "invalid arithmetic series parameter values";
Tcl_SetResult(interp, description, TCL_STATIC);
Tcl_SetErrorCode(interp, "ARITH", "DOMAIN", description, (char *)NULL);
}
return objPtr;
}
/*
*----------------------------------------------------------------------
*
* TclArithSeriesObjIndex --
*
|
| ︙ | ︙ | |||
915 916 917 918 919 920 921 | /* *---------------------------------------------------------------------- * * TclArithSeriesObjRange -- * * Makes a slice of an ArithSeries value. | | | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | /* *---------------------------------------------------------------------- * * TclArithSeriesObjRange -- * * Makes a slice of an ArithSeries value. * *arithSeriesObj must be known to be a valid list. * * Results: * Returns a pointer to the sliced series. * This may be a new object or the same object if not shared. * * Side effects: * ?The possible conversion of the object referenced by listPtr? * ?to a list object.? * *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
969 970 971 972 973 974 975 |
len = toIdx - fromIdx + 1;
if (arithSeriesRepPtr->isDouble) {
ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl *)arithSeriesRepPtr;
double dstart = ArithSeriesIndexDbl(arithSeriesRepPtr, fromIdx);
| | | | | 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
len = toIdx - fromIdx + 1;
if (arithSeriesRepPtr->isDouble) {
ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl *)arithSeriesRepPtr;
double dstart = ArithSeriesIndexDbl(arithSeriesRepPtr, fromIdx);
if (Tcl_IsShared(arithSeriesObj) || ((arithSeriesRepPtr->refCount > 1))) {
/* as new object */
*newObjPtr = NewArithSeriesDbl(dstart, dblRepPtr->step, len,
dblRepPtr->precision);
} else {
/* in-place is possible */
*newObjPtr = arithSeriesObj;
/*
* Even if nothing below causes any changes, we still want the
* string-canonizing effect of [lrange 0 end].
*/
TclInvalidateStringRep(arithSeriesObj);
dblRepPtr->start = dstart;
/* step and precision remain the same */
dblRepPtr->base.len = len;
FreeElements(arithSeriesRepPtr);
}
} else {
ArithSeriesInt *intRepPtr = (ArithSeriesInt *) arithSeriesRepPtr;
Tcl_WideInt start = ArithSeriesIndexInt(arithSeriesRepPtr, fromIdx);
if (Tcl_IsShared(arithSeriesObj) || ((arithSeriesRepPtr->refCount > 1))) {
/* as new object */
*newObjPtr = NewArithSeriesInt(start, intRepPtr->step, len);
} else {
/* in-place is possible. */
*newObjPtr = arithSeriesObj;
/*
* Even if nothing below causes any changes, we still want the
|
| ︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 |
if (objc > 0) {
if (arithSeriesRepPtr->elements) {
/* If this exists, it has already been populated */
objv = arithSeriesRepPtr->elements;
} else {
/* Construct the elements array */
| | | 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
if (objc > 0) {
if (arithSeriesRepPtr->elements) {
/* If this exists, it has already been populated */
objv = arithSeriesRepPtr->elements;
} else {
/* Construct the elements array */
objv = (Tcl_Obj **) Tcl_Alloc(sizeof(Tcl_Obj*) * objc);
if (objv == NULL) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"max length of a Tcl list exceeded",
TCL_AUTO_LENGTH));
Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
}
|
| ︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 | * TclArithSeriesObjReverse -- * * Reverse the order of the ArithSeries value. The arithSeriesObj is * assumed to be a valid ArithSeries. The new Obj has the Start and End * values appropriately swapped and the Step value sign is changed. * * Results: | | | | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 |
* TclArithSeriesObjReverse --
*
* Reverse the order of the ArithSeries value. The arithSeriesObj is
* assumed to be a valid ArithSeries. The new Obj has the Start and End
* values appropriately swapped and the Step value sign is changed.
*
* Results:
* The result will be an ArithSeries in the reverse order.
*
* Side effects:
* The ogiginal obj will be modified and returned if it is not Shared.
*
*----------------------------------------------------------------------
*/
int
TclArithSeriesObjReverse(
Tcl_Interp *interp, /* For error message(s) */
Tcl_Obj *arithSeriesObj, /* List object to reverse. */
|
| ︙ | ︙ | |||
1137 1138 1139 1140 1141 1142 1143 |
arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj);
if (Tcl_IsShared(arithSeriesObj) || (arithSeriesRepPtr->refCount > 1)) {
if (arithSeriesRepPtr->isDouble) {
ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl *)arithSeriesRepPtr;
resultObj = NewArithSeriesDbl(ArithSeriesEndDbl(dblRepPtr),
| | < | | 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 |
arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj);
if (Tcl_IsShared(arithSeriesObj) || (arithSeriesRepPtr->refCount > 1)) {
if (arithSeriesRepPtr->isDouble) {
ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl *)arithSeriesRepPtr;
resultObj = NewArithSeriesDbl(ArithSeriesEndDbl(dblRepPtr),
-dblRepPtr->step, arithSeriesRepPtr->len, dblRepPtr->precision);
} else {
ArithSeriesInt *intRepPtr = (ArithSeriesInt *)arithSeriesRepPtr;
resultObj = NewArithSeriesInt(ArithSeriesEndInt(intRepPtr),
-intRepPtr->step, arithSeriesRepPtr->len);
}
} else {
/*
* In-place is possible.
*/
TclInvalidateStringRep(arithSeriesObj);
|
| ︙ | ︙ | |||
1230 1231 1232 1233 1234 1235 1236 |
} else {
char tmp[TCL_DOUBLE_SPACE + 2];
for (i = 0; i < arithSeriesRepPtr->len; i++) {
double d = ArithSeriesIndexDbl(arithSeriesRepPtr, i);
Tcl_Size elen;
tmp[0] = '\0';
| | | < | | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 |
} else {
char tmp[TCL_DOUBLE_SPACE + 2];
for (i = 0; i < arithSeriesRepPtr->len; i++) {
double d = ArithSeriesIndexDbl(arithSeriesRepPtr, i);
Tcl_Size elen;
tmp[0] = '\0';
Tcl_PrintDouble(NULL,d,tmp);
elen = strlen(tmp);
if (bytlen > TCL_SIZE_MAX - elen) {
/* overflow, todo: check we could use some representation instead of the panic
* to signal it is too large for string representation, because too heavy */
Tcl_Panic("UpdateStringOfArithSeries: too large to represent");
}
bytlen += elen;
}
}
bytlen += arithSeriesRepPtr->len; // Space for each separator
|
| ︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 |
*p++ = ' ';
}
} else {
for (i = 0; i < arithSeriesRepPtr->len; i++) {
double d = ArithSeriesIndexDbl(arithSeriesRepPtr, i);
*p = '\0';
| | | | | | | | | | 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 |
*p++ = ' ';
}
} else {
for (i = 0; i < arithSeriesRepPtr->len; i++) {
double d = ArithSeriesIndexDbl(arithSeriesRepPtr, i);
*p = '\0';
Tcl_PrintDouble(NULL,d,p);
p += strlen(p);
assert(p - arithSeriesObjPtr->bytes <= bytlen);
*p++ = ' ';
}
}
(void) Tcl_InitStringRep(arithSeriesObjPtr, NULL, (--p - srep));
}
/*
*----------------------------------------------------------------------
*
* ArithSeriesInOperator --
*
* Evaluate the "in" operation for expr
*
* This can be done more efficiently in the Arith Series relative to
* doing a linear search as implemented in expr.
*
* Results:
* Boolean true or false (1/0)
*
* Side effects:
* None
*
*----------------------------------------------------------------------
*/
static int
ArithSeriesInOperation(
Tcl_Interp *interp,
Tcl_Obj *valueObj,
Tcl_Obj *arithSeriesObjPtr,
int *boolResult)
{
ArithSeries *repPtr = (ArithSeries *)
arithSeriesObjPtr->internalRep.twoPtrValue.ptr1;
int status;
Tcl_Size index, incr, elen, vlen;
if (repPtr->isDouble) {
ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl *) repPtr;
double y;
int test = 0;
incr = 0; // Check index+incr where incr is 0 and 1
status = Tcl_GetDoubleFromObj(interp, valueObj, &y);
if (status != TCL_OK) {
test = 0;
} else {
const char *vstr = TclGetStringFromObj(valueObj, &vlen);
index = (y - dblRepPtr->start) / dblRepPtr->step;
while (incr<2) {
Tcl_Obj *elemObj;
elen = 0;
TclArithSeriesObjIndex(interp, arithSeriesObjPtr, (index+incr), &elemObj);
const char *estr = elemObj ? TclGetStringFromObj(elemObj, &elen) : "";
/* "in" operation defined as a string compare */
test = (elen == vlen) ? (memcmp(estr, vstr, elen) == 0) : 0;
Tcl_BounceRefCount(elemObj);
/* Stop if we have a match */
if (test) {
break;
}
incr++;
}
}
if (boolResult) {
*boolResult = test;
}
} else {
ArithSeriesInt *intRepPtr = (ArithSeriesInt *) repPtr;
Tcl_WideInt y;
status = Tcl_GetWideIntFromObj(NULL, valueObj, &y);
if (status != TCL_OK) {
|
| ︙ | ︙ |
Changes to generic/tclAssembly.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | */ /*- *- THINGS TO DO: *- More instructions: *- done - alternate exit point (affects stack and exception range checking) *- break and continue - if exception ranges can be sorted out. | | | > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | */ /*- *- THINGS TO DO: *- More instructions: *- done - alternate exit point (affects stack and exception range checking) *- break and continue - if exception ranges can be sorted out. *- foreach_start4, foreach_step4 *- returnImm, returnStk *- expandStart, expandStkTop, invokeExpanded, expandDrop *- dictFirst, dictNext, dictDone *- dictUpdateStart, dictUpdateEnd *- jumpTable testing *- syntax (?) *- returnCodeBranch *- tclooNext, tclooNextClass */ #include "tclInt.h" #include "tclCompile.h" #include "tclOOInt.h" |
| ︙ | ︙ | |||
56 57 58 59 60 61 62 63 64 65 66 |
/*
* Structure that defines a basic block - a linear sequence of bytecode
* instructions with no jumps in or out (including not changing the
* state of any exception range).
*/
typedef struct BasicBlock {
int startOffset; /* Instruction offset of the start of the
* block */
int startLine; /* Line number in the input script of the
* instruction at the start of the block */
| > > | | < < > > | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
/*
* Structure that defines a basic block - a linear sequence of bytecode
* instructions with no jumps in or out (including not changing the
* state of any exception range).
*/
typedef struct BasicBlock {
int originalStartOffset; /* Instruction offset before JUMP1s were
* substituted with JUMP4's */
int startOffset; /* Instruction offset of the start of the
* block */
int startLine; /* Line number in the input script of the
* instruction at the start of the block */
int jumpOffset; /* Bytecode offset of the 'jump' instruction
* that ends the block, or -1 if there is no
* jump. */
int jumpLine; /* Line number in the input script of the
* 'jump' instruction that ends the block, or
* -1 if there is no jump */
struct BasicBlock* prevPtr; /* Immediate predecessor of this block */
struct BasicBlock* predecessor;
/* Predecessor of this block in the spanning
* tree */
struct BasicBlock* successor1;
/* BasicBlock structure of the following
* block: NULL at the end of the bytecode
* sequence. */
Tcl_Obj* jumpTarget; /* Jump target label if the jump target is
* unresolved */
int initialStackDepth; /* Absolute stack depth on entry */
int minStackDepth; /* Low-water relative stack depth */
int maxStackDepth; /* High-water relative stack depth */
int finalStackDepth; /* Relative stack depth on exit */
enum BasicBlockCatchState catchState;
/* State of the block for 'catch' analysis */
int catchDepth; /* Number of nested catches in which the basic
* block appears */
struct BasicBlock* enclosingCatch;
/* BasicBlock structure of the last startCatch
* executed on a path to this block, or NULL
* if there is no enclosing catch */
int foreignExceptionBase; /* Base index of foreign exceptions */
int foreignExceptionCount; /* Count of foreign exceptions */
ExceptionRange* foreignExceptions;
/* ExceptionRange structures for exception
* ranges belonging to embedded scripts and
* expressions in this block */
JumptableInfo* jtPtr; /* Jump table at the end of this basic block */
int flags; /* Boolean flags */
} BasicBlock;
/*
* Flags that pertain to a basic block.
*/
enum BasicBlockFlags {
BB_VISITED = (1 << 0), /* Block has been visited in the current
* traversal */
BB_FALLTHRU = (1 << 1), /* Control may pass from this block to a
* successor */
BB_JUMP1 = (1 << 2), /* Basic block ends with a 1-byte-offset jump
* and may need expansion */
BB_JUMPTABLE = (1 << 3), /* Basic block ends with a jump table */
BB_BEGINCATCH = (1 << 4), /* Block ends with a 'beginCatch' instruction,
* marking it as the start of a 'catch'
* sequence. The 'jumpTarget' is the exception
* exit from the catch block. */
BB_ENDCATCH = (1 << 5) /* Block ends with an 'endCatch' instruction,
* unwinding the catch from the exception
* stack. */
};
/*
* Source instruction type recognized by the assembler.
*/
typedef enum {
ASSEM_1BYTE, /* Fixed arity, 1-byte instruction */
ASSEM_BEGIN_CATCH, /* Begin catch: one 4-byte jump offset to be
* converted to appropriate exception
* ranges */
ASSEM_BOOL, /* One Boolean operand */
ASSEM_BOOL_LVT4, /* One Boolean, one 4-byte LVT ref. */
ASSEM_CLOCK_READ, /* 1-byte unsigned-integer case number, in the
* range 0-3 */
ASSEM_CONCAT1, /* 1-byte unsigned-integer operand count, must
* be strictly positive, consumes N, produces
* 1 */
ASSEM_DICT_GET, /* 'dict get' and related - consumes N+1
* operands, produces 1, N > 0 */
|
| ︙ | ︙ | |||
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
* compiling it in line with the assembly
* code! I love Tcl!) */
ASSEM_INDEX, /* 4 byte operand, integer or end-integer */
ASSEM_INVOKE, /* 1- or 4-byte operand count, must be
* strictly positive, consumes N, produces
* 1. */
ASSEM_JUMP, /* Jump instructions */
ASSEM_JUMPTABLE, /* Jumptable (switch -exact) */
ASSEM_LABEL, /* The assembly directive that defines a
* label */
ASSEM_LINDEX_MULTI, /* 4-byte operand count, must be strictly
* positive, consumes N, produces 1 */
ASSEM_LIST, /* 4-byte operand count, must be nonnegative,
* consumses N, produces 1 */
ASSEM_LSET_FLAT, /* 4-byte operand count, must be >= 3,
* consumes N, produces 1 */
| > > > | | | | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
* compiling it in line with the assembly
* code! I love Tcl!) */
ASSEM_INDEX, /* 4 byte operand, integer or end-integer */
ASSEM_INVOKE, /* 1- or 4-byte operand count, must be
* strictly positive, consumes N, produces
* 1. */
ASSEM_JUMP, /* Jump instructions */
ASSEM_JUMP4, /* Jump instructions forcing a 4-byte offset */
ASSEM_JUMPTABLE, /* Jumptable (switch -exact) */
ASSEM_LABEL, /* The assembly directive that defines a
* label */
ASSEM_LINDEX_MULTI, /* 4-byte operand count, must be strictly
* positive, consumes N, produces 1 */
ASSEM_LIST, /* 4-byte operand count, must be nonnegative,
* consumses N, produces 1 */
ASSEM_LSET_FLAT, /* 4-byte operand count, must be >= 3,
* consumes N, produces 1 */
ASSEM_LVT, /* One operand that references a local
* variable */
ASSEM_LVT1, /* One 1-byte operand that references a local
* variable */
ASSEM_LVT1_SINT1, /* One 1-byte operand that references a local
* variable, one signed-integer 1-byte
* operand */
ASSEM_LVT4, /* One 4-byte operand that references a local
* variable */
ASSEM_OVER, /* OVER: 4-byte operand count, consumes N+1,
* produces N+2 */
ASSEM_PUSH, /* one literal operand */
ASSEM_REGEXP, /* One Boolean operand, but weird mapping to
* call flags */
ASSEM_REVERSE, /* REVERSE: 4-byte operand count, consumes N,
* produces N */
ASSEM_SINT1, /* One 1-byte signed-integer operand
* (INCR_STK_IMM) */
ASSEM_SINT4_LVT4, /* Signed 4-byte integer operand followed by
* LVT entry. Fixed arity */
ASSEM_DICT_GET_DEF /* 'dict getwithdefault' - consumes N+2
* operands, produces 1, N > 0 */
} TalInstType;
/*
* Description of an instruction recognized by the assembler.
|
| ︙ | ︙ | |||
211 212 213 214 215 216 217 |
typedef struct AssemblyEnv {
CompileEnv* envPtr; /* Compilation environment being used for code
* generation */
Tcl_Parse* parsePtr; /* Parse of the current line of source */
Tcl_HashTable labelHash; /* Hash table whose keys are labels and whose
* values are 'label' objects storing the code
* offsets of the labels. */
| | | | | | | | | | | > > | | | | | | | | | | | | | | | > | | | | < | | | < < | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | > > | | > | | | | | > | < | < | | | | | > | > | | | < | | < | < | < | > | > | > | | > | | > | | > | > | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
typedef struct AssemblyEnv {
CompileEnv* envPtr; /* Compilation environment being used for code
* generation */
Tcl_Parse* parsePtr; /* Parse of the current line of source */
Tcl_HashTable labelHash; /* Hash table whose keys are labels and whose
* values are 'label' objects storing the code
* offsets of the labels. */
Tcl_Size cmdLine; /* Current line number within the assembly
* code */
Tcl_Size* clNext; /* Invisible continuation line for
* [info frame] */
BasicBlock* head_bb; /* First basic block in the code */
BasicBlock* curr_bb; /* Current basic block */
int maxDepth; /* Maximum stack depth encountered */
int curCatchDepth; /* Current depth of catches */
int maxCatchDepth; /* Maximum depth of catches encountered */
int flags; /* Compilation flags (TCL_EVAL_DIRECT) */
} AssemblyEnv;
/*
* Static functions defined in this file.
*/
static void AddBasicBlockRangeToErrorInfo(AssemblyEnv*,
BasicBlock*);
static BasicBlock * AllocBB(AssemblyEnv*);
static int AssembleOneLine(AssemblyEnv* envPtr);
static void BBAdjustStackDepth(BasicBlock* bbPtr, int consumed,
int produced);
static void BBUpdateStackReqs(BasicBlock* bbPtr, int tblIdx,
int count);
static void BBEmitInstInt1(AssemblyEnv* assemEnvPtr, int tblIdx,
int opnd, int count);
static void BBEmitInstInt4(AssemblyEnv* assemEnvPtr, int tblIdx,
int opnd, int count);
static void BBEmitInst1or4(AssemblyEnv* assemEnvPtr, int tblIdx,
int param, int count);
static void BBEmitOpcode(AssemblyEnv* assemEnvPtr, int tblIdx,
int count);
static int BuildExceptionRanges(AssemblyEnv* assemEnvPtr);
static int CalculateJumpRelocations(AssemblyEnv*, int*);
static int CheckForUnclosedCatches(AssemblyEnv*);
static int CheckForThrowInWrongContext(AssemblyEnv*);
static int CheckNonThrowingBlock(AssemblyEnv*, BasicBlock*);
static int BytecodeMightThrow(unsigned char);
static int CheckJumpTableLabels(AssemblyEnv*, BasicBlock*);
static int CheckNamespaceQualifiers(Tcl_Interp*, const char*,
int);
static int CheckNonNegative(Tcl_Interp*, int);
static int CheckOneByte(Tcl_Interp*, int);
static int CheckSignedOneByte(Tcl_Interp*, int);
static int CheckStack(AssemblyEnv*);
static int CheckStrictlyPositive(Tcl_Interp*, int);
static ByteCode * CompileAssembleObj(Tcl_Interp *interp,
Tcl_Obj *objPtr);
static void CompileEmbeddedScript(AssemblyEnv*, Tcl_Token*,
const TalInstDesc*);
static int DefineLabel(AssemblyEnv* envPtr, const char* label);
static void DeleteMirrorJumpTable(JumptableInfo* jtPtr);
static void FillInJumpOffsets(AssemblyEnv*);
static int CreateMirrorJumpTable(AssemblyEnv* assemEnvPtr,
Tcl_Obj* jumpTable);
static size_t FindLocalVar(AssemblyEnv* envPtr,
Tcl_Token** tokenPtrPtr);
static int FinishAssembly(AssemblyEnv*);
static void FreeAssemblyEnv(AssemblyEnv*);
static int GetBooleanOperand(AssemblyEnv*, Tcl_Token**, int*);
static int GetListIndexOperand(AssemblyEnv*, Tcl_Token**, int*);
static int GetIntegerOperand(AssemblyEnv*, Tcl_Token**, int*);
static int GetNextOperand(AssemblyEnv*, Tcl_Token**, Tcl_Obj**);
static void LookForFreshCatches(BasicBlock*, BasicBlock**);
static void MoveCodeForJumps(AssemblyEnv*, int);
static void MoveExceptionRangesToBasicBlock(AssemblyEnv*, int);
static AssemblyEnv* NewAssemblyEnv(CompileEnv*, int);
static int ProcessCatches(AssemblyEnv*);
static int ProcessCatchesInBasicBlock(AssemblyEnv*, BasicBlock*,
BasicBlock*, enum BasicBlockCatchState, int);
static void ResetVisitedBasicBlocks(AssemblyEnv*);
static void ResolveJumpTableTargets(AssemblyEnv*, BasicBlock*);
static void ReportUndefinedLabel(AssemblyEnv*, BasicBlock*,
Tcl_Obj*);
static void RestoreEmbeddedExceptionRanges(AssemblyEnv*);
static int StackCheckBasicBlock(AssemblyEnv*, BasicBlock *,
BasicBlock *, int);
static BasicBlock* StartBasicBlock(AssemblyEnv*, int fallthrough,
Tcl_Obj* jumpLabel);
/* static int AdvanceIp(const unsigned char *pc); */
static int StackCheckBasicBlock(AssemblyEnv*, BasicBlock *,
BasicBlock *, int);
static int StackCheckExit(AssemblyEnv*);
static void StackFreshCatches(AssemblyEnv*, BasicBlock*, int,
BasicBlock**, int*);
static void SyncStackDepth(AssemblyEnv*);
static int TclAssembleCode(CompileEnv* envPtr, const char* code,
int codeLen, int flags);
static void UnstackExpiredCatches(CompileEnv*, BasicBlock*, int,
BasicBlock**, int*);
/*
* Tcl_ObjType that describes bytecode emitted by the assembler.
*/
static Tcl_FreeInternalRepProc FreeAssembleCodeInternalRep;
static Tcl_DupInternalRepProc DupAssembleCodeInternalRep;
static const Tcl_ObjType assembleCodeType = {
"assemblecode",
FreeAssembleCodeInternalRep, /* freeIntRepProc */
DupAssembleCodeInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
/*
* Source instructions recognized in the Tcl Assembly Language (TAL)
*/
static const TalInstDesc TalInstructionTable[] = {
/* PUSH must be first, see the code near the end of TclAssembleCode */
{"push", ASSEM_PUSH, (INST_PUSH1<<8
| INST_PUSH4), 0, 1},
{"add", ASSEM_1BYTE, INST_ADD, 2, 1},
{"append", ASSEM_LVT, (INST_APPEND_SCALAR1<<8
| INST_APPEND_SCALAR4),1, 1},
{"appendArray", ASSEM_LVT, (INST_APPEND_ARRAY1<<8
| INST_APPEND_ARRAY4), 2, 1},
{"appendArrayStk", ASSEM_1BYTE, INST_APPEND_ARRAY_STK, 3, 1},
{"appendStk", ASSEM_1BYTE, INST_APPEND_STK, 2, 1},
{"arrayExistsImm", ASSEM_LVT4, INST_ARRAY_EXISTS_IMM, 0, 1},
{"arrayExistsStk", ASSEM_1BYTE, INST_ARRAY_EXISTS_STK, 1, 1},
{"arrayMakeImm", ASSEM_LVT4, INST_ARRAY_MAKE_IMM, 0, 0},
{"arrayMakeStk", ASSEM_1BYTE, INST_ARRAY_MAKE_STK, 1, 0},
{"beginCatch", ASSEM_BEGIN_CATCH,
INST_BEGIN_CATCH4, 0, 0},
{"bitand", ASSEM_1BYTE, INST_BITAND, 2, 1},
{"bitnot", ASSEM_1BYTE, INST_BITNOT, 1, 1},
{"bitor", ASSEM_1BYTE, INST_BITOR, 2, 1},
{"bitxor", ASSEM_1BYTE, INST_BITXOR, 2, 1},
{"clockRead", ASSEM_CLOCK_READ, INST_CLOCK_READ, 0, 1},
{"concat", ASSEM_CONCAT1, INST_STR_CONCAT1, INT_MIN,1},
{"concatStk", ASSEM_LIST, INST_CONCAT_STK, INT_MIN,1},
{"coroName", ASSEM_1BYTE, INST_COROUTINE_NAME, 0, 1},
{"currentNamespace",ASSEM_1BYTE, INST_NS_CURRENT, 0, 1},
{"dictAppend", ASSEM_LVT4, INST_DICT_APPEND, 2, 1},
{"dictExists", ASSEM_DICT_GET, INST_DICT_EXISTS, INT_MIN,1},
{"dictExpand", ASSEM_1BYTE, INST_DICT_EXPAND, 3, 1},
{"dictGet", ASSEM_DICT_GET, INST_DICT_GET, INT_MIN,1},
{"dictGetDef", ASSEM_DICT_GET_DEF, INST_DICT_GET_DEF, INT_MIN,1},
{"dictIncrImm", ASSEM_SINT4_LVT4,
INST_DICT_INCR_IMM, 1, 1},
{"dictLappend", ASSEM_LVT4, INST_DICT_LAPPEND, 2, 1},
{"dictRecombineStk",ASSEM_1BYTE, INST_DICT_RECOMBINE_STK,3, 0},
{"dictRecombineImm",ASSEM_LVT4, INST_DICT_RECOMBINE_IMM,2, 0},
{"dictSet", ASSEM_DICT_SET, INST_DICT_SET, INT_MIN,1},
{"dictUnset", ASSEM_DICT_UNSET,
INST_DICT_UNSET, INT_MIN,1},
{"div", ASSEM_1BYTE, INST_DIV, 2, 1},
{"dup", ASSEM_1BYTE, INST_DUP, 1, 2},
{"endCatch", ASSEM_END_CATCH,INST_END_CATCH, 0, 0},
{"eq", ASSEM_1BYTE, INST_EQ, 2, 1},
{"eval", ASSEM_EVAL, INST_EVAL_STK, 1, 1},
{"evalStk", ASSEM_1BYTE, INST_EVAL_STK, 1, 1},
{"exist", ASSEM_LVT4, INST_EXIST_SCALAR, 0, 1},
{"existArray", ASSEM_LVT4, INST_EXIST_ARRAY, 1, 1},
{"existArrayStk", ASSEM_1BYTE, INST_EXIST_ARRAY_STK, 2, 1},
{"existStk", ASSEM_1BYTE, INST_EXIST_STK, 1, 1},
{"expon", ASSEM_1BYTE, INST_EXPON, 2, 1},
{"expr", ASSEM_EVAL, INST_EXPR_STK, 1, 1},
{"exprStk", ASSEM_1BYTE, INST_EXPR_STK, 1, 1},
{"ge", ASSEM_1BYTE, INST_GE, 2, 1},
{"gt", ASSEM_1BYTE, INST_GT, 2, 1},
{"incr", ASSEM_LVT1, INST_INCR_SCALAR1, 1, 1},
{"incrArray", ASSEM_LVT1, INST_INCR_ARRAY1, 2, 1},
{"incrArrayImm", ASSEM_LVT1_SINT1,
INST_INCR_ARRAY1_IMM, 1, 1},
{"incrArrayStk", ASSEM_1BYTE, INST_INCR_ARRAY_STK, 3, 1},
{"incrArrayStkImm", ASSEM_SINT1, INST_INCR_ARRAY_STK_IMM,2, 1},
{"incrImm", ASSEM_LVT1_SINT1,
INST_INCR_SCALAR1_IMM, 0, 1},
{"incrStk", ASSEM_1BYTE, INST_INCR_STK, 2, 1},
{"incrStkImm", ASSEM_SINT1, INST_INCR_STK_IMM, 1, 1},
{"infoLevelArgs", ASSEM_1BYTE, INST_INFO_LEVEL_ARGS, 1, 1},
{"infoLevelNumber", ASSEM_1BYTE, INST_INFO_LEVEL_NUM, 0, 1},
{"invokeStk", ASSEM_INVOKE, (INST_INVOKE_STK1 << 8
| INST_INVOKE_STK4), INT_MIN,1},
{"jump", ASSEM_JUMP, INST_JUMP1, 0, 0},
{"jump4", ASSEM_JUMP4, INST_JUMP4, 0, 0},
{"jumpFalse", ASSEM_JUMP, INST_JUMP_FALSE1, 1, 0},
{"jumpFalse4", ASSEM_JUMP4, INST_JUMP_FALSE4, 1, 0},
{"jumpTable", ASSEM_JUMPTABLE,INST_JUMP_TABLE, 1, 0},
{"jumpTrue", ASSEM_JUMP, INST_JUMP_TRUE1, 1, 0},
{"jumpTrue4", ASSEM_JUMP4, INST_JUMP_TRUE4, 1, 0},
{"label", ASSEM_LABEL, 0, 0, 0},
{"lappend", ASSEM_LVT, (INST_LAPPEND_SCALAR1<<8
| INST_LAPPEND_SCALAR4),
1, 1},
{"lappendArray", ASSEM_LVT, (INST_LAPPEND_ARRAY1<<8
| INST_LAPPEND_ARRAY4),2, 1},
{"lappendArrayStk", ASSEM_1BYTE, INST_LAPPEND_ARRAY_STK, 3, 1},
{"lappendList", ASSEM_LVT4, INST_LAPPEND_LIST, 1, 1},
{"lappendListArray",ASSEM_LVT4, INST_LAPPEND_LIST_ARRAY,2, 1},
{"lappendListArrayStk", ASSEM_1BYTE,INST_LAPPEND_LIST_ARRAY_STK, 3, 1},
{"lappendListStk", ASSEM_1BYTE, INST_LAPPEND_LIST_STK, 2, 1},
{"lappendStk", ASSEM_1BYTE, INST_LAPPEND_STK, 2, 1},
{"le", ASSEM_1BYTE, INST_LE, 2, 1},
{"lindexMulti", ASSEM_LINDEX_MULTI,
INST_LIST_INDEX_MULTI, INT_MIN,1},
{"list", ASSEM_LIST, INST_LIST, INT_MIN,1},
{"listConcat", ASSEM_1BYTE, INST_LIST_CONCAT, 2, 1},
{"listIn", ASSEM_1BYTE, INST_LIST_IN, 2, 1},
{"listIndex", ASSEM_1BYTE, INST_LIST_INDEX, 2, 1},
{"listIndexImm", ASSEM_INDEX, INST_LIST_INDEX_IMM, 1, 1},
{"listLength", ASSEM_1BYTE, INST_LIST_LENGTH, 1, 1},
{"listNotIn", ASSEM_1BYTE, INST_LIST_NOT_IN, 2, 1},
{"load", ASSEM_LVT, (INST_LOAD_SCALAR1 << 8
| INST_LOAD_SCALAR4), 0, 1},
{"loadArray", ASSEM_LVT, (INST_LOAD_ARRAY1<<8
| INST_LOAD_ARRAY4), 1, 1},
{"loadArrayStk", ASSEM_1BYTE, INST_LOAD_ARRAY_STK, 2, 1},
{"loadStk", ASSEM_1BYTE, INST_LOAD_STK, 1, 1},
{"lsetFlat", ASSEM_LSET_FLAT,INST_LSET_FLAT, INT_MIN,1},
{"lsetList", ASSEM_1BYTE, INST_LSET_LIST, 3, 1},
{"lshift", ASSEM_1BYTE, INST_LSHIFT, 2, 1},
{"lt", ASSEM_1BYTE, INST_LT, 2, 1},
{"mod", ASSEM_1BYTE, INST_MOD, 2, 1},
{"mult", ASSEM_1BYTE, INST_MULT, 2, 1},
{"neq", ASSEM_1BYTE, INST_NEQ, 2, 1},
{"nop", ASSEM_1BYTE, INST_NOP, 0, 0},
{"not", ASSEM_1BYTE, INST_LNOT, 1, 1},
{"nsupvar", ASSEM_LVT4, INST_NSUPVAR, 2, 1},
{"numericType", ASSEM_1BYTE, INST_NUM_TYPE, 1, 1},
{"originCmd", ASSEM_1BYTE, INST_ORIGIN_COMMAND, 1, 1},
{"over", ASSEM_OVER, INST_OVER, INT_MIN,-1-1},
{"pop", ASSEM_1BYTE, INST_POP, 1, 0},
{"pushReturnCode", ASSEM_1BYTE, INST_PUSH_RETURN_CODE, 0, 1},
{"pushReturnOpts", ASSEM_1BYTE, INST_PUSH_RETURN_OPTIONS,
0, 1},
{"pushResult", ASSEM_1BYTE, INST_PUSH_RESULT, 0, 1},
{"regexp", ASSEM_REGEXP, INST_REGEXP, 2, 1},
{"resolveCmd", ASSEM_1BYTE, INST_RESOLVE_COMMAND, 1, 1},
{"reverse", ASSEM_REVERSE, INST_REVERSE, INT_MIN,-1-0},
{"rshift", ASSEM_1BYTE, INST_RSHIFT, 2, 1},
{"store", ASSEM_LVT, (INST_STORE_SCALAR1<<8
| INST_STORE_SCALAR4), 1, 1},
{"storeArray", ASSEM_LVT, (INST_STORE_ARRAY1<<8
| INST_STORE_ARRAY4), 2, 1},
{"storeArrayStk", ASSEM_1BYTE, INST_STORE_ARRAY_STK, 3, 1},
{"storeStk", ASSEM_1BYTE, INST_STORE_STK, 2, 1},
{"strcaseLower", ASSEM_1BYTE, INST_STR_LOWER, 1, 1},
{"strcaseTitle", ASSEM_1BYTE, INST_STR_TITLE, 1, 1},
{"strcaseUpper", ASSEM_1BYTE, INST_STR_UPPER, 1, 1},
{"strcmp", ASSEM_1BYTE, INST_STR_CMP, 2, 1},
{"strcat", ASSEM_CONCAT1, INST_STR_CONCAT1, INT_MIN,1},
|
| ︙ | ︙ | |||
469 470 471 472 473 474 475 |
{"strrange", ASSEM_1BYTE, INST_STR_RANGE, 3, 1},
{"strreplace", ASSEM_1BYTE, INST_STR_REPLACE, 4, 1},
{"strrfind", ASSEM_1BYTE, INST_STR_FIND_LAST, 2, 1},
{"strtrim", ASSEM_1BYTE, INST_STR_TRIM, 2, 1},
{"strtrimLeft", ASSEM_1BYTE, INST_STR_TRIM_LEFT, 2, 1},
{"strtrimRight", ASSEM_1BYTE, INST_STR_TRIM_RIGHT, 2, 1},
{"sub", ASSEM_1BYTE, INST_SUB, 2, 1},
| < < | | | | | | | | | | | | | | > | | | > | | | | | | < < | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
{"strrange", ASSEM_1BYTE, INST_STR_RANGE, 3, 1},
{"strreplace", ASSEM_1BYTE, INST_STR_REPLACE, 4, 1},
{"strrfind", ASSEM_1BYTE, INST_STR_FIND_LAST, 2, 1},
{"strtrim", ASSEM_1BYTE, INST_STR_TRIM, 2, 1},
{"strtrimLeft", ASSEM_1BYTE, INST_STR_TRIM_LEFT, 2, 1},
{"strtrimRight", ASSEM_1BYTE, INST_STR_TRIM_RIGHT, 2, 1},
{"sub", ASSEM_1BYTE, INST_SUB, 2, 1},
{"tclooClass", ASSEM_1BYTE, INST_TCLOO_CLASS, 1, 1},
{"tclooIsObject", ASSEM_1BYTE, INST_TCLOO_IS_OBJECT, 1, 1},
{"tclooNamespace", ASSEM_1BYTE, INST_TCLOO_NS, 1, 1},
{"tclooSelf", ASSEM_1BYTE, INST_TCLOO_SELF, 0, 1},
{"tryCvtToBoolean", ASSEM_1BYTE, INST_TRY_CVT_TO_BOOLEAN,1, 2},
{"tryCvtToNumeric", ASSEM_1BYTE, INST_TRY_CVT_TO_NUMERIC,1, 1},
{"uminus", ASSEM_1BYTE, INST_UMINUS, 1, 1},
{"unset", ASSEM_BOOL_LVT4,INST_UNSET_SCALAR, 0, 0},
{"unsetArray", ASSEM_BOOL_LVT4,INST_UNSET_ARRAY, 1, 0},
{"unsetArrayStk", ASSEM_BOOL, INST_UNSET_ARRAY_STK, 2, 0},
{"unsetStk", ASSEM_BOOL, INST_UNSET_STK, 1, 0},
{"uplus", ASSEM_1BYTE, INST_UPLUS, 1, 1},
{"upvar", ASSEM_LVT4, INST_UPVAR, 2, 1},
{"variable", ASSEM_LVT4, INST_VARIABLE, 1, 0},
{"verifyDict", ASSEM_1BYTE, INST_DICT_VERIFY, 1, 0},
{"yield", ASSEM_1BYTE, INST_YIELD, 1, 1},
{NULL, ASSEM_1BYTE, 0, 0, 0}
};
/*
* List of instructions that cannot throw an exception under any
* circumstances. These instructions are the ones that are permissible after
* an exception is caught but before the corresponding exception range is
* popped from the stack.
* The instructions must be in ascending order by numeric operation code.
*/
static const unsigned char NonThrowingByteCodes[] = {
INST_PUSH1, INST_PUSH4, INST_POP, INST_DUP, /* 1-4 */
INST_JUMP1, INST_JUMP4, /* 34-35 */
INST_END_CATCH, INST_PUSH_RESULT, INST_PUSH_RETURN_CODE, /* 70-72 */
INST_STR_EQ, INST_STR_NEQ, INST_STR_CMP, INST_STR_LEN, /* 73-76 */
INST_LIST, /* 79 */
INST_OVER, /* 95 */
INST_PUSH_RETURN_OPTIONS, /* 108 */
INST_REVERSE, /* 126 */
INST_NOP, /* 132 */
INST_STR_MAP, /* 143 */
INST_STR_FIND, /* 144 */
INST_COROUTINE_NAME, /* 149 */
INST_NS_CURRENT, /* 151 */
INST_INFO_LEVEL_NUM, /* 152 */
INST_RESOLVE_COMMAND, /* 154 */
INST_STR_TRIM, INST_STR_TRIM_LEFT, INST_STR_TRIM_RIGHT, /* 166-168 */
INST_CONCAT_STK, /* 169 */
INST_STR_UPPER, INST_STR_LOWER, INST_STR_TITLE, /* 170-172 */
INST_NUM_TYPE, /* 180 */
INST_STR_LT, INST_STR_GT, INST_STR_LE, INST_STR_GE /* 191-194 */
};
/*
* Helper macros.
*/
#if defined(TCL_DEBUG_ASSEMBLY) && defined(__GNUC__) && __GNUC__ > 2
|
| ︙ | ︙ | |||
665 666 667 668 669 670 671 |
int op = TalInstructionTable[tblIdx].tclInstCode & 0xFF;
/*
* If this is the first instruction in a basic block, record its line
* number.
*/
| | < < < < < < < < < < < | < | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
int op = TalInstructionTable[tblIdx].tclInstCode & 0xFF;
/*
* If this is the first instruction in a basic block, record its line
* number.
*/
if (bbPtr->startOffset == envPtr->codeNext - envPtr->codeStart) {
bbPtr->startLine = assemEnvPtr->cmdLine;
}
TclEmitInt1(op, envPtr);
TclUpdateAtCmdStart(op, envPtr);
BBUpdateStackReqs(bbPtr, tblIdx, count);
}
|
| ︙ | ︙ | |||
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
BBEmitOpcode(assemEnvPtr, tblIdx, count);
TclEmitInt4(opnd, assemEnvPtr->envPtr);
}
/*
*-----------------------------------------------------------------------------
*
* Tcl_AssembleObjCmd, TclNRAssembleObjCmd --
*
* Direct evaluation path for tcl::unsupported::assemble
*
* Results:
* Returns a standard Tcl result.
*
* Side effects:
* Assembles the code in objv[1], and executes it, so side effects
* include whatever the code does.
*
*-----------------------------------------------------------------------------
*/
int
Tcl_AssembleObjCmd(
void *clientData, /* clientData */
Tcl_Interp *interp, /* Current interpreter. */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | | > > > | | | > > | 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 |
BBEmitOpcode(assemEnvPtr, tblIdx, count);
TclEmitInt4(opnd, assemEnvPtr->envPtr);
}
/*
*-----------------------------------------------------------------------------
*
* BBEmitInst1or4 --
*
* Emits a 1- or 4-byte operation according to the magnitude of the
* operand.
*
*-----------------------------------------------------------------------------
*/
static void
BBEmitInst1or4(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
int tblIdx, /* Index in TalInstructionTable of op */
int param, /* Variable-length parameter */
int count) /* Arity if variadic */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr = assemEnvPtr->curr_bb;
/* Current basic block */
int op = TalInstructionTable[tblIdx].tclInstCode;
if (param <= 0xFF) {
op >>= 8;
} else {
op &= 0xFF;
}
TclEmitInt1(op, envPtr);
if (param <= 0xFF) {
TclEmitInt1(param, envPtr);
} else {
TclEmitInt4(param, envPtr);
}
TclUpdateAtCmdStart(op, envPtr);
BBUpdateStackReqs(bbPtr, tblIdx, count);
}
/*
*-----------------------------------------------------------------------------
*
* Tcl_AssembleObjCmd, TclNRAssembleObjCmd --
*
* Direct evaluation path for tcl::unsupported::assemble
*
* Results:
* Returns a standard Tcl result.
*
* Side effects:
* Assembles the code in objv[1], and executes it, so side effects
* include whatever the code does.
*
*-----------------------------------------------------------------------------
*/
int
Tcl_AssembleObjCmd(
void *clientData, /* clientData */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
/*
* Boilerplate - make sure that there is an NRE trampoline on the C stack
* because there needs to be one in place to execute bytecode.
*/
return Tcl_NRCallObjProc(interp, TclNRAssembleObjCmd, clientData, objc, objv);
}
int
TclNRAssembleObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
ByteCode *codePtr; /* Pointer to the bytecode to execute */
Tcl_Obj* backtrace; /* Object where extra error information is
* constructed. */
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "bytecodeList");
return TCL_ERROR;
}
/*
* Assemble the source to bytecode.
*/
codePtr = CompileAssembleObj(interp, objv[1]);
/*
* On failure, report error line.
*/
if (codePtr == NULL) {
Tcl_AddErrorInfo(interp, "\n (\"");
Tcl_AppendObjToErrorInfo(interp, objv[0]);
Tcl_AddErrorInfo(interp, "\" body, line ");
TclNewIntObj(backtrace, Tcl_GetErrorLine(interp));
Tcl_AppendObjToErrorInfo(interp, backtrace);
Tcl_AddErrorInfo(interp, ")");
return TCL_ERROR;
}
/*
* Use NRE to evaluate the bytecode from the trampoline.
*/
|
| ︙ | ︙ | |||
910 911 912 913 914 915 916 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Token *tokenPtr; /* Token in the input script */
| > | | | < < < < | 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Token *tokenPtr; /* Token in the input script */
size_t numCommands = envPtr->numCommands;
int offset = envPtr->codeNext - envPtr->codeStart;
size_t depth = envPtr->currStackDepth;
/*
* Make sure that the command has a single arg that is a simple word.
*/
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
943 944 945 946 947 948 949 | Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (\"%.*s\" body, line %d)", (int)parsePtr->tokenPtr->size, parsePtr->tokenPtr->start, Tcl_GetErrorLine(interp))); envPtr->numCommands = numCommands; envPtr->codeNext = envPtr->codeStart + offset; envPtr->currStackDepth = depth; | < < < < < < < < < < < | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (\"%.*s\" body, line %d)",
(int)parsePtr->tokenPtr->size, parsePtr->tokenPtr->start,
Tcl_GetErrorLine(interp)));
envPtr->numCommands = numCommands;
envPtr->codeNext = envPtr->codeStart + offset;
envPtr->currStackDepth = depth;
TclCompileSyntaxError(interp, envPtr);
}
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
|
| ︙ | ︙ | |||
983 984 985 986 987 988 989 |
*/
static int
TclAssembleCode(
CompileEnv *envPtr, /* Compilation environment that is to receive
* the generated bytecode */
const char* codePtr, /* Assembly-language code to be processed */
| | | < | | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 |
*/
static int
TclAssembleCode(
CompileEnv *envPtr, /* Compilation environment that is to receive
* the generated bytecode */
const char* codePtr, /* Assembly-language code to be processed */
int codeLen, /* Length of the code */
int flags) /* OR'ed combination of flags */
{
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
/*
* Walk through the assembly script using the Tcl parser. Each 'command'
* will be an instruction or assembly directive.
*/
const char* instPtr = codePtr;
/* Where to start looking for a line of code */
const char* nextPtr; /* Pointer to the end of the line of code */
int bytesLeft = codeLen; /* Number of bytes of source code remaining to
* be parsed */
int status; /* Tcl status return */
AssemblyEnv* assemEnvPtr = NewAssemblyEnv(envPtr, flags);
Tcl_Parse* parsePtr = assemEnvPtr->parsePtr;
do {
/*
|
| ︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | } /* * If tracing, show each line assembled as it happens. */ #ifdef TCL_COMPILE_DEBUG | | < | | 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 |
}
/*
* If tracing, show each line assembled as it happens.
*/
#ifdef TCL_COMPILE_DEBUG
if ((tclTraceCompile >= 2) && (envPtr->procPtr == NULL)) {
printf(" %4" TCL_Z_MODIFIER "d Assembling: ",
envPtr->codeNext - envPtr->codeStart);
TclPrintSource(stdout, parsePtr->commandStart,
TclMin(instLen, 55));
printf("\n");
}
#endif
if (AssembleOneLine(assemEnvPtr) != TCL_OK) {
if (flags & TCL_EVAL_DIRECT) {
|
| ︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 |
static AssemblyEnv*
NewAssemblyEnv(
CompileEnv* envPtr, /* Compilation environment being used for code
* generation*/
int flags) /* Compilation flags (TCL_EVAL_DIRECT) */
{
| | | < | 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 |
static AssemblyEnv*
NewAssemblyEnv(
CompileEnv* envPtr, /* Compilation environment being used for code
* generation*/
int flags) /* Compilation flags (TCL_EVAL_DIRECT) */
{
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
AssemblyEnv* assemEnvPtr = (AssemblyEnv*)TclStackAlloc(interp, sizeof(AssemblyEnv));
/* Assembler environment under construction */
Tcl_Parse* parsePtr = (Tcl_Parse*)TclStackAlloc(interp, sizeof(Tcl_Parse));
/* Parse of one line of assembly code */
assemEnvPtr->envPtr = envPtr;
assemEnvPtr->parsePtr = parsePtr;
assemEnvPtr->cmdLine = 1;
|
| ︙ | ︙ | |||
1164 1165 1166 1167 1168 1169 1170 |
static void
FreeAssemblyEnv(
AssemblyEnv* assemEnvPtr) /* Environment to free */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment being used for code
* generation */
| | | | < | 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
static void
FreeAssemblyEnv(
AssemblyEnv* assemEnvPtr) /* Environment to free */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment being used for code
* generation */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
BasicBlock* thisBB; /* Pointer to a basic block being deleted */
BasicBlock* nextBB; /* Pointer to a deleted basic block's
* successor */
/*
* Free all the basic block structures.
*/
for (thisBB = assemEnvPtr->head_bb; thisBB != NULL; thisBB = nextBB) {
if (thisBB->jumpTarget != NULL) {
Tcl_DecrRefCount(thisBB->jumpTarget);
}
if (thisBB->foreignExceptions != NULL) {
Tcl_Free(thisBB->foreignExceptions);
}
nextBB = thisBB->successor1;
if (thisBB->jtPtr != NULL) {
DeleteMirrorJumpTable(thisBB->jtPtr);
thisBB->jtPtr = NULL;
}
Tcl_Free(thisBB);
}
/*
* Dispose what's left.
*/
|
| ︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 |
static int
AssembleOneLine(
AssemblyEnv* assemEnvPtr) /* State of the assembly */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment being used for code
* gen */
| | | | | | > | | 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 |
static int
AssembleOneLine(
AssemblyEnv* assemEnvPtr) /* State of the assembly */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment being used for code
* gen */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
Tcl_Parse* parsePtr = assemEnvPtr->parsePtr;
/* Parse of the line of code */
Tcl_Token* tokenPtr; /* Current token within the line of code */
Tcl_Obj* instNameObj; /* Name of the instruction */
int tblIdx; /* Index in TalInstructionTable of the
* instruction */
TalInstType instType; /* Type of the instruction */
Tcl_Obj* operand1Obj = NULL;
/* First operand to the instruction */
const char* operand1; /* String rep of the operand */
Tcl_Size operand1Len; /* String length of the operand */
int opnd; /* Integer representation of an operand */
int litIndex; /* Literal pool index of a constant */
Tcl_Size localVar; /* LVT index of a local variable */
int flags; /* Flags for a basic block */
JumptableInfo* jtPtr; /* Pointer to a jumptable */
int infoIndex; /* Index of the jumptable in auxdata */
int status = TCL_ERROR; /* Return value from this function */
/*
* Make sure that the instruction name is known at compile time.
*/
tokenPtr = parsePtr->tokenPtr;
|
| ︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 |
goto cleanup;
}
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
operand1 = TclGetStringFromObj(operand1Obj, &operand1Len);
litIndex = TclRegisterLiteral(envPtr, operand1, operand1Len, 0);
| | | 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 |
goto cleanup;
}
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
operand1 = TclGetStringFromObj(operand1Obj, &operand1Len);
litIndex = TclRegisterLiteral(envPtr, operand1, operand1Len, 0);
BBEmitInst1or4(assemEnvPtr, tblIdx, litIndex, 0);
break;
case ASSEM_1BYTE:
if (parsePtr->numWords != 1) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "");
goto cleanup;
}
|
| ︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 |
Tcl_WrongNumArgs(interp, 1, &instNameObj, "label");
goto cleanup;
}
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
assemEnvPtr->curr_bb->jumpLine = assemEnvPtr->cmdLine;
| | | | 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 |
Tcl_WrongNumArgs(interp, 1, &instNameObj, "label");
goto cleanup;
}
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
assemEnvPtr->curr_bb->jumpLine = assemEnvPtr->cmdLine;
assemEnvPtr->curr_bb->jumpOffset = envPtr->codeNext-envPtr->codeStart;
BBEmitInstInt4(assemEnvPtr, tblIdx, 0, 0);
assemEnvPtr->curr_bb->flags |= BB_BEGINCATCH;
StartBasicBlock(assemEnvPtr, BB_FALLTHRU, operand1Obj);
break;
case ASSEM_BOOL:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "boolean");
goto cleanup;
}
if (GetBooleanOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
BBEmitInstInt1(assemEnvPtr, tblIdx, opnd, 0);
break;
case ASSEM_BOOL_LVT4:
if (parsePtr->numWords != 3) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "boolean varName");
goto cleanup;
}
if (GetBooleanOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
|
| ︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 |
Tcl_WrongNumArgs(interp, 1, &instNameObj, "imm8");
goto cleanup;
}
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
if (opnd < 0 || opnd > 3) {
| | | | 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 |
Tcl_WrongNumArgs(interp, 1, &instNameObj, "imm8");
goto cleanup;
}
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
if (opnd < 0 || opnd > 3) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("operand must be [0..3]", -1));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "OPERAND<0,>3", (char *)NULL);
goto cleanup;
}
BBEmitInstInt1(assemEnvPtr, tblIdx, opnd, opnd);
break;
case ASSEM_CONCAT1:
|
| ︙ | ︙ | |||
1449 1450 1451 1452 1453 1454 1455 | operand1 = TclGetStringFromObj(operand1Obj, &operand1Len); litIndex = TclRegisterLiteral(envPtr, operand1, operand1Len, 0); /* * Assumes that PUSH is the first slot! */ | | | > | > > > > | | > | < < < < < | < < < < < < < | < < > | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < | 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 |
operand1 = TclGetStringFromObj(operand1Obj, &operand1Len);
litIndex = TclRegisterLiteral(envPtr, operand1, operand1Len, 0);
/*
* Assumes that PUSH is the first slot!
*/
BBEmitInst1or4(assemEnvPtr, 0, litIndex, 0);
BBEmitOpcode(assemEnvPtr, tblIdx, 0);
}
break;
case ASSEM_INVOKE:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "count");
goto cleanup;
}
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
|| CheckStrictlyPositive(interp, opnd) != TCL_OK) {
goto cleanup;
}
BBEmitInst1or4(assemEnvPtr, tblIdx, opnd, opnd);
break;
case ASSEM_JUMP:
case ASSEM_JUMP4:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "label");
goto cleanup;
}
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
assemEnvPtr->curr_bb->jumpOffset = envPtr->codeNext-envPtr->codeStart;
if (instType == ASSEM_JUMP) {
flags = BB_JUMP1;
BBEmitInstInt1(assemEnvPtr, tblIdx, 0, 0);
} else {
flags = 0;
BBEmitInstInt4(assemEnvPtr, tblIdx, 0, 0);
}
/*
* Start a new basic block at the instruction following the jump.
*/
assemEnvPtr->curr_bb->jumpLine = assemEnvPtr->cmdLine;
if (TalInstructionTable[tblIdx].operandsConsumed != 0) {
flags |= BB_FALLTHRU;
}
StartBasicBlock(assemEnvPtr, flags, operand1Obj);
break;
case ASSEM_JUMPTABLE:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "table");
goto cleanup;
}
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
goto cleanup;
}
jtPtr = (JumptableInfo*)Tcl_Alloc(sizeof(JumptableInfo));
Tcl_InitHashTable(&jtPtr->hashTable, TCL_STRING_KEYS);
assemEnvPtr->curr_bb->jumpLine = assemEnvPtr->cmdLine;
assemEnvPtr->curr_bb->jumpOffset = envPtr->codeNext-envPtr->codeStart;
DEBUG_PRINT("bb %p jumpLine %d jumpOffset %d\n",
assemEnvPtr->curr_bb, assemEnvPtr->cmdLine,
envPtr->codeNext - envPtr->codeStart);
infoIndex = TclCreateAuxData(jtPtr, &tclJumptableInfoType, envPtr);
DEBUG_PRINT("auxdata index=%d\n", infoIndex);
BBEmitInstInt4(assemEnvPtr, tblIdx, infoIndex, 0);
if (CreateMirrorJumpTable(assemEnvPtr, operand1Obj) != TCL_OK) {
goto cleanup;
}
StartBasicBlock(assemEnvPtr, BB_JUMPTABLE|BB_FALLTHRU, NULL);
break;
case ASSEM_LABEL:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "name");
goto cleanup;
}
if (GetNextOperand(assemEnvPtr, &tokenPtr, &operand1Obj) != TCL_OK) {
|
| ︙ | ︙ | |||
1613 1614 1615 1616 1617 1618 1619 |
goto cleanup;
}
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
if (opnd < 2) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
| | | > > > > > > > > > > > > > > > > > > > > > > > > | | | < | | | 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 |
goto cleanup;
}
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
if (opnd < 2) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("operand must be >=2", -1));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "OPERAND>=2", (char *)NULL);
}
goto cleanup;
}
BBEmitInstInt4(assemEnvPtr, tblIdx, opnd, opnd);
break;
case ASSEM_LVT:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
goto cleanup;
}
localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
if (localVar < 0) {
goto cleanup;
}
BBEmitInst1or4(assemEnvPtr, tblIdx, localVar, 0);
break;
case ASSEM_LVT1:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
goto cleanup;
}
localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
if (localVar < 0 || CheckOneByte(interp, localVar)) {
goto cleanup;
}
BBEmitInstInt1(assemEnvPtr, tblIdx, localVar, 0);
break;
case ASSEM_LVT1_SINT1:
if (parsePtr->numWords != 3) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "varName imm8");
goto cleanup;
}
localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
if (localVar < 0 || CheckOneByte(interp, localVar)
|| GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
|| CheckSignedOneByte(interp, opnd)) {
goto cleanup;
}
BBEmitInstInt1(assemEnvPtr, tblIdx, localVar, 0);
TclEmitInt1(opnd, envPtr);
break;
case ASSEM_LVT4:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "varname");
goto cleanup;
}
localVar = FindLocalVar(assemEnvPtr, &tokenPtr);
if (localVar < 0) {
goto cleanup;
}
BBEmitInstInt4(assemEnvPtr, tblIdx, localVar, 0);
|
| ︙ | ︙ | |||
1670 1671 1672 1673 1674 1675 1676 |
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "boolean");
goto cleanup;
}
if (GetBooleanOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
| > | < > | 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 |
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "boolean");
goto cleanup;
}
if (GetBooleanOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
{
BBEmitInstInt1(assemEnvPtr, tblIdx, TCL_REG_ADVANCED | (opnd ? TCL_REG_NOCASE : 0), 0);
}
break;
case ASSEM_REVERSE:
if (parsePtr->numWords != 2) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "count");
goto cleanup;
}
|
| ︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 |
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
|| CheckSignedOneByte(interp, opnd) != TCL_OK) {
goto cleanup;
}
BBEmitInstInt1(assemEnvPtr, tblIdx, opnd, 0);
break;
| | | 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 |
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK
|| CheckSignedOneByte(interp, opnd) != TCL_OK) {
goto cleanup;
}
BBEmitInstInt1(assemEnvPtr, tblIdx, opnd, 0);
break;
case ASSEM_SINT4_LVT4:
if (parsePtr->numWords != 3) {
Tcl_WrongNumArgs(interp, 1, &instNameObj, "count varName");
goto cleanup;
}
if (GetIntegerOperand(assemEnvPtr, &tokenPtr, &opnd) != TCL_OK) {
goto cleanup;
}
|
| ︙ | ︙ | |||
1720 1721 1722 1723 1724 1725 1726 |
default:
Tcl_Panic("Instruction \"%s\" could not be found, can't happen\n",
TclGetString(instNameObj));
}
status = TCL_OK;
| | | 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 |
default:
Tcl_Panic("Instruction \"%s\" could not be found, can't happen\n",
TclGetString(instNameObj));
}
status = TCL_OK;
cleanup:
Tcl_DecrRefCount(instNameObj);
if (operand1Obj) {
Tcl_DecrRefCount(operand1Obj);
}
return status;
}
|
| ︙ | ︙ | |||
1763 1764 1765 1766 1767 1768 1769 |
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token* tokenPtr, /* Tcl_Token containing the script */
const TalInstDesc* instPtr) /* Instruction that determines whether
* the script is 'expr' or 'eval' */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
| | | | | 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 |
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token* tokenPtr, /* Tcl_Token containing the script */
const TalInstDesc* instPtr) /* Instruction that determines whether
* the script is 'expr' or 'eval' */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
/*
* The expression or script is not only known at compile time, but
* actually a "simple word". It can be compiled inline by invoking the
* compiler recursively.
*
* Save away the stack depth and reset it before compiling the script.
* We'll record the stack usage of the script in the BasicBlock, and
* accumulate it together with the stack usage of the enclosing assembly
* code.
*/
size_t savedStackDepth = envPtr->currStackDepth;
size_t savedMaxStackDepth = envPtr->maxStackDepth;
int savedExceptArrayNext = envPtr->exceptArrayNext;
envPtr->currStackDepth = 0;
envPtr->maxStackDepth = 0;
StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);
switch (instPtr->tclInstCode) {
case INST_EVAL_STK:
TclCompileScript(interp, tokenPtr->start, tokenPtr->size, envPtr);
break;
case INST_EXPR_STK:
TclCompileExpr(interp, tokenPtr->start, tokenPtr->size, envPtr, 1);
break;
default:
Tcl_Panic("no ASSEM_EVAL case for %s (%d), can't happen",
instPtr->name, instPtr->tclInstCode);
}
/*
|
| ︙ | ︙ | |||
1845 1846 1847 1848 1849 1850 1851 |
SyncStackDepth(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* curr_bb = assemEnvPtr->curr_bb;
/* Current basic block */
| | | 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 |
SyncStackDepth(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* curr_bb = assemEnvPtr->curr_bb;
/* Current basic block */
int maxStackDepth = curr_bb->finalStackDepth + envPtr->maxStackDepth;
/* Max stack depth in the basic block */
if (maxStackDepth > curr_bb->maxStackDepth) {
curr_bb->maxStackDepth = maxStackDepth;
}
curr_bb->finalStackDepth += envPtr->currStackDepth;
}
|
| ︙ | ︙ | |||
1870 1871 1872 1873 1874 1875 1876 |
*
*-----------------------------------------------------------------------------
*/
static void
MoveExceptionRangesToBasicBlock(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
| < | | | | | | 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 |
*
*-----------------------------------------------------------------------------
*/
static void
MoveExceptionRangesToBasicBlock(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
int savedExceptArrayNext) /* Saved index of the end of the exception
* range array */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* curr_bb = assemEnvPtr->curr_bb;
/* Current basic block */
int exceptionCount = envPtr->exceptArrayNext - savedExceptArrayNext;
/* Number of ranges that must be moved */
int i;
if (exceptionCount == 0) {
/* Nothing to do */
return;
}
/*
* Save the exception ranges in the basic block. They will be re-added at
* the conclusion of assembly; at this time, the INST_BEGIN_CATCH
* instructions in the block will be adjusted from whatever range indices
* they have [savedExceptArrayNext .. envPtr->exceptArrayNext) to the
* indices that the exceptions acquire. The saved exception ranges are
* converted to a relative nesting depth. The depth will be recomputed
* once flow analysis has determined the actual stack depth of the block.
*/
DEBUG_PRINT("basic block %p has %d exceptions starting at %d\n",
curr_bb, exceptionCount, savedExceptArrayNext);
curr_bb->foreignExceptionBase = savedExceptArrayNext;
curr_bb->foreignExceptionCount = exceptionCount;
curr_bb->foreignExceptions =
(ExceptionRange*)Tcl_Alloc(exceptionCount * sizeof(ExceptionRange));
memcpy(curr_bb->foreignExceptions,
envPtr->exceptArrayPtr + savedExceptArrayNext,
exceptionCount * sizeof(ExceptionRange));
for (i = 0; i < exceptionCount; ++i) {
curr_bb->foreignExceptions[i].nestingLevel -= envPtr->exceptDepth;
}
envPtr->exceptArrayNext = savedExceptArrayNext;
|
| ︙ | ︙ | |||
1928 1929 1930 1931 1932 1933 1934 | * interpreter on error. * * Side effects: * Initializes the jump table pointer in the current basic block to a * JumptableInfo. The keys in the JumptableInfo are the comparison * strings. The values, instead of being jump displacements, are * Tcl_Obj's with the code labels. | | | < > > | | < | > | > > > > > > > > > > > > > > > > | < > | > | < | | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < > | | < < | | | | | | | | | < < < < < < < < < < < < < | 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 |
* interpreter on error.
*
* Side effects:
* Initializes the jump table pointer in the current basic block to a
* JumptableInfo. The keys in the JumptableInfo are the comparison
* strings. The values, instead of being jump displacements, are
* Tcl_Obj's with the code labels.
*/
static int
CreateMirrorJumpTable(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Obj* jumps) /* List of alternating keywords and labels */
{
Tcl_Size objc; /* Number of elements in the 'jumps' list */
Tcl_Obj** objv; /* Pointers to the elements in the list */
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
BasicBlock* bbPtr = assemEnvPtr->curr_bb;
/* Current basic block */
JumptableInfo* jtPtr;
Tcl_HashTable* jtHashPtr; /* Hashtable in the JumptableInfo */
Tcl_HashEntry* hashEntry; /* Entry for a key in the hashtable */
int isNew; /* Flag==1 if the key is not yet in the
* table. */
Tcl_Size i;
if (TclListObjLength(interp, jumps, &objc) != TCL_OK) {
return TCL_ERROR;
}
if (objc % 2 != 0) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"jump table must have an even number of list elements",
-1));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADJUMPTABLE", (char *)NULL);
}
return TCL_ERROR;
}
if (TclListObjGetElements(interp, jumps, &objc, &objv) != TCL_OK) {
return TCL_ERROR;
}
/*
* Allocate the jumptable.
*/
jtPtr = (JumptableInfo*)Tcl_Alloc(sizeof(JumptableInfo));
jtHashPtr = &jtPtr->hashTable;
Tcl_InitHashTable(jtHashPtr, TCL_STRING_KEYS);
/*
* Fill the keys and labels into the table.
*/
DEBUG_PRINT("jump table {\n");
for (i = 0; i < objc; i+=2) {
DEBUG_PRINT(" %s -> %s\n", TclGetString(objv[i]),
TclGetString(objv[i+1]));
hashEntry = Tcl_CreateHashEntry(jtHashPtr, TclGetString(objv[i]),
&isNew);
if (!isNew) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"duplicate entry in jump table for \"%s\"",
TclGetString(objv[i])));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "DUPJUMPTABLEENTRY", (char *)NULL);
DeleteMirrorJumpTable(jtPtr);
return TCL_ERROR;
}
}
Tcl_SetHashValue(hashEntry, objv[i+1]);
Tcl_IncrRefCount(objv[i+1]);
}
DEBUG_PRINT("}\n");
/*
* Put the mirror jumptable in the basic block struct.
*/
bbPtr->jtPtr = jtPtr;
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
*
* DeleteMirrorJumpTable --
*
* Cleans up a jump table when the basic block is deleted.
*
*-----------------------------------------------------------------------------
*/
static void
DeleteMirrorJumpTable(
JumptableInfo* jtPtr)
{
Tcl_HashTable* jtHashPtr = &jtPtr->hashTable;
/* Hash table pointer */
Tcl_HashSearch search; /* Hash search control */
Tcl_HashEntry* entry; /* Hash table entry containing a jump label */
Tcl_Obj* label; /* Jump label from the hash table */
for (entry = Tcl_FirstHashEntry(jtHashPtr, &search);
entry != NULL;
entry = Tcl_NextHashEntry(&search)) {
label = (Tcl_Obj*)Tcl_GetHashValue(entry);
Tcl_DecrRefCount(label);
Tcl_SetHashValue(entry, NULL);
}
Tcl_DeleteHashTable(jtHashPtr);
Tcl_Free(jtPtr);
}
/*
*-----------------------------------------------------------------------------
*
* GetNextOperand --
*
|
| ︙ | ︙ | |||
2145 2146 2147 2148 2149 2150 2151 | * Advances *tokenPtrPtr around the token just processed. * *----------------------------------------------------------------------------- */ static int GetNextOperand( | | | | | | | < | 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 |
* Advances *tokenPtrPtr around the token just processed.
*
*-----------------------------------------------------------------------------
*/
static int
GetNextOperand(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr, /* INPUT/OUTPUT: Pointer to the token holding
* the operand */
Tcl_Obj** operandObjPtr) /* OUTPUT: Tcl object holding the operand text
* with \-substitutions done. */
{
Tcl_Interp* interp = (Tcl_Interp*) assemEnvPtr->envPtr->iPtr;
Tcl_Obj* operandObj;
TclNewObj(operandObj);
if (!TclWordKnownAtCompileTime(*tokenPtrPtr, operandObj)) {
Tcl_DecrRefCount(operandObj);
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"assembly code may not contain substitutions", -1));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NOSUBST", (char *)NULL);
}
return TCL_ERROR;
}
*tokenPtrPtr = TokenAfter(*tokenPtrPtr);
Tcl_IncrRefCount(operandObj);
*operandObjPtr = operandObj;
|
| ︙ | ︙ | |||
2198 2199 2200 2201 2202 2203 2204 |
GetBooleanOperand(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr, /* Current token from the parser */
int* result) /* OUTPUT: Integer extracted from the token */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
| | | | 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 |
GetBooleanOperand(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr, /* Current token from the parser */
int* result) /* OUTPUT: Integer extracted from the token */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
Tcl_Token* tokenPtr = *tokenPtrPtr;
/* INOUT: Pointer to the next token in the
* source code */
Tcl_Obj* intObj; /* Integer from the source code */
int status; /* Tcl status return */
/*
* Extract the next token as a string.
*/
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {
|
| ︙ | ︙ | |||
2251 2252 2253 2254 2255 2256 2257 |
GetIntegerOperand(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr, /* Current token from the parser */
int* result) /* OUTPUT: Integer extracted from the token */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
| | | | 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 |
GetIntegerOperand(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr, /* Current token from the parser */
int* result) /* OUTPUT: Integer extracted from the token */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
Tcl_Token* tokenPtr = *tokenPtrPtr;
/* INOUT: Pointer to the next token in the
* source code */
Tcl_Obj* intObj; /* Integer from the source code */
int status; /* Tcl status return */
/*
* Extract the next token as a string.
*/
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &intObj) != TCL_OK) {
|
| ︙ | ︙ | |||
2302 2303 2304 2305 2306 2307 2308 |
static int
GetListIndexOperand(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr, /* Current token from the parser */
int* result) /* OUTPUT: encoded index derived from the token */
{
| | | | | 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 |
static int
GetListIndexOperand(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr, /* Current token from the parser */
int* result) /* OUTPUT: encoded index derived from the token */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
Tcl_Token* tokenPtr = *tokenPtrPtr;
/* INOUT: Pointer to the next token in the
* source code */
Tcl_Obj *value;
int status;
/* General operand validity check */
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &value) != TCL_OK) {
|
| ︙ | ︙ | |||
2354 2355 2356 2357 2358 2359 2360 | * has not yet been seen and the execution context allows for it. * *----------------------------------------------------------------------------- */ static size_t FindLocalVar( | | | | | | | | | | | 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 |
* has not yet been seen and the execution context allows for it.
*
*-----------------------------------------------------------------------------
*/
static size_t
FindLocalVar(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
Tcl_Token** tokenPtrPtr)
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
Tcl_Token* tokenPtr = *tokenPtrPtr;
/* INOUT: Pointer to the next token in the
* source code. */
Tcl_Obj* varNameObj; /* Name of the variable */
const char* varNameStr;
Tcl_Size varNameLen;
Tcl_Size localVar; /* Index of the variable in the LVT */
if (GetNextOperand(assemEnvPtr, tokenPtrPtr, &varNameObj) != TCL_OK) {
return TCL_INDEX_NONE;
}
varNameStr = TclGetStringFromObj(varNameObj, &varNameLen);
if (CheckNamespaceQualifiers(interp, varNameStr, varNameLen)) {
Tcl_DecrRefCount(varNameObj);
return TCL_INDEX_NONE;
}
localVar = TclFindCompiledLocal(varNameStr, varNameLen, 1, envPtr);
Tcl_DecrRefCount(varNameObj);
if (localVar < 0) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"cannot use this instruction to create a variable"
" in a non-proc context", -1));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "LVT", (char *)NULL);
}
return TCL_INDEX_NONE;
}
*tokenPtrPtr = TokenAfter(tokenPtr);
return localVar;
}
|
| ︙ | ︙ | |||
2409 2410 2411 2412 2413 2414 2415 | * an error message in the interpreter result. * *----------------------------------------------------------------------------- */ static int CheckNamespaceQualifiers( | | | | | | 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 |
* an error message in the interpreter result.
*
*-----------------------------------------------------------------------------
*/
static int
CheckNamespaceQualifiers(
Tcl_Interp* interp, /* Tcl interpreter for error reporting */
const char* name, /* Variable name to check */
int nameLen) /* Length of the variable */
{
const char* p;
for (p = name; p+2 < name+nameLen; p++) {
if ((*p == ':') && (p[1] == ':')) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"variable \"%s\" is not local", name));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NONLOCAL", name, (char *)NULL);
return TCL_ERROR;
|
| ︙ | ︙ | |||
2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 | * * Verify that a constant fits in a single byte in the instruction * stream. * * Results: * On success, returns TCL_OK. On failure, returns TCL_ERROR and stores * an error message in the interpreter result. * *----------------------------------------------------------------------------- */ static int CheckOneByte( | > > > > | | > > > | < | > | | > > > | < | 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 |
*
* Verify that a constant fits in a single byte in the instruction
* stream.
*
* Results:
* On success, returns TCL_OK. On failure, returns TCL_ERROR and stores
* an error message in the interpreter result.
*
* This code is here primarily to verify that instructions like INCR_SCALAR1
* are possible on a given local variable. The fact that there is no
* INCR_SCALAR4 is puzzling.
*
*-----------------------------------------------------------------------------
*/
static int
CheckOneByte(
Tcl_Interp* interp, /* Tcl interpreter for error reporting */
int value) /* Value to check */
{
Tcl_Obj* result; /* Error message */
if (value < 0 || value > 0xFF) {
result = Tcl_NewStringObj("operand does not fit in one byte", -1);
Tcl_SetObjResult(interp, result);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "1BYTE", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
*
* CheckSignedOneByte --
*
* Verify that a constant fits in a single signed byte in the instruction
* stream.
*
* Results:
* On success, returns TCL_OK. On failure, returns TCL_ERROR and stores
* an error message in the interpreter result.
*
* This code is here primarily to verify that instructions like INCR_SCALAR1
* are possible on a given local variable. The fact that there is no
* INCR_SCALAR4 is puzzling.
*
*-----------------------------------------------------------------------------
*/
static int
CheckSignedOneByte(
Tcl_Interp* interp, /* Tcl interpreter for error reporting */
int value) /* Value to check */
{
Tcl_Obj* result; /* Error message */
if (value > 0x7F || value < -0x80) {
result = Tcl_NewStringObj("operand does not fit in one byte", -1);
Tcl_SetObjResult(interp, result);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "1BYTE", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
2506 2507 2508 2509 2510 2511 2512 | * are consuming a positive number of operands * *----------------------------------------------------------------------------- */ static int CheckNonNegative( | | | > > | > | < | 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 |
* are consuming a positive number of operands
*
*-----------------------------------------------------------------------------
*/
static int
CheckNonNegative(
Tcl_Interp* interp, /* Tcl interpreter for error reporting */
int value) /* Value to check */
{
Tcl_Obj* result; /* Error message */
if (value < 0) {
result = Tcl_NewStringObj("operand must be nonnegative", -1);
Tcl_SetObjResult(interp, result);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NONNEGATIVE", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
2537 2538 2539 2540 2541 2542 2543 | * are consuming a positive number of operands * *----------------------------------------------------------------------------- */ static int CheckStrictlyPositive( | | | > > | > | < | 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 |
* are consuming a positive number of operands
*
*-----------------------------------------------------------------------------
*/
static int
CheckStrictlyPositive(
Tcl_Interp* interp, /* Tcl interpreter for error reporting */
int value) /* Value to check */
{
Tcl_Obj* result; /* Error message */
if (value <= 0) {
result = Tcl_NewStringObj("operand must be positive", -1);
Tcl_SetObjResult(interp, result);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "POSITIVE", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
2566 2567 2568 2569 2570 2571 2572 | * if a duplicate definition is found. * *----------------------------------------------------------------------------- */ static int DefineLabel( | | | | | | | 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 |
* if a duplicate definition is found.
*
*-----------------------------------------------------------------------------
*/
static int
DefineLabel(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
const char* labelName) /* Label being defined */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
Tcl_HashEntry* entry; /* Label's entry in the symbol table */
int isNew; /* Flag == 1 iff the label was previously
* undefined */
/* TODO - This can now be simplified! */
StartBasicBlock(assemEnvPtr, BB_FALLTHRU, NULL);
|
| ︙ | ︙ | |||
2627 2628 2629 2630 2631 2632 2633 |
*/
static BasicBlock*
StartBasicBlock(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
int flags, /* Flags to apply to the basic block being
* closed, if there is one. */
| | | | 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 |
*/
static BasicBlock*
StartBasicBlock(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
int flags, /* Flags to apply to the basic block being
* closed, if there is one. */
Tcl_Obj* jumpLabel) /* Label of the location that the block jumps
* to, or NULL if the block does not jump */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* newBB; /* BasicBlock structure for the new block */
BasicBlock* currBB = assemEnvPtr->curr_bb;
/*
* Coalesce zero-length blocks.
*/
if (currBB->startOffset == envPtr->codeNext - envPtr->codeStart) {
currBB->startLine = assemEnvPtr->cmdLine;
return currBB;
}
/*
* Make the new basic block.
*/
|
| ︙ | ︙ | |||
2695 2696 2697 2698 2699 2700 2701 |
static BasicBlock *
AllocBB(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
BasicBlock *bb = (BasicBlock*)Tcl_Alloc(sizeof(BasicBlock));
| > | < | 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 |
static BasicBlock *
AllocBB(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
BasicBlock *bb = (BasicBlock*)Tcl_Alloc(sizeof(BasicBlock));
bb->originalStartOffset =
bb->startOffset = envPtr->codeNext - envPtr->codeStart;
bb->startLine = assemEnvPtr->cmdLine + 1;
bb->jumpOffset = -1;
bb->jumpLine = -1;
bb->prevPtr = assemEnvPtr->curr_bb;
bb->predecessor = NULL;
bb->successor1 = NULL;
bb->jumpTarget = NULL;
bb->initialStackDepth = 0;
bb->minStackDepth = 0;
bb->maxStackDepth = 0;
bb->finalStackDepth = 0;
bb->catchDepth = 0;
bb->enclosingCatch = NULL;
bb->foreignExceptionBase = -1;
bb->foreignExceptionCount = 0;
bb->foreignExceptions = NULL;
bb->jtPtr = NULL;
bb->flags = 0;
return bb;
}
/*
*-----------------------------------------------------------------------------
|
| ︙ | ︙ | |||
2744 2745 2746 2747 2748 2749 2750 2751 |
*-----------------------------------------------------------------------------
*/
static int
FinishAssembly(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
/*
| > > > | > | > > > > > > > > | 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 |
*-----------------------------------------------------------------------------
*/
static int
FinishAssembly(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
int mustMove; /* Amount by which the code needs to be grown
* because of expanding jumps */
/*
* Resolve the targets of all jumps and determine whether code needs to be
* moved around.
*/
if (CalculateJumpRelocations(assemEnvPtr, &mustMove)) {
return TCL_ERROR;
}
/*
* Move the code if necessary.
*/
if (mustMove) {
MoveCodeForJumps(assemEnvPtr, mustMove);
}
/*
* Resolve jump target labels to bytecode offsets.
*/
FillInJumpOffsets(assemEnvPtr);
|
| ︙ | ︙ | |||
2794 2795 2796 2797 2798 2799 2800 |
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
*
| | | > > > > > > > > | > > | | > > > > > > > > > | > > > > | | | | > > > > > > > | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | > > | 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 |
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
*
* CalculateJumpRelocations --
*
* Calculate any movement that has to be done in the assembly code to
* expand JUMP1 instructions to JUMP4 (because they jump more than a
* 1-byte range).
*
* Results:
* Returns a standard Tcl result, with an appropriate error message if
* anything fails.
*
* Side effects:
* Sets the 'startOffset' pointer in every basic block to the new origin
* of the block, and turns off JUMP1 flags on instructions that must be
* expanded (and adjusts them to the corresponding JUMP4's). Does *not*
* store the jump offsets at this point.
*
* Sets *mustMove to 1 if and only if at least one instruction changed
* size so the code must be moved.
*
* As a side effect, also checks for undefined labels and reports them.
*
*-----------------------------------------------------------------------------
*/
static int
CalculateJumpRelocations(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
int* mustMove) /* OUTPUT: Number of bytes that have been
* added to the code */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr; /* Pointer to a basic block being checked */
Tcl_HashEntry* entry; /* Exit label's entry in the symbol table */
BasicBlock* jumpTarget; /* Basic block where the jump goes */
int motion; /* Amount by which the code has expanded */
int offset; /* Offset in the bytecode from a jump
* instruction to its target */
unsigned opcode; /* Opcode in the bytecode being adjusted */
/*
* Iterate through basic blocks as long as a change results in code
* expansion.
*/
*mustMove = 0;
do {
motion = 0;
for (bbPtr = assemEnvPtr->head_bb;
bbPtr != NULL;
bbPtr = bbPtr->successor1) {
/*
* Advance the basic block start offset by however many bytes we
* have inserted in the code up to this point
*/
bbPtr->startOffset += motion;
/*
* If the basic block references a label (and hence performs a
* jump), find the location of the label. Report an error if the
* label is missing.
*/
if (bbPtr->jumpTarget != NULL) {
entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
TclGetString(bbPtr->jumpTarget));
if (entry == NULL) {
ReportUndefinedLabel(assemEnvPtr, bbPtr,
bbPtr->jumpTarget);
return TCL_ERROR;
}
/*
* If the instruction is a JUMP1, turn it into a JUMP4 if its
* target is out of range.
*/
jumpTarget = (BasicBlock*)Tcl_GetHashValue(entry);
if (bbPtr->flags & BB_JUMP1) {
offset = jumpTarget->startOffset
- (bbPtr->jumpOffset + motion);
if (offset < -0x80 || offset > 0x7F) {
opcode = TclGetUInt1AtPtr(envPtr->codeStart
+ bbPtr->jumpOffset);
++opcode;
TclStoreInt1AtPtr(opcode,
envPtr->codeStart + bbPtr->jumpOffset);
motion += 3;
bbPtr->flags &= ~BB_JUMP1;
}
}
}
/*
* If the basic block references a jump table, that doesn't affect
* the code locations, but resolve the labels now, and store basic
* block pointers in the jumptable hash.
*/
if (bbPtr->flags & BB_JUMPTABLE) {
if (CheckJumpTableLabels(assemEnvPtr, bbPtr) != TCL_OK) {
return TCL_ERROR;
}
}
}
*mustMove += motion;
} while (motion != 0);
return TCL_OK;
}
/*
*-----------------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2872 2873 2874 2875 2876 2877 2878 |
*/
static int
CheckJumpTableLabels(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr) /* Basic block that ends in a jump table */
{
| > | | | | < < | | | | | | | | | | | | < < < < < < < < < < < < < < < < < | 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 |
*/
static int
CheckJumpTableLabels(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr) /* Basic block that ends in a jump table */
{
Tcl_HashTable* symHash = &bbPtr->jtPtr->hashTable;
/* Hash table with the symbols */
Tcl_HashSearch search; /* Hash table iterator */
Tcl_HashEntry* symEntryPtr; /* Hash entry for the symbols */
Tcl_Obj* symbolObj; /* Jump target */
Tcl_HashEntry* valEntryPtr; /* Hash entry for the resolutions */
/*
* Look up every jump target in the jump hash.
*/
DEBUG_PRINT("check jump table labels %p {\n", bbPtr);
for (symEntryPtr = Tcl_FirstHashEntry(symHash, &search);
symEntryPtr != NULL;
symEntryPtr = Tcl_NextHashEntry(&search)) {
symbolObj = (Tcl_Obj*)Tcl_GetHashValue(symEntryPtr);
valEntryPtr = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
TclGetString(symbolObj));
DEBUG_PRINT(" %s -> %s (%d)\n",
(char *)Tcl_GetHashKey(symHash, symEntryPtr),
TclGetString(symbolObj), (valEntryPtr != NULL));
if (valEntryPtr == NULL) {
ReportUndefinedLabel(assemEnvPtr, bbPtr, symbolObj);
return TCL_ERROR;
}
}
DEBUG_PRINT("}\n");
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
2936 2937 2938 2939 2940 2941 2942 | * the assembler's Tcl interpreter. * *----------------------------------------------------------------------------- */ static void ReportUndefinedLabel( | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 |
* the assembler's Tcl interpreter.
*
*-----------------------------------------------------------------------------
*/
static void
ReportUndefinedLabel(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr, /* Basic block that contains the undefined
* label */
Tcl_Obj* jumpTarget) /* Label of a jump target */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"undefined label \"%s\"", TclGetString(jumpTarget)));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "NOLABEL",
TclGetString(jumpTarget), (char *)NULL);
Tcl_SetErrorLine(interp, bbPtr->jumpLine);
}
}
/*
*-----------------------------------------------------------------------------
*
* MoveCodeForJumps --
*
* Move bytecodes in memory to accommodate JUMP1 instructions that have
* expanded to become JUMP4's.
*
*-----------------------------------------------------------------------------
*/
static void
MoveCodeForJumps(
AssemblyEnv* assemEnvPtr, /* Assembler environment */
int mustMove) /* Number of bytes of added code */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr; /* Pointer to a basic block being checked */
int topOffset; /* Bytecode offset of the following basic
* block before code motion */
/*
* Make sure that there is enough space in the bytecode array to
* accommodate the expanded code.
*/
while (envPtr->codeEnd < envPtr->codeNext + mustMove) {
TclExpandCodeArray(envPtr);
}
/*
* Iterate through the bytecodes in reverse order, and move them upward to
* their new homes.
*/
topOffset = envPtr->codeNext - envPtr->codeStart;
for (bbPtr = assemEnvPtr->curr_bb; bbPtr != NULL; bbPtr = bbPtr->prevPtr) {
DEBUG_PRINT("move code from %d to %d\n",
bbPtr->originalStartOffset, bbPtr->startOffset);
memmove(envPtr->codeStart + bbPtr->startOffset,
envPtr->codeStart + bbPtr->originalStartOffset,
topOffset - bbPtr->originalStartOffset);
topOffset = bbPtr->originalStartOffset;
bbPtr->jumpOffset += (bbPtr->startOffset - bbPtr->originalStartOffset);
}
envPtr->codeNext += mustMove;
}
/*
*-----------------------------------------------------------------------------
*
* FillInJumpOffsets --
*
* Fill in the final offsets of all jump instructions once bytecode
|
| ︙ | ︙ | |||
2988 2989 2990 2991 2992 2993 2994 |
bbPtr = bbPtr->successor1) {
if (bbPtr->jumpTarget != NULL) {
entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
TclGetString(bbPtr->jumpTarget));
jumpTarget = (BasicBlock*)Tcl_GetHashValue(entry);
fromOffset = bbPtr->jumpOffset;
targetOffset = jumpTarget->startOffset;
| > > > > | | > | 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 |
bbPtr = bbPtr->successor1) {
if (bbPtr->jumpTarget != NULL) {
entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
TclGetString(bbPtr->jumpTarget));
jumpTarget = (BasicBlock*)Tcl_GetHashValue(entry);
fromOffset = bbPtr->jumpOffset;
targetOffset = jumpTarget->startOffset;
if (bbPtr->flags & BB_JUMP1) {
TclStoreInt1AtPtr(targetOffset - fromOffset,
envPtr->codeStart + fromOffset + 1);
} else {
TclStoreInt4AtPtr(targetOffset - fromOffset,
envPtr->codeStart + fromOffset + 1);
}
}
if (bbPtr->flags & BB_JUMPTABLE) {
ResolveJumpTableTargets(assemEnvPtr, bbPtr);
}
}
}
|
| ︙ | ︙ | |||
3018 3019 3020 3021 3022 3023 3024 |
static void
ResolveJumpTableTargets(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr) /* Basic block that ends in a jump table */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
| > | | > > > | < < < < < | < | | | < | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 |
static void
ResolveJumpTableTargets(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr) /* Basic block that ends in a jump table */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_HashTable* symHash = &bbPtr->jtPtr->hashTable;
/* Hash table with the symbols */
Tcl_HashSearch search; /* Hash table iterator */
Tcl_HashEntry* symEntryPtr; /* Hash entry for the symbols */
Tcl_Obj* symbolObj; /* Jump target */
Tcl_HashEntry* valEntryPtr; /* Hash entry for the resolutions */
int auxDataIndex; /* Index of the auxdata */
JumptableInfo* realJumpTablePtr;
/* Jump table in the actual code */
Tcl_HashTable* realJumpHashPtr;
/* Jump table hash in the actual code */
Tcl_HashEntry* realJumpEntryPtr;
/* Entry in the jump table hash in
* the actual code */
BasicBlock* jumpTargetBBPtr;
/* Basic block that the jump proceeds to */
int junk;
auxDataIndex = TclGetInt4AtPtr(envPtr->codeStart + bbPtr->jumpOffset + 1);
DEBUG_PRINT("bbPtr = %p jumpOffset = %d auxDataIndex = %d\n",
bbPtr, bbPtr->jumpOffset, auxDataIndex);
realJumpTablePtr = (JumptableInfo*)TclFetchAuxData(envPtr, auxDataIndex);
realJumpHashPtr = &realJumpTablePtr->hashTable;
/*
* Look up every jump target in the jump hash.
*/
DEBUG_PRINT("resolve jump table {\n");
for (symEntryPtr = Tcl_FirstHashEntry(symHash, &search);
symEntryPtr != NULL;
symEntryPtr = Tcl_NextHashEntry(&search)) {
symbolObj = (Tcl_Obj*)Tcl_GetHashValue(symEntryPtr);
DEBUG_PRINT(" symbol %s\n", TclGetString(symbolObj));
valEntryPtr = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
TclGetString(symbolObj));
jumpTargetBBPtr = (BasicBlock*)Tcl_GetHashValue(valEntryPtr);
realJumpEntryPtr = Tcl_CreateHashEntry(realJumpHashPtr,
Tcl_GetHashKey(symHash, symEntryPtr), &junk);
DEBUG_PRINT(" %s -> %s -> bb %p (pc %d) hash entry %p\n",
(char *)Tcl_GetHashKey(symHash, symEntryPtr),
TclGetString(symbolObj), jumpTargetBBPtr,
jumpTargetBBPtr->startOffset, realJumpEntryPtr);
Tcl_SetHashValue(realJumpEntryPtr,
INT2PTR(jumpTargetBBPtr->startOffset - bbPtr->jumpOffset));
}
DEBUG_PRINT("}\n");
}
/*
*-----------------------------------------------------------------------------
*
* CheckForThrowInWrongContext --
*
|
| ︙ | ︙ | |||
3180 3181 3182 3183 3184 3185 3186 | * Stashes an error message in the interpreter result. * *----------------------------------------------------------------------------- */ static int CheckNonThrowingBlock( | | | | | | | | | | 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 |
* Stashes an error message in the interpreter result.
*
*-----------------------------------------------------------------------------
*/
static int
CheckNonThrowingBlock(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* blockPtr) /* Basic block where exceptions are not
* allowed */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
BasicBlock* nextPtr; /* Pointer to the succeeding basic block */
int offset; /* Bytecode offset of the current
* instruction */
int bound; /* Bytecode offset following the last
* instruction of the block. */
unsigned char opcode; /* Current bytecode instruction */
/*
* Determine where in the code array the basic block ends.
*/
nextPtr = blockPtr->successor1;
if (nextPtr == NULL) {
bound = envPtr->codeNext - envPtr->codeStart;
} else {
bound = nextPtr->startOffset;
}
/*
* Walk through the instructions of the block.
*/
|
| ︙ | ︙ | |||
3371 3372 3373 3374 3375 3376 3377 | * reachable along multiple flow paths with different stack depths. * *----------------------------------------------------------------------------- */ static int StackCheckBasicBlock( | | | | | | | | | < | 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 |
* reachable along multiple flow paths with different stack depths.
*
*-----------------------------------------------------------------------------
*/
static int
StackCheckBasicBlock(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* blockPtr, /* Pointer to the basic block being checked */
BasicBlock* predecessor, /* Pointer to the block that passed control to
* this one. */
int initialStackDepth) /* Stack depth on entry to the block */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
BasicBlock* jumpTarget; /* Basic block where a jump goes */
int stackDepth; /* Current stack depth */
int maxDepth; /* Maximum stack depth so far */
int result; /* Tcl status return */
Tcl_HashSearch jtSearch; /* Search structure for the jump table */
Tcl_HashEntry* jtEntry; /* Hash entry in the jump table */
Tcl_Obj* targetLabel; /* Target label from the jump table */
Tcl_HashEntry* entry; /* Hash entry in the label table */
if (blockPtr->flags & BB_VISITED) {
/*
* If the block is already visited, check stack depth for consistency
* among the paths that reach it.
*/
if (blockPtr->initialStackDepth == initialStackDepth) {
return TCL_OK;
}
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"inconsistent stack depths on two execution paths", -1));
/*
* TODO - add execution trace of both paths
*/
Tcl_SetErrorLine(interp, blockPtr->startLine);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADSTACK", (char *)NULL);
|
| ︙ | ︙ | |||
3431 3432 3433 3434 3435 3436 3437 |
/*
* Calculate minimum stack depth, and flag an error if the block
* underflows the stack.
*/
if (initialStackDepth + blockPtr->minStackDepth < 0) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
| | < | < | 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 |
/*
* Calculate minimum stack depth, and flag an error if the block
* underflows the stack.
*/
if (initialStackDepth + blockPtr->minStackDepth < 0) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("stack underflow", -1));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADSTACK", (char *)NULL);
AddBasicBlockRangeToErrorInfo(assemEnvPtr, blockPtr);
Tcl_SetErrorLine(interp, blockPtr->startLine);
}
return TCL_ERROR;
}
/*
* Make sure that the block doesn't try to pop below the stack level of an
* enclosing catch.
*/
if (blockPtr->enclosingCatch != 0 &&
initialStackDepth + blockPtr->minStackDepth
< (blockPtr->enclosingCatch->initialStackDepth
+ blockPtr->enclosingCatch->finalStackDepth)) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"code pops stack below level of enclosing catch", -1));
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADSTACKINCATCH", (char *)NULL);
AddBasicBlockRangeToErrorInfo(assemEnvPtr, blockPtr);
Tcl_SetErrorLine(interp, blockPtr->startLine);
}
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3494 3495 3496 3497 3498 3499 3500 |
}
/*
* All blocks referenced in a jump table are successors.
*/
if (blockPtr->flags & BB_JUMPTABLE) {
| < < | > | | | 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 |
}
/*
* All blocks referenced in a jump table are successors.
*/
if (blockPtr->flags & BB_JUMPTABLE) {
for (jtEntry = Tcl_FirstHashEntry(&blockPtr->jtPtr->hashTable,
&jtSearch);
result == TCL_OK && jtEntry != NULL;
jtEntry = Tcl_NextHashEntry(&jtSearch)) {
targetLabel = (Tcl_Obj*)Tcl_GetHashValue(jtEntry);
entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
TclGetString(targetLabel));
jumpTarget = (BasicBlock*)Tcl_GetHashValue(entry);
result = StackCheckBasicBlock(assemEnvPtr, jumpTarget,
blockPtr, stackDepth);
}
}
return result;
}
|
| ︙ | ︙ | |||
3534 3535 3536 3537 3538 3539 3540 | * assembly code. * *----------------------------------------------------------------------------- */ static int StackCheckExit( | | | | | | 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 |
* assembly code.
*
*-----------------------------------------------------------------------------
*/
static int
StackCheckExit(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
int depth; /* Net stack effect */
int litIndex; /* Index in the literal pool of the empty
* string */
BasicBlock* curr_bb = assemEnvPtr->curr_bb;
/* Final basic block in the assembly */
/*
* Don't perform these checks if execution doesn't reach the exit (either
* because of an infinite loop or because the only return is from the
* middle.
*/
|
| ︙ | ︙ | |||
3569 3570 3571 3572 3573 3574 3575 | litIndex = TclRegisterLiteral(envPtr, "", 0, 0); /* * Assumes that 'push' is at slot 0 in TalInstructionTable. */ | | | 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 | litIndex = TclRegisterLiteral(envPtr, "", 0, 0); /* * Assumes that 'push' is at slot 0 in TalInstructionTable. */ BBEmitInst1or4(assemEnvPtr, 0, litIndex, 0); ++depth; } /* * Exit with unbalanced stack. */ |
| ︙ | ︙ | |||
3684 3685 3686 3687 3688 3689 3690 | * assembler program, and records the enclosing 'catch' for every basic block. * *----------------------------------------------------------------------------- */ static int ProcessCatchesInBasicBlock( | | | | | | | | | | | | | | 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 |
* assembler program, and records the enclosing 'catch' for every basic block.
*
*-----------------------------------------------------------------------------
*/
static int
ProcessCatchesInBasicBlock(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr, /* Basic block being processed */
BasicBlock* enclosing, /* Start basic block of the enclosing catch */
enum BasicBlockCatchState state,
/* BBCS_NONE, BBCS_INCATCH, or BBCS_CAUGHT */
int catchDepth) /* Depth of nesting of catches */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
int result; /* Return value from this procedure */
BasicBlock* fallThruEnclosing;
/* Enclosing catch if execution falls thru */
enum BasicBlockCatchState fallThruState;
/* Catch state of the successor block */
BasicBlock* jumpEnclosing; /* Enclosing catch if execution goes to jump
* target */
enum BasicBlockCatchState jumpState;
/* Catch state of the jump target */
int changed = 0; /* Flag == 1 iff successor blocks need to be
* checked because the state of this block has
* changed. */
BasicBlock* jumpTarget; /* Basic block where a jump goes */
Tcl_HashSearch jtSearch; /* Hash search control for a jumptable */
Tcl_HashEntry* jtEntry; /* Entry in a jumptable */
Tcl_Obj* targetLabel; /* Target label from a jumptable */
Tcl_HashEntry* entry; /* Entry from the label table */
/*
* Update the state of the current block, checking for consistency. Set
* 'changed' to 1 if the state changes and successor blocks need to be
* rechecked.
*/
if (bbPtr->catchState == BBCS_UNKNOWN) {
bbPtr->enclosingCatch = enclosing;
} else if (bbPtr->enclosingCatch != enclosing) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"execution reaches an instruction in inconsistent "
"exception contexts", -1));
Tcl_SetErrorLine(interp, bbPtr->startLine);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADCATCH", (char *)NULL);
}
return TCL_ERROR;
}
if (state > bbPtr->catchState) {
bbPtr->catchState = state;
|
| ︙ | ︙ | |||
3784 3785 3786 3787 3788 3789 3790 |
* If the block ends a catch, the state for the successor is whatever
* the state was on entry to the catch.
*/
if (enclosing == NULL) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
| | < | 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 |
* If the block ends a catch, the state for the successor is whatever
* the state was on entry to the catch.
*/
if (enclosing == NULL) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"endCatch without a corresponding beginCatch", -1));
Tcl_SetErrorLine(interp, bbPtr->startLine);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADENDCATCH", (char *)NULL);
}
return TCL_ERROR;
}
fallThruEnclosing = enclosing->enclosingCatch;
fallThruState = enclosing->catchState;
|
| ︙ | ︙ | |||
3818 3819 3820 3821 3822 3823 3824 |
}
/*
* All blocks referenced in a jump table are successors.
*/
if (bbPtr->flags & BB_JUMPTABLE) {
| < < | | | 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 |
}
/*
* All blocks referenced in a jump table are successors.
*/
if (bbPtr->flags & BB_JUMPTABLE) {
for (jtEntry = Tcl_FirstHashEntry(&bbPtr->jtPtr->hashTable,&jtSearch);
result == TCL_OK && jtEntry != NULL;
jtEntry = Tcl_NextHashEntry(&jtSearch)) {
targetLabel = (Tcl_Obj*)Tcl_GetHashValue(jtEntry);
entry = Tcl_FindHashEntry(&assemEnvPtr->labelHash,
TclGetString(targetLabel));
jumpTarget = (BasicBlock*)Tcl_GetHashValue(entry);
result = ProcessCatchesInBasicBlock(assemEnvPtr, jumpTarget,
jumpEnclosing, jumpState, catchDepth);
}
}
|
| ︙ | ︙ | |||
3852 3853 3854 3855 3856 3857 3858 | * catches. * *----------------------------------------------------------------------------- */ static int CheckForUnclosedCatches( | | | | | < | 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 |
* catches.
*
*-----------------------------------------------------------------------------
*/
static int
CheckForUnclosedCatches(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
if (assemEnvPtr->curr_bb->catchState >= BBCS_INCATCH) {
if (assemEnvPtr->flags & TCL_EVAL_DIRECT) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"catch still active on exit from assembly code", -1));
Tcl_SetErrorLine(interp,
assemEnvPtr->curr_bb->enclosingCatch->startLine);
Tcl_SetErrorCode(interp, "TCL", "ASSEM", "UNCLOSEDCATCH", (char *)NULL);
}
return TCL_ERROR;
}
return TCL_OK;
|
| ︙ | ︙ | |||
3907 3908 3909 3910 3911 3912 3913 |
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr; /* Current basic block */
BasicBlock* prevPtr = NULL; /* Previous basic block */
int catchDepth = 0; /* Current catch depth */
int maxCatchDepth = 0; /* Maximum catch depth in the program */
BasicBlock** catches; /* Stack of catches in progress */
| | | | 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 |
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr; /* Current basic block */
BasicBlock* prevPtr = NULL; /* Previous basic block */
int catchDepth = 0; /* Current catch depth */
int maxCatchDepth = 0; /* Maximum catch depth in the program */
BasicBlock** catches; /* Stack of catches in progress */
int* catchIndices; /* Indices of the exception ranges of catches
* in progress */
int i;
/*
* Determine the max catch depth for the entire assembly script
* (excluding embedded eval's and expr's, which will be handled later).
*/
for (bbPtr=assemEnvPtr->head_bb; bbPtr != NULL; bbPtr=bbPtr->successor1) {
if (bbPtr->catchDepth > maxCatchDepth) {
maxCatchDepth = bbPtr->catchDepth;
}
}
/*
* Allocate memory for a stack of active catches.
*/
catches = (BasicBlock**)Tcl_Alloc(maxCatchDepth * sizeof(BasicBlock*));
catchIndices = (int *)Tcl_Alloc(maxCatchDepth * sizeof(int));
for (i = 0; i < maxCatchDepth; ++i) {
catches[i] = NULL;
catchIndices[i] = -1;
}
/*
* Walk through the basic blocks and manage exception ranges.
|
| ︙ | ︙ | |||
3950 3951 3952 3953 3954 3955 3956 |
/*
* If the last block was a 'begin catch', fill in the exception range.
*/
catchDepth = bbPtr->catchDepth;
if (prevPtr != NULL && (prevPtr->flags & BB_BEGINCATCH)) {
| | | 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 |
/*
* If the last block was a 'begin catch', fill in the exception range.
*/
catchDepth = bbPtr->catchDepth;
if (prevPtr != NULL && (prevPtr->flags & BB_BEGINCATCH)) {
TclStoreInt4AtPtr(catchIndices[catchDepth-1],
envPtr->codeStart + bbPtr->startOffset - 4);
}
prevPtr = bbPtr;
}
/* Make sure that all catches are closed */
|
| ︙ | ︙ | |||
3986 3987 3988 3989 3990 3991 3992 | * current one. * *----------------------------------------------------------------------------- */ static void UnstackExpiredCatches( | | | | | | 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 |
* current one.
*
*-----------------------------------------------------------------------------
*/
static void
UnstackExpiredCatches(
CompileEnv* envPtr, /* Compilation environment */
BasicBlock* bbPtr, /* Basic block being processed */
int catchDepth, /* Depth of nesting of catches prior to entry
* to this block */
BasicBlock** catches, /* Array of catch contexts */
int* catchIndices) /* Indices of the exception ranges
* corresponding to the catch contexts */
{
ExceptionRange* range; /* Exception range for a specific catch */
BasicBlock* block; /* Catch block being examined */
BasicBlockCatchState catchState;
/* State of the code relative to the catch
* block being examined ("in catch" or
|
| ︙ | ︙ | |||
4097 4098 4099 4100 4101 4102 4103 |
static void
StackFreshCatches(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr, /* Basic block being processed */
int catchDepth, /* Depth of nesting of catches prior to entry
* to this block */
BasicBlock** catches, /* Array of catch contexts */
| | | 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 |
static void
StackFreshCatches(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr, /* Basic block being processed */
int catchDepth, /* Depth of nesting of catches prior to entry
* to this block */
BasicBlock** catches, /* Array of catch contexts */
int* catchIndices) /* Indices of the exception ranges
* corresponding to the catch contexts */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
ExceptionRange* range; /* Exception range for a specific catch */
BasicBlock* block; /* Catch block being examined */
BasicBlock* errorExit; /* Error exit from the catch block */
|
| ︙ | ︙ | |||
4160 4161 4162 4163 4164 4165 4166 |
static void
RestoreEmbeddedExceptionRanges(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr; /* Current basic block */
| | | | 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 |
static void
RestoreEmbeddedExceptionRanges(
AssemblyEnv* assemEnvPtr) /* Assembly environment */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr; /* Current basic block */
int rangeBase; /* Base of the foreign exception ranges when
* they are reinstalled */
size_t rangeIndex; /* Index of the current foreign exception
* range as reinstalled */
ExceptionRange* range; /* Current foreign exception range */
unsigned char opcode; /* Current instruction's opcode */
int catchIndex; /* Index of the exception range to which the
* current instruction refers */
int i;
/*
* Walk the basic blocks looking for exceptions in embedded scripts.
*/
|
| ︙ | ︙ | |||
4196 4197 4198 4199 4200 4201 4202 |
if (range->nestingLevel + 1 >= envPtr->maxExceptDepth + 1) {
envPtr->maxExceptDepth = range->nestingLevel + 1;
}
}
/*
* Walk through the bytecode of the basic block, and relocate
| | | | 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 |
if (range->nestingLevel + 1 >= envPtr->maxExceptDepth + 1) {
envPtr->maxExceptDepth = range->nestingLevel + 1;
}
}
/*
* Walk through the bytecode of the basic block, and relocate
* INST_BEGIN_CATCH4 instructions to the new locations
*/
i = bbPtr->startOffset;
while (i < bbPtr->successor1->startOffset) {
opcode = envPtr->codeStart[i];
if (opcode == INST_BEGIN_CATCH4) {
catchIndex = TclGetUInt4AtPtr(envPtr->codeStart + i + 1);
if (catchIndex >= bbPtr->foreignExceptionBase
&& catchIndex < (bbPtr->foreignExceptionBase +
bbPtr->foreignExceptionCount)) {
catchIndex -= bbPtr->foreignExceptionBase;
catchIndex += rangeBase;
TclStoreInt4AtPtr(catchIndex, envPtr->codeStart+i+1);
|
| ︙ | ︙ | |||
4257 4258 4259 4260 4261 4262 4263 | * information when reporting an error in stack checking. * *----------------------------------------------------------------------------- */ static void AddBasicBlockRangeToErrorInfo( | | | | | > > > > > > > | > | < < < < | | 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 |
* information when reporting an error in stack checking.
*
*-----------------------------------------------------------------------------
*/
static void
AddBasicBlockRangeToErrorInfo(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
BasicBlock* bbPtr) /* Basic block in which the error is found */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
Tcl_Interp* interp = (Tcl_Interp*) envPtr->iPtr;
/* Tcl interpreter */
Tcl_Obj* lineNo; /* Line number in the source */
Tcl_AddErrorInfo(interp, "\n in assembly code between lines ");
TclNewIntObj(lineNo, bbPtr->startLine);
Tcl_IncrRefCount(lineNo);
Tcl_AppendObjToErrorInfo(interp, lineNo);
Tcl_AddErrorInfo(interp, " and ");
if (bbPtr->successor1 != NULL) {
TclSetIntObj(lineNo, bbPtr->successor1->startLine);
Tcl_AppendObjToErrorInfo(interp, lineNo);
} else {
Tcl_AddErrorInfo(interp, "end of assembly code");
}
Tcl_DecrRefCount(lineNo);
}
/*
*-----------------------------------------------------------------------------
*
* DupAssembleCodeInternalRep --
*
|
| ︙ | ︙ |
Changes to generic/tclAsync.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
struct ThreadSpecificData;
/*
* One of the following structures exists for each asynchronous handler:
*/
typedef struct AsyncHandler {
| | | | | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
struct ThreadSpecificData;
/*
* One of the following structures exists for each asynchronous handler:
*/
typedef struct AsyncHandler {
int ready; /* Non-zero means this handler should be
* invoked in the next call to
* Tcl_AsyncInvoke. */
struct AsyncHandler *nextPtr, *prevPtr;
/* Next, previous in list of all handlers
* for the process. */
Tcl_AsyncProc *proc; /* Procedure to call when handler is
* invoked. */
void *clientData; /* Value to pass to handler when it is
* invoked. */
struct ThreadSpecificData *originTsd;
/* Used in Tcl_AsyncMark to modify thread-
* specific data from outside the thread it is
* associated to. */
Tcl_ThreadId originThrdId; /* Origin thread where this token was created
* and where it will be yielded. */
void *notifierData; /* Platform notifier data or NULL. */
} AsyncHandler;
typedef struct ThreadSpecificData {
int asyncReady; /* This is set to 1 whenever a handler becomes
* ready and it is cleared to zero whenever
* Tcl_AsyncInvoke is called. It can be
* checked elsewhere in the application by
* calling Tcl_AsyncReady to see if
* Tcl_AsyncInvoke should be invoked. */
int asyncActive; /* Indicates whether Tcl_AsyncInvoke is
* currently working. If so then we won't set
* asyncReady again until Tcl_AsyncInvoke
* returns. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/* Mutex to protect linked-list of AsyncHandlers in the process. */
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
*----------------------------------------------------------------------
*/
Tcl_AsyncHandler
Tcl_AsyncCreate(
Tcl_AsyncProc *proc, /* Procedure to call when handler is
* invoked. */
| | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
*----------------------------------------------------------------------
*/
Tcl_AsyncHandler
Tcl_AsyncCreate(
Tcl_AsyncProc *proc, /* Procedure to call when handler is
* invoked. */
void *clientData) /* Argument to pass to handler. */
{
AsyncHandler *asyncPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
asyncPtr = (AsyncHandler*)Tcl_Alloc(sizeof(AsyncHandler));
asyncPtr->ready = 0;
asyncPtr->nextPtr = NULL;
|
| ︙ | ︙ | |||
186 187 188 189 190 191 192 | * The handler gets marked for invocation later. * *---------------------------------------------------------------------- */ void Tcl_AsyncMark( | | | > | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
* The handler gets marked for invocation later.
*
*----------------------------------------------------------------------
*/
void
Tcl_AsyncMark(
Tcl_AsyncHandler async) /* Token for handler. */
{
AsyncHandler *token = (AsyncHandler *) async;
Tcl_MutexLock(&asyncMutex);
token->ready = 1;
if (!token->originTsd->asyncActive) {
token->originTsd->asyncReady = 1;
Tcl_ThreadAlert(token->originThrdId);
}
Tcl_MutexUnlock(&asyncMutex);
}
/*
*----------------------------------------------------------------------
*
* Tcl_AsyncMarkFromSignal --
*
|
| ︙ | ︙ | |||
219 220 221 222 223 224 225 | * The handler gets marked for invocation later. * *---------------------------------------------------------------------- */ int Tcl_AsyncMarkFromSignal( | | | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
* The handler gets marked for invocation later.
*
*----------------------------------------------------------------------
*/
int
Tcl_AsyncMarkFromSignal(
Tcl_AsyncHandler async, /* Token for handler. */
int sigNumber) /* Signal number. */
{
#if TCL_THREADS
AsyncHandler *token = (AsyncHandler *) async;
return TclAsyncNotifier(sigNumber, token->originThrdId,
token->notifierData, &token->ready, -1);
#else
(void)sigNumber;
Tcl_AsyncMark(async);
return 1;
#endif
}
|
| ︙ | ︙ | |||
263 264 265 266 267 268 269 |
Tcl_MutexLock(&asyncMutex);
for (token = firstHandler; token != NULL;
token = token->nextPtr) {
if (token->ready == -1) {
token->ready = 1;
if (!token->originTsd->asyncActive) {
| | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
Tcl_MutexLock(&asyncMutex);
for (token = firstHandler; token != NULL;
token = token->nextPtr) {
if (token->ready == -1) {
token->ready = 1;
if (!token->originTsd->asyncActive) {
token->originTsd->asyncReady = 1;
Tcl_ThreadAlert(token->originThrdId);
}
}
}
Tcl_MutexUnlock(&asyncMutex);
}
|
| ︙ | ︙ | |||
304 305 306 307 308 309 310 |
{
AsyncHandler *asyncPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_ThreadId self = Tcl_GetCurrentThread();
Tcl_MutexLock(&asyncMutex);
| | | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
{
AsyncHandler *asyncPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_ThreadId self = Tcl_GetCurrentThread();
Tcl_MutexLock(&asyncMutex);
if (tsdPtr->asyncReady == 0) {
Tcl_MutexUnlock(&asyncMutex);
return code;
}
tsdPtr->asyncReady = 0;
tsdPtr->asyncActive = 1;
if (interp == NULL) {
code = 0;
}
/*
* Make one or more passes over the list of handlers, invoking at most one
* handler in each pass. After invoking a handler, go back to the start of
|
| ︙ | ︙ | |||
342 343 344 345 346 347 348 |
break;
}
asyncPtr->ready = 0;
Tcl_MutexUnlock(&asyncMutex);
code = asyncPtr->proc(asyncPtr->clientData, interp, code);
Tcl_MutexLock(&asyncMutex);
}
| | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
break;
}
asyncPtr->ready = 0;
Tcl_MutexUnlock(&asyncMutex);
code = asyncPtr->proc(asyncPtr->clientData, interp, code);
Tcl_MutexLock(&asyncMutex);
}
tsdPtr->asyncActive = 0;
Tcl_MutexUnlock(&asyncMutex);
return code;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
373 374 375 376 377 378 379 | * deleted by some other thread. * *---------------------------------------------------------------------- */ void Tcl_AsyncDelete( | | | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
* deleted by some other thread.
*
*----------------------------------------------------------------------
*/
void
Tcl_AsyncDelete(
Tcl_AsyncHandler async) /* Token for handler to delete. */
{
AsyncHandler *asyncPtr = (AsyncHandler *) async;
/*
* Assure early handling of the constraint
*/
|
| ︙ | ︙ | |||
427 428 429 430 431 432 433 |
*----------------------------------------------------------------------
*/
int
Tcl_AsyncReady(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
| | | | | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
*----------------------------------------------------------------------
*/
int
Tcl_AsyncReady(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->asyncReady;
}
int *
TclGetAsyncReadyPtr(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return &(tsdPtr->asyncReady);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclBasic.c.
| ︙ | ︙ | |||
78 79 80 81 82 83 84 |
#ifndef __has_builtin
#define __has_builtin(x) 0 /* for non-clang compilers */
#endif
void *
TclGetCStackPtr(void)
{
| | | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
#ifndef __has_builtin
#define __has_builtin(x) 0 /* for non-clang compilers */
#endif
void *
TclGetCStackPtr(void)
{
#if defined( __GNUC__ ) || __has_builtin(__builtin_frame_address)
return __builtin_frame_address(0);
#elif defined(_MSC_VER)
return _AddressOfReturnAddress();
#else
ptrdiff_t unused = 0;
/*
* LLVM recommends using volatile:
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
iPtr->cmdFramePtr = (context).cmdFramePtr; \
iPtr->lineLABCPtr = (context).lineLABCPtr
/*
* Static functions in this file:
*/
| | < | < | | | | | | | | | | | < | | < < | | | | | | | | | | | < < < | | | > | | | > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > < < | | < | | | < | < | | | | | | | | | | | | | | | | | | | | | | > | < | > | < | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | < < > | | < < > > > > > > > | < < > > > > > > > > > > > > > | < < < | < < < < < < < < < < < < < < < < < < < < < | | | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 |
iPtr->cmdFramePtr = (context).cmdFramePtr; \
iPtr->lineLABCPtr = (context).lineLABCPtr
/*
* Static functions in this file:
*/
static Tcl_ObjCmdProc BadEnsembleSubcommand;
static Tcl_CmdDeleteProc BadEnsembleSubcommandCleanup;
static char * CallCommandTraces(Interp *iPtr, Command *cmdPtr,
const char *oldName, const char *newName,
int flags);
static int CancelEvalProc(void *clientData,
Tcl_Interp *interp, int code);
static int CheckDoubleResult(Tcl_Interp *interp, double dResult);
static void DeleteCoroutine(void *clientData);
static Tcl_FreeProc DeleteInterpProc;
static void DeleteOpCmdClientData(void *clientData);
#ifdef USE_DTRACE
static Tcl_ObjCmdProc DTraceObjCmd;
static Tcl_NRPostProc DTraceCmdReturn;
#else
# define DTraceCmdReturn NULL
#endif /* USE_DTRACE */
static Tcl_ObjCmdProc InvokeStringCommand;
static Tcl_ObjCmdProc ExprAbsFunc;
static Tcl_ObjCmdProc ExprBinaryFunc;
static Tcl_ObjCmdProc ExprBoolFunc;
static Tcl_ObjCmdProc ExprCeilFunc;
static Tcl_ObjCmdProc ExprDoubleFunc;
static Tcl_ObjCmdProc ExprFloorFunc;
static Tcl_ObjCmdProc ExprIntFunc;
static Tcl_ObjCmdProc ExprIsqrtFunc;
static Tcl_ObjCmdProc ExprIsFiniteFunc;
static Tcl_ObjCmdProc ExprIsInfinityFunc;
static Tcl_ObjCmdProc ExprIsNaNFunc;
static Tcl_ObjCmdProc ExprIsNormalFunc;
static Tcl_ObjCmdProc ExprIsSubnormalFunc;
static Tcl_ObjCmdProc ExprIsUnorderedFunc;
static Tcl_ObjCmdProc ExprMaxFunc;
static Tcl_ObjCmdProc ExprMinFunc;
static Tcl_ObjCmdProc ExprRandFunc;
static Tcl_ObjCmdProc ExprRoundFunc;
static Tcl_ObjCmdProc ExprSqrtFunc;
static Tcl_ObjCmdProc ExprSrandFunc;
static Tcl_ObjCmdProc ExprUnaryFunc;
static Tcl_ObjCmdProc ExprWideFunc;
static Tcl_ObjCmdProc FloatClassifyObjCmd;
static void MathFuncWrongNumArgs(Tcl_Interp *interp, Tcl_Size expected,
Tcl_Size actual, Tcl_Obj *const *objv);
static Tcl_NRPostProc NRCoroutineCallerCallback;
static Tcl_NRPostProc NRCoroutineExitCallback;
static Tcl_NRPostProc NRCommand;
static void ProcessUnexpectedResult(Tcl_Interp *interp,
int returnCode);
static int RewindCoroutine(CoroutineData *corPtr, int result);
static void TEOV_SwitchVarFrame(Tcl_Interp *interp);
static void TEOV_PushExceptionHandlers(Tcl_Interp *interp,
Tcl_Size objc, Tcl_Obj *const objv[], int flags);
static inline Command * TEOV_LookupCmdFromObj(Tcl_Interp *interp,
Tcl_Obj *namePtr, Namespace *lookupNsPtr);
static int TEOV_NotFound(Tcl_Interp *interp, Tcl_Size objc,
Tcl_Obj *const objv[], Namespace *lookupNsPtr);
static int TEOV_RunEnterTraces(Tcl_Interp *interp,
Command **cmdPtrPtr, Tcl_Obj *commandPtr, Tcl_Size objc,
Tcl_Obj *const objv[]);
static Tcl_NRPostProc RewindCoroutineCallback;
static Tcl_NRPostProc TEOEx_ByteCodeCallback;
static Tcl_NRPostProc TEOEx_ListCallback;
static Tcl_NRPostProc TEOV_Error;
static Tcl_NRPostProc TEOV_Exception;
static Tcl_NRPostProc TEOV_NotFoundCallback;
static Tcl_NRPostProc TEOV_RestoreVarFrame;
static Tcl_NRPostProc TEOV_RunLeaveTraces;
static Tcl_NRPostProc EvalObjvCore;
static Tcl_NRPostProc Dispatch;
static Tcl_NRPostProc NRPostInvoke;
static Tcl_ObjCmdProc CoroTypeObjCmd;
static Tcl_ObjCmdProc TclNRCoroInjectObjCmd;
static Tcl_ObjCmdProc TclNRCoroProbeObjCmd;
static Tcl_NRPostProc InjectHandler;
static Tcl_NRPostProc InjectHandlerPostCall;
MODULE_SCOPE const TclStubs tclStubs;
/*
* Magical counts for the number of arguments accepted by a coroutine command
* after particular kinds of [yield].
*/
#define CORO_ACTIVATE_YIELD NULL
#define CORO_ACTIVATE_YIELDM INT2PTR(1)
enum CoroutineArgumentTypes {
COROUTINE_ARGUMENTS_SINGLE_OPTIONAL = -1,
COROUTINE_ARGUMENTS_ARBITRARY = -2
};
/*
* The following structure define the commands in the Tcl core.
*/
typedef struct {
const char *name; // Name of object-based command.
Tcl_ObjCmdProc *objProc; // Object-based function for command.
CompileProc *compileProc; // Function called to compile command.
Tcl_ObjCmdProc *nreProc; // NR-based function for command.
int flags; // Various flag bits, as defined below.
} CmdInfo;
enum CmdInfoFlags {
CMD_IS_SAFE = 1 /* Whether this command is part of the set of
* commands present by default in a safe
* interpreter. */
/* CMD_COMPILES_EXPANDED - Whether the compiler for this command can handle
* expansion for itself rather than needing the generic layer to take care of
* it for it. Defined in tclInt.h. */
};
/*
* The following struct states that the command it talks about (a subcommand
* of one of Tcl's built-in ensembles) is unsafe and must be hidden when an
* interpreter is made safe. (TclHideUnsafeCommands accesses an array of these
* structs.) Alas, we can't sensibly just store the information directly in
* the commands.
*/
typedef struct {
const char *ensembleNsName; /* The ensemble's name within ::tcl. NULL for
* the end of the list of commands to hide. */
const char *commandName; /* The name of the command within the
* ensemble. If this is NULL, we want to also
* make the overall command be hidden, an ugly
* hack because it is expected by security
* policies in the wild. */
} UnsafeEnsembleInfo;
/*
* Description of commands in ::tcl::unsupported.
*
*/
typedef struct UnsupportedCmdInfo {
const char *name; // Name of command in ::tcl::unsupported.
Tcl_ObjCmdProc *objProc; // Object-based function for command.
CompileProc *compileProc; // Function called to compile command.
Tcl_ObjCmdProc *nreProc; // NR-based function for command.
void *clientData; // ClientData to use for the command.
int flags; // Various flag bits, as defined for CmdInfo.
} UnsupportedCmdInfo;
// A function that can configure an ensemble after it is created.
typedef int (EnsembleConfigurer)(Tcl_Interp *interp, Tcl_Command ensemble);
typedef struct EnsembleSetup {
const char *name; // Name of ensemble.
const EnsembleImplMap *implMap; // Ensemble contents descriptor.
EnsembleConfigurer *configurerProc; // Optional callback for customisation.
int flags; /* Ensemble commands are never technically
* unsafe (though their subcommands may well
* be so), but some code expects them to be
* so. This flag lets us mark those cases. */
} EnsembleSetup;
/*
* The built-in commands, and the functions that implement them:
*/
static int
ProcObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
return Tcl_ProcObjCmd(clientData, interp, objc, objv);
}
static const CmdInfo builtInCmds[] = {
/*
* Commands in the generic core. All are safe.
*/
{"append", Tcl_AppendObjCmd, TclCompileAppendCmd, NULL, CMD_IS_SAFE},
{"apply", Tcl_ApplyObjCmd, NULL, TclNRApplyObjCmd, CMD_IS_SAFE},
{"break", Tcl_BreakObjCmd, TclCompileBreakCmd, NULL, CMD_IS_SAFE},
{"catch", Tcl_CatchObjCmd, TclCompileCatchCmd, TclNRCatchObjCmd, CMD_IS_SAFE},
{"concat", Tcl_ConcatObjCmd, TclCompileConcatCmd, NULL, CMD_IS_SAFE},
{"const", Tcl_ConstObjCmd, TclCompileConstCmd, NULL, CMD_IS_SAFE},
{"continue", Tcl_ContinueObjCmd, TclCompileContinueCmd, NULL, CMD_IS_SAFE},
{"coroinject", NULL, NULL, TclNRCoroInjectObjCmd, CMD_IS_SAFE},
{"coroprobe", NULL, NULL, TclNRCoroProbeObjCmd, CMD_IS_SAFE},
{"coroutine", NULL, NULL, TclNRCoroutineObjCmd, CMD_IS_SAFE},
{"error", Tcl_ErrorObjCmd, TclCompileErrorCmd, NULL, CMD_IS_SAFE},
{"eval", Tcl_EvalObjCmd, NULL, TclNREvalObjCmd, CMD_IS_SAFE},
{"expr", Tcl_ExprObjCmd, TclCompileExprCmd, TclNRExprObjCmd, CMD_IS_SAFE},
{"for", Tcl_ForObjCmd, TclCompileForCmd, TclNRForObjCmd, CMD_IS_SAFE},
{"foreach", Tcl_ForeachObjCmd, TclCompileForeachCmd, TclNRForeachCmd, CMD_IS_SAFE},
{"format", Tcl_FormatObjCmd, TclCompileFormatCmd, NULL, CMD_IS_SAFE},
{"fpclassify", FloatClassifyObjCmd, NULL, NULL, CMD_IS_SAFE},
{"global", Tcl_GlobalObjCmd, TclCompileGlobalCmd, NULL, CMD_IS_SAFE},
{"if", Tcl_IfObjCmd, TclCompileIfCmd, TclNRIfObjCmd, CMD_IS_SAFE},
{"incr", Tcl_IncrObjCmd, TclCompileIncrCmd, NULL, CMD_IS_SAFE},
{"join", Tcl_JoinObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lappend", Tcl_LappendObjCmd, TclCompileLappendCmd, NULL, CMD_IS_SAFE},
{"lassign", Tcl_LassignObjCmd, TclCompileLassignCmd, NULL, CMD_IS_SAFE},
{"ledit", Tcl_LeditObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lindex", Tcl_LindexObjCmd, TclCompileLindexCmd, NULL, CMD_IS_SAFE},
{"linsert", Tcl_LinsertObjCmd, TclCompileLinsertCmd, NULL, CMD_IS_SAFE},
{"list", Tcl_ListObjCmd, TclCompileListCmd, NULL, CMD_IS_SAFE|CMD_COMPILES_EXPANDED},
{"llength", Tcl_LlengthObjCmd, TclCompileLlengthCmd, NULL, CMD_IS_SAFE},
{"lmap", Tcl_LmapObjCmd, TclCompileLmapCmd, TclNRLmapCmd, CMD_IS_SAFE},
{"lpop", Tcl_LpopObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lrange", Tcl_LrangeObjCmd, TclCompileLrangeCmd, NULL, CMD_IS_SAFE},
{"lremove", Tcl_LremoveObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lrepeat", Tcl_LrepeatObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lreplace", Tcl_LreplaceObjCmd, TclCompileLreplaceCmd, NULL, CMD_IS_SAFE},
{"lreverse", Tcl_LreverseObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lsearch", Tcl_LsearchObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lseq", Tcl_LseqObjCmd, NULL, NULL, CMD_IS_SAFE},
{"lset", Tcl_LsetObjCmd, TclCompileLsetCmd, NULL, CMD_IS_SAFE},
{"lsort", Tcl_LsortObjCmd, NULL, NULL, CMD_IS_SAFE},
{"package", Tcl_PackageObjCmd, NULL, TclNRPackageObjCmd, CMD_IS_SAFE},
{"proc", ProcObjCmd, NULL, NULL, CMD_IS_SAFE},
{"regexp", Tcl_RegexpObjCmd, TclCompileRegexpCmd, NULL, CMD_IS_SAFE},
{"regsub", Tcl_RegsubObjCmd, TclCompileRegsubCmd, NULL, CMD_IS_SAFE},
{"rename", Tcl_RenameObjCmd, NULL, NULL, CMD_IS_SAFE},
{"return", Tcl_ReturnObjCmd, TclCompileReturnCmd, NULL, CMD_IS_SAFE},
{"scan", Tcl_ScanObjCmd, NULL, NULL, CMD_IS_SAFE},
{"set", Tcl_SetObjCmd, TclCompileSetCmd, NULL, CMD_IS_SAFE},
{"split", Tcl_SplitObjCmd, NULL, NULL, CMD_IS_SAFE},
{"subst", Tcl_SubstObjCmd, TclCompileSubstCmd, TclNRSubstObjCmd, CMD_IS_SAFE},
{"switch", Tcl_SwitchObjCmd, TclCompileSwitchCmd, TclNRSwitchObjCmd, CMD_IS_SAFE},
{"tailcall", NULL, TclCompileTailcallCmd, TclNRTailcallObjCmd, CMD_IS_SAFE},
{"throw", Tcl_ThrowObjCmd, TclCompileThrowCmd, NULL, CMD_IS_SAFE},
{"trace", Tcl_TraceObjCmd, NULL, NULL, CMD_IS_SAFE},
{"try", Tcl_TryObjCmd, TclCompileTryCmd, TclNRTryObjCmd, CMD_IS_SAFE},
{"unset", Tcl_UnsetObjCmd, TclCompileUnsetCmd, NULL, CMD_IS_SAFE},
{"uplevel", Tcl_UplevelObjCmd, NULL, TclNRUplevelObjCmd, CMD_IS_SAFE},
{"upvar", Tcl_UpvarObjCmd, TclCompileUpvarCmd, NULL, CMD_IS_SAFE},
{"variable", Tcl_VariableObjCmd, TclCompileVariableCmd, NULL, CMD_IS_SAFE},
{"while", Tcl_WhileObjCmd, TclCompileWhileCmd, TclNRWhileObjCmd, CMD_IS_SAFE},
{"yield", NULL, TclCompileYieldCmd, TclNRYieldObjCmd, CMD_IS_SAFE},
{"yieldto", NULL, TclCompileYieldToCmd, TclNRYieldToObjCmd, CMD_IS_SAFE},
/*
* Commands in the OS-interface. Note that many of these are unsafe.
*/
{"after", Tcl_AfterObjCmd, NULL, NULL, CMD_IS_SAFE},
{"cd", Tcl_CdObjCmd, NULL, NULL, 0},
{"close", Tcl_CloseObjCmd, NULL, NULL, CMD_IS_SAFE},
{"eof", Tcl_EofObjCmd, NULL, NULL, CMD_IS_SAFE},
{"exec", Tcl_ExecObjCmd, NULL, NULL, 0},
{"exit", Tcl_ExitObjCmd, NULL, NULL, 0},
{"fblocked", Tcl_FblockedObjCmd, NULL, NULL, CMD_IS_SAFE},
{"fconfigure", Tcl_FconfigureObjCmd, NULL, NULL, 0},
{"fcopy", Tcl_FcopyObjCmd, NULL, NULL, CMD_IS_SAFE},
{"fileevent", Tcl_FileEventObjCmd, NULL, NULL, CMD_IS_SAFE},
{"flush", Tcl_FlushObjCmd, NULL, NULL, CMD_IS_SAFE},
{"gets", Tcl_GetsObjCmd, NULL, NULL, CMD_IS_SAFE},
{"glob", Tcl_GlobObjCmd, NULL, NULL, 0},
{"load", Tcl_LoadObjCmd, NULL, NULL, 0},
{"open", Tcl_OpenObjCmd, NULL, NULL, 0},
{"pid", Tcl_PidObjCmd, NULL, NULL, CMD_IS_SAFE},
{"puts", Tcl_PutsObjCmd, NULL, NULL, CMD_IS_SAFE},
{"pwd", Tcl_PwdObjCmd, NULL, NULL, 0},
{"read", Tcl_ReadObjCmd, NULL, NULL, CMD_IS_SAFE},
{"seek", Tcl_SeekObjCmd, NULL, NULL, CMD_IS_SAFE},
{"socket", Tcl_SocketObjCmd, NULL, NULL, 0},
{"source", Tcl_SourceObjCmd, NULL, TclNRSourceObjCmd, 0},
{"tell", Tcl_TellObjCmd, NULL, NULL, CMD_IS_SAFE},
{"time", Tcl_TimeObjCmd, NULL, NULL, CMD_IS_SAFE},
{"timerate", Tcl_TimeRateObjCmd, NULL, NULL, CMD_IS_SAFE},
{"unload", Tcl_UnloadObjCmd, NULL, NULL, 0},
{"update", Tcl_UpdateObjCmd, NULL, NULL, CMD_IS_SAFE},
{"vwait", Tcl_VwaitObjCmd, NULL, NULL, CMD_IS_SAFE},
{NULL, NULL, NULL, NULL, 0}
};
static const UnsupportedCmdInfo unsupportedCmds[] = {
{"disassemble", Tcl_DisassembleObjCmd, NULL, NULL, INT2PTR(0), 0},
{"getbytecode", Tcl_DisassembleObjCmd, NULL, NULL, INT2PTR(1), 0},
{"representation", Tcl_RepresentationCmd, NULL, NULL, NULL, 0},
{"assemble", Tcl_AssembleObjCmd, TclCompileAssembleCmd, TclNRAssembleObjCmd, NULL, 0},
{"corotype", CoroTypeObjCmd, NULL, NULL, NULL, 0},
{"loadIcu", TclLoadIcuObjCmd, NULL, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
/*
* Information about which pieces of ensembles to hide when making an
* interpreter safe:
*/
static const UnsafeEnsembleInfo unsafeEnsembleCommands[] = {
/* [encoding] has two unsafe commands. Assumed by older security policies
* to be overall unsafe; it isn't but... */
{"encoding", NULL},
{"encoding", "dirs"},
{"encoding", "system"},
/* [file] has MANY unsafe commands! Assumed by older security policies to
* be overall unsafe; it isn't but... */
{"file", NULL},
{"file", "atime"},
{"file", "attributes"},
{"file", "copy"},
{"file", "delete"},
{"file", "dirname"},
{"file", "executable"},
{"file", "exists"},
{"file", "extension"},
{"file", "home"},
{"file", "isdirectory"},
{"file", "isfile"},
{"file", "link"},
{"file", "lstat"},
{"file", "mtime"},
{"file", "mkdir"},
{"file", "nativename"},
{"file", "normalize"},
{"file", "owned"},
{"file", "readable"},
{"file", "readlink"},
{"file", "rename"},
{"file", "rootname"},
{"file", "size"},
{"file", "stat"},
{"file", "tail"},
{"file", "tempdir"},
{"file", "tempfile"},
{"file", "tildeexpand"},
{"file", "type"},
{"file", "volumes"},
{"file", "writable"},
/* [info] has two unsafe commands */
{"info", "cmdtype"},
{"info", "nameofexecutable"},
/* [tcl::process] has ONLY unsafe commands! */
{"process", "list"},
{"process", "status"},
{"process", "purge"},
{"process", "autopurge"},
/*
* [zipfs] perhaps has some safe commands. But like file make it inaccessible
* until they are analyzed to be safe.
*/
{"zipfs", NULL},
{"zipfs", "canonical"},
{"zipfs", "exists"},
{"zipfs", "info"},
{"zipfs", "list"},
{"zipfs", "lmkimg"},
{"zipfs", "lmkzip"},
{"zipfs", "mkimg"},
{"zipfs", "mkkey"},
{"zipfs", "mkzip"},
{"zipfs", "mount"},
{"zipfs", "mountdata"},
{"zipfs", "root"},
{"zipfs", "unmount"},
{NULL, NULL}
};
/*
* Math functions. All are safe.
*/
typedef double (BuiltinUnaryFunc)(double x);
typedef double (BuiltinBinaryFunc)(double x, double y);
#define BINARY_TYPECAST(fn) \
(BuiltinUnaryFunc *)(void *)(BuiltinBinaryFunc *) fn
typedef struct {
const char *name; /* Name of the function. The full name is
* "::tcl::mathfunc::<name>". */
Tcl_ObjCmdProc *objCmdProc; /* Function that evaluates the function */
BuiltinUnaryFunc *fn; /* Real function pointer */
} BuiltinFuncDef;
static const BuiltinFuncDef BuiltinFuncTable[] = {
{ "abs", ExprAbsFunc, NULL },
{ "acos", ExprUnaryFunc, acos },
{ "asin", ExprUnaryFunc, asin },
{ "atan", ExprUnaryFunc, atan },
{ "atan2", ExprBinaryFunc, BINARY_TYPECAST(atan2) },
{ "bool", ExprBoolFunc, NULL },
{ "ceil", ExprCeilFunc, NULL },
{ "cos", ExprUnaryFunc, cos },
{ "cosh", ExprUnaryFunc, cosh },
{ "double", ExprDoubleFunc, NULL },
{ "entier", ExprIntFunc, NULL },
{ "exp", ExprUnaryFunc, exp },
{ "floor", ExprFloorFunc, NULL },
{ "fmod", ExprBinaryFunc, BINARY_TYPECAST(fmod) },
{ "hypot", ExprBinaryFunc, BINARY_TYPECAST(hypot) },
{ "int", ExprIntFunc, NULL },
{ "isfinite", ExprIsFiniteFunc, NULL },
{ "isinf", ExprIsInfinityFunc, NULL },
{ "isnan", ExprIsNaNFunc, NULL },
{ "isnormal", ExprIsNormalFunc, NULL },
{ "isqrt", ExprIsqrtFunc, NULL },
{ "issubnormal", ExprIsSubnormalFunc, NULL, },
{ "isunordered", ExprIsUnorderedFunc, NULL, },
{ "log", ExprUnaryFunc, log },
{ "log10", ExprUnaryFunc, log10 },
{ "max", ExprMaxFunc, NULL },
{ "min", ExprMinFunc, NULL },
{ "pow", ExprBinaryFunc, BINARY_TYPECAST(pow) },
{ "rand", ExprRandFunc, NULL },
{ "round", ExprRoundFunc, NULL },
{ "sin", ExprUnaryFunc, sin },
{ "sinh", ExprUnaryFunc, sinh },
{ "sqrt", ExprSqrtFunc, NULL },
{ "srand", ExprSrandFunc, NULL },
{ "tan", ExprUnaryFunc, tan },
{ "tanh", ExprUnaryFunc, tanh },
{ "wide", ExprWideFunc, NULL },
{ NULL, NULL, NULL }
};
/*
* TIP#174's math operators. All are safe.
*/
typedef struct {
const char *name; /* Name of object-based command. */
Tcl_ObjCmdProc *objProc; /* Object-based function for command. */
CompileProc *compileProc; /* Function called to compile command. */
union {
int numArgs;
int identity;
} i;
const char *expected; /* For error message, what argument(s)
* were expected. */
} OpCmdInfo;
static const OpCmdInfo mathOpCmds[] = {
{ "~", TclSingleOpCmd, TclCompileInvertOpCmd,
/* numArgs */ {1}, "integer"},
{ "!", TclSingleOpCmd, TclCompileNotOpCmd,
|
| ︙ | ︙ | |||
649 650 651 652 653 654 655 |
*/
static int
BuildInfoObjCmd2(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
| | > | | 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 |
*/
static int
BuildInfoObjCmd2(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *buildData = (const char *) clientData;
char buf[80];
const char *arg, *p, *q;
Tcl_Size len;
int idx;
static const char * const identifiers[] = {
"commit", "compiler", "patchlevel", "version", NULL
};
enum Identifiers {
ID_COMMIT, ID_COMPILER, ID_PATCHLEVEL, ID_VERSION, ID_OTHER
};
if (objc > 2) {
|
| ︙ | ︙ | |||
682 683 684 685 686 687 688 |
&idx) != TCL_OK) {
idx = ID_OTHER;
}
switch (idx) {
case ID_PATCHLEVEL:
if ((p = strchr(buildData, '+')) != NULL) {
| > > | > > | > > | > > | > > | < | < | | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 |
&idx) != TCL_OK) {
idx = ID_OTHER;
}
switch (idx) {
case ID_PATCHLEVEL:
if ((p = strchr(buildData, '+')) != NULL) {
memcpy(buf, buildData, p - buildData);
buf[p - buildData] = '\0';
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, TCL_INDEX_NONE));
}
return TCL_OK;
case ID_VERSION:
if ((p = strchr(buildData, '.')) != NULL) {
const char *r = strchr(p++, '+');
q = strchr(p, '.');
p = (q < r) ? q : r;
}
if (p != NULL) {
memcpy(buf, buildData, p - buildData);
buf[p - buildData] = '\0';
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, TCL_INDEX_NONE));
}
return TCL_OK;
case ID_COMMIT:
if ((p = strchr(buildData, '+')) != NULL) {
if ((q = strchr(p++, '.')) != NULL) {
memcpy(buf, p, q - p);
buf[q - p] = '\0';
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, TCL_INDEX_NONE));
} else {
Tcl_SetObjResult(interp, Tcl_NewStringObj(p, TCL_INDEX_NONE));
}
}
return TCL_OK;
case ID_COMPILER:
for (p = strchr(buildData, '.'); p != NULL; p = strchr(p, '.')) {
p++;
/*
* Does the word begin with one of the standard prefixes?
*/
if (!strncmp(p, "clang-", 6)
|| !strncmp(p, "gcc-", 4)
|| !strncmp(p, "icc-", 4)
|| !strncmp(p, "msvc-", 5)) {
if ((q = strchr(p, '.')) != NULL) {
memcpy(buf, p, q - p);
buf[q - p] = '\0';
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, TCL_INDEX_NONE));
} else {
Tcl_SetObjResult(interp, Tcl_NewStringObj(p, TCL_INDEX_NONE));
}
return TCL_OK;
}
}
break;
default: /* Boolean test for other identifiers' presence */
arg = TclGetStringFromObj(objv[1], &len);
for (p = strchr(buildData, '.'); p != NULL; p = strchr(p, '.')) {
p++;
if (!strncmp(p, arg, len)
&& ((p[len] == '.') || (p[len] == '-') || (p[len] == '\0'))) {
if (p[len] == '-') {
p += len;
q = strchr(++p, '.');
if (!q) {
q = p + strlen(p);
}
memcpy(buf, p, q - p);
buf[q - p] = '\0';
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, TCL_INDEX_NONE));
} else {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
}
return TCL_OK;
}
}
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
return TCL_OK;
}
static int
BuildInfoObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return BuildInfoObjCmd2(clientData, interp, objc, objv);
}
/*
*----------------------------------------------------------------------
*
* Tcl_CreateInterp --
*
* Create a new TCL command interpreter.
*
|
| ︙ | ︙ | |||
830 831 832 833 834 835 836 837 |
Tcl_InitHashTable(&cancelTable, TCL_ONE_WORD_KEYS);
cancelTableInitialized = 1;
}
Tcl_MutexUnlock(&cancelLock);
}
if (commandTypeInit == 0) {
| > | | 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 |
Tcl_InitHashTable(&cancelTable, TCL_ONE_WORD_KEYS);
cancelTableInitialized = 1;
}
Tcl_MutexUnlock(&cancelLock);
}
#undef TclObjInterpProc
if (commandTypeInit == 0) {
TclRegisterCommandTypeName(TclObjInterpProc, "proc");
TclRegisterCommandTypeName(TclEnsembleImplementationCmd, "ensemble");
TclRegisterCommandTypeName(TclAliasObjCmd, "alias");
TclRegisterCommandTypeName(TclLocalAliasObjCmd, "alias");
TclRegisterCommandTypeName(TclChildObjCmd, "interp");
TclRegisterCommandTypeName(TclInvokeImportedCmd, "import");
TclRegisterCommandTypeName(TclOOPublicObjectCmd, "object");
TclRegisterCommandTypeName(TclOOPrivateObjectCmd, "privateObject");
|
| ︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | cmdPtr->hPtr = hPtr; cmdPtr->nsPtr = iPtr->globalNsPtr; cmdPtr->refCount = 1; cmdPtr->cmdEpoch = 0; cmdPtr->compileProc = cmdInfoPtr->compileProc; cmdPtr->proc = NULL; cmdPtr->clientData = NULL; | | | | | | | | | | | | | | | > | < < < > > | | | | | | | 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 |
cmdPtr->hPtr = hPtr;
cmdPtr->nsPtr = iPtr->globalNsPtr;
cmdPtr->refCount = 1;
cmdPtr->cmdEpoch = 0;
cmdPtr->compileProc = cmdInfoPtr->compileProc;
cmdPtr->proc = NULL;
cmdPtr->clientData = NULL;
cmdPtr->objProc = cmdInfoPtr->objProc;
cmdPtr->objClientData = NULL;
cmdPtr->deleteProc = NULL;
cmdPtr->deleteData = NULL;
cmdPtr->flags = 0;
if (cmdInfoPtr->flags & CMD_COMPILES_EXPANDED) {
cmdPtr->flags |= CMD_COMPILES_EXPANDED;
}
cmdPtr->importRefPtr = NULL;
cmdPtr->tracePtr = NULL;
cmdPtr->nreProc = cmdInfoPtr->nreProc;
Tcl_SetHashValue(hPtr, cmdPtr);
}
}
/*
* Create the "array", "binary", "chan", "clock", "dict", "encoding",
* "file", "info", "namespace" and "string" ensembles. Note that all these
* commands (and their subcommands that are not present in the global
* namespace) are wholly safe *except* for "clock", "encoding" and "file".
*/
TclInitArrayCmd(interp);
TclInitBinaryCmd(interp);
TclInitChanCmd(interp);
TclInitDictCmd(interp);
TclInitEncodingCmd(interp);
TclInitFileCmd(interp);
TclInitInfoCmd(interp);
TclInitNamespaceCmd(interp);
TclInitStringCmd(interp);
TclInitPrefixCmd(interp);
TclInitProcessCmd(interp);
/*
* Register "clock" subcommands. These *do* go through
* Tcl_CreateObjCommand, since they aren't in the global namespace and
* involve ensembles.
*/
TclClockInit(interp);
/*
* Register the built-in functions. This is empty now that they are
* implemented as commands in the ::tcl::mathfunc namespace.
*/
/*
* Register the default [interp bgerror] handler.
*/
Tcl_CreateObjCommand(interp, "::tcl::Bgerror",
TclDefaultBgErrorHandlerObjCmd, NULL, NULL);
/*
* Create unsupported commands for debugging bytecode and objects.
*/
const UnsupportedCmdInfo *unsCmdInfoPtr;
for (unsCmdInfoPtr=unsupportedCmds; unsCmdInfoPtr->name; unsCmdInfoPtr++) {
cmdPtr = (Command *) TclCreateObjCommandInNs(interp,
unsCmdInfoPtr->name, unsupportedNs, unsCmdInfoPtr->objProc,
unsCmdInfoPtr->clientData, NULL);
cmdPtr->nreProc = unsCmdInfoPtr->nreProc;
cmdPtr->compileProc = unsCmdInfoPtr->compileProc;
}
Tcl_Export(interp, unsupportedNs, "*", 1);
#ifdef USE_DTRACE
/*
* Register the tcl::dtrace command.
*/
Tcl_CreateObjCommand(interp, "::tcl::dtrace", DTraceObjCmd, NULL, NULL);
#endif /* USE_DTRACE */
/*
* Register the builtin math functions.
*/
nsPtr = Tcl_CreateNamespace(interp, "::tcl::mathfunc", NULL, NULL);
if (nsPtr == NULL) {
Tcl_Panic("Can't create math function namespace");
}
#define MATH_FUNC_PREFIX_LEN 17 /* == strlen("::tcl::mathfunc::") */
memcpy(mathFuncName, "::tcl::mathfunc::", MATH_FUNC_PREFIX_LEN);
for (builtinFuncPtr = BuiltinFuncTable; builtinFuncPtr->name != NULL;
builtinFuncPtr++) {
strcpy(mathFuncName + MATH_FUNC_PREFIX_LEN, builtinFuncPtr->name);
Tcl_CreateObjCommand(interp, mathFuncName,
builtinFuncPtr->objCmdProc, (void *)builtinFuncPtr->fn, NULL);
Tcl_Export(interp, nsPtr, builtinFuncPtr->name, 0);
}
/*
* Register the mathematical "operator" commands. [TIP #174]
*/
nsPtr = Tcl_CreateNamespace(interp, "::tcl::mathop", NULL, NULL);
if (nsPtr == NULL) {
Tcl_Panic("cannot create math operator namespace");
}
Tcl_Export(interp, nsPtr, "*", 1);
#define MATH_OP_PREFIX_LEN 15 /* == strlen("::tcl::mathop::") */
memcpy(mathFuncName, "::tcl::mathop::", MATH_OP_PREFIX_LEN);
for (opcmdInfoPtr=mathOpCmds ; opcmdInfoPtr->name!=NULL ; opcmdInfoPtr++){
TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)Tcl_Alloc(sizeof(TclOpCmdClientData));
occdPtr->op = opcmdInfoPtr->name;
occdPtr->i.numArgs = opcmdInfoPtr->i.numArgs;
occdPtr->expected = opcmdInfoPtr->expected;
strcpy(mathFuncName + MATH_OP_PREFIX_LEN, opcmdInfoPtr->name);
cmdPtr = (Command *) Tcl_CreateObjCommand(interp, mathFuncName,
opcmdInfoPtr->objProc, occdPtr, DeleteOpCmdClientData);
if (cmdPtr == NULL) {
Tcl_Panic("failed to create math operator %s",
opcmdInfoPtr->name);
} else if (opcmdInfoPtr->compileProc != NULL) {
cmdPtr->compileProc = opcmdInfoPtr->compileProc;
}
|
| ︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 |
* Register Tcl's version number.
* TIP #268: Full patchlevel instead of just major.minor
* TIP #599: Extended build information "+<UUID>.<tag1>.<tag2>...."
*/
Tcl_PkgProvideEx(interp, "Tcl", TCL_PATCH_LEVEL, &tclStubs);
Tcl_PkgProvideEx(interp, "tcl", TCL_PATCH_LEVEL, &tclStubs);
| < < < < < | < < < < < | 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 |
* Register Tcl's version number.
* TIP #268: Full patchlevel instead of just major.minor
* TIP #599: Extended build information "+<UUID>.<tag1>.<tag2>...."
*/
Tcl_PkgProvideEx(interp, "Tcl", TCL_PATCH_LEVEL, &tclStubs);
Tcl_PkgProvideEx(interp, "tcl", TCL_PATCH_LEVEL, &tclStubs);
Tcl_CmdInfo info2;
Tcl_Command buildInfoCmd = Tcl_CreateObjCommand(interp, "::tcl::build-info",
BuildInfoObjCmd, (void *)version, NULL);
Tcl_GetCommandInfoFromToken(buildInfoCmd, &info2);
info2.objProc2 = BuildInfoObjCmd2;
info2.objClientData2 = (void *)version;
Tcl_SetCommandInfoFromToken(buildInfoCmd, &info2);
if (TclTommath_Init(interp) != TCL_OK) {
Tcl_Panic("%s", Tcl_GetStringResult(interp));
}
if (TclOOInit(interp) != TCL_OK) {
Tcl_Panic("%s", Tcl_GetStringResult(interp));
}
if (TclZlibInit(interp) != TCL_OK || TclZipfs_Init(interp) != TCL_OK) {
Tcl_Panic("%s", Tcl_GetStringResult(interp));
}
TOP_CB(iPtr) = NULL;
return interp;
}
static void
DeleteOpCmdClientData(
void *clientData)
|
| ︙ | ︙ | |||
1344 1345 1346 1347 1348 1349 1350 | * recommended that those names be ASCII.) * * --------------------------------------------------------------------- */ void TclRegisterCommandTypeName( | | | 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 |
* 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);
|
| ︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 |
}
const char *
TclGetCommandTypeName(
Tcl_Command command)
{
Command *cmdPtr = (Command *) command;
| | | | 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 |
}
const char *
TclGetCommandTypeName(
Tcl_Command command)
{
Command *cmdPtr = (Command *) command;
Tcl_ObjCmdProc *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);
|
| ︙ | ︙ | |||
1417 1418 1419 1420 1421 1422 1423 |
static void
HideCommandInTclNs(
Tcl_Interp *interp,
const char *nsName,
const char *name,
Tcl_Obj *publicNameTuple)
{
| < < | < < < < < | < < < < < | | | | < | < | | | | < < | | > | | > | | > > | < > | | | | < > > > > | > | > > > > > | 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 |
static void
HideCommandInTclNs(
Tcl_Interp *interp,
const char *nsName,
const char *name,
Tcl_Obj *publicNameTuple)
{
Tcl_Obj *cmdName = Tcl_ObjPrintf("::tcl::%s::%s", nsName, name);
Tcl_Obj *hideName = Tcl_ObjPrintf("tcl:%s:%s", nsName, name);
#define INTERIM_HACK_NAME "___tmp"
// TODO: Fix the hiding machinery to handle namespaced commands.
if (TclRenameCommand(interp, TclGetString(cmdName),
INTERIM_HACK_NAME) != TCL_OK
|| Tcl_HideCommand(interp, INTERIM_HACK_NAME,
TclGetString(hideName)) != TCL_OK) {
Tcl_Panic("problem making '%s %s' safe: %s",
nsName, name, Tcl_GetStringResult(interp));
}
if (publicNameTuple) {
Tcl_IncrRefCount(publicNameTuple);
Tcl_CreateObjCommand(interp, TclGetString(cmdName),
BadEnsembleSubcommand, (void *)publicNameTuple,
BadEnsembleSubcommandCleanup);
}
TclDecrRefCount(cmdName);
TclDecrRefCount(hideName);
}
int
TclHideUnsafeCommands(
Tcl_Interp *interp) /* Hide commands in this interpreter. */
{
const CmdInfo *cmdInfoPtr;
const UnsafeEnsembleInfo *unsafePtr;
const UnsupportedCmdInfo *unsCmdInfoPtr;
if (interp == NULL) {
return TCL_ERROR;
}
for (cmdInfoPtr = builtInCmds; cmdInfoPtr->name != NULL; cmdInfoPtr++) {
if (!(cmdInfoPtr->flags & CMD_IS_SAFE)) {
Tcl_HideCommand(interp, cmdInfoPtr->name, cmdInfoPtr->name);
}
}
for (unsafePtr = unsafeEnsembleCommands;
unsafePtr->ensembleNsName; unsafePtr++) {
if (unsafePtr->commandName) {
/*
* Hide an ensemble subcommand.
*/
Tcl_Obj *cmdName = Tcl_ObjPrintf("::tcl::%s::%s",
unsafePtr->ensembleNsName, unsafePtr->commandName);
Tcl_Obj *hideName = Tcl_ObjPrintf("tcl:%s:%s",
unsafePtr->ensembleNsName, unsafePtr->commandName);
#define INTERIM_HACK_NAME "___tmp"
if (TclRenameCommand(interp, TclGetString(cmdName),
INTERIM_HACK_NAME) != TCL_OK
|| Tcl_HideCommand(interp, INTERIM_HACK_NAME,
TclGetString(hideName)) != TCL_OK) {
Tcl_Panic("problem making '%s %s' safe: %s",
unsafePtr->ensembleNsName, unsafePtr->commandName,
Tcl_GetStringResult(interp));
}
Tcl_CreateObjCommand(interp, TclGetString(cmdName),
BadEnsembleSubcommand, (void *)unsafePtr, NULL);
TclDecrRefCount(cmdName);
TclDecrRefCount(hideName);
} else {
/*
* Hide an ensemble main command (for compatibility).
*/
if (Tcl_HideCommand(interp, unsafePtr->ensembleNsName,
unsafePtr->ensembleNsName) != TCL_OK) {
Tcl_Panic("problem making '%s' safe: %s",
unsafePtr->ensembleNsName,
Tcl_GetStringResult(interp));
}
}
}
for (unsCmdInfoPtr=unsupportedCmds; unsCmdInfoPtr->name; unsCmdInfoPtr++) {
HideCommandInTclNs(interp, "unsupported", unsCmdInfoPtr->name, NULL);
}
|
| ︙ | ︙ | |||
1529 1530 1531 1532 1533 1534 1535 |
*----------------------------------------------------------------------
*/
static int
BadEnsembleSubcommand(
void *clientData,
Tcl_Interp *interp,
| | | < < | | 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 |
*----------------------------------------------------------------------
*/
static int
BadEnsembleSubcommand(
void *clientData,
Tcl_Interp *interp,
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /* objv */)
{
const UnsafeEnsembleInfo *infoPtr = (const UnsafeEnsembleInfo *)clientData;
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"not allowed to invoke subcommand %s of %s",
infoPtr->commandName, infoPtr->ensembleNsName));
Tcl_SetErrorCode(interp, "TCL", "SAFE", "SUBCOMMAND", (char *)NULL);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1819 1820 1821 1822 1823 1824 1825 |
*----------------------------------------------------------------------
*/
int
Tcl_InterpDeleted(
Tcl_Interp *interp)
{
| | | 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 |
*----------------------------------------------------------------------
*/
int
Tcl_InterpDeleted(
Tcl_Interp *interp)
{
return (((Interp *) interp)->flags & DELETED) ? 1 : 0;
}
/*
*----------------------------------------------------------------------
*
* Tcl_DeleteInterp --
*
|
| ︙ | ︙ | |||
1910 1911 1912 1913 1914 1915 1916 |
Tcl_HashSearch search;
Tcl_HashTable *hTablePtr;
ResolverScheme *resPtr, *nextResPtr;
Tcl_Size i;
/*
* Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup,
| | | 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 |
Tcl_HashSearch search;
Tcl_HashTable *hTablePtr;
ResolverScheme *resPtr, *nextResPtr;
Tcl_Size i;
/*
* Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup,
* unless we are exiting.
*/
if ((iPtr->numLevels > 0) && !TclInExit()) {
Tcl_Panic("DeleteInterpProc called with active evals");
}
/*
|
| ︙ | ︙ | |||
2549 2550 2551 2552 2553 2554 2555 | * The return value is a token for the command, which can be used in * future calls to Tcl_GetCommandName. * * Side effects: * If a command named cmdName already exists for interp, it is deleted. * In the future, when cmdName is seen as the name of a command by * Tcl_Eval, proc will be called. To support the bytecode interpreter, | | | 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 | * The return value is a token for the command, which can be used in * future calls to Tcl_GetCommandName. * * Side effects: * If a command named cmdName already exists for interp, it is deleted. * In the future, when cmdName is seen as the name of a command by * Tcl_Eval, proc will be called. To support the bytecode interpreter, * the command is created with a wrapper Tcl_ObjCmdProc * (InvokeStringCommand) that eventually calls proc. When the command * is deleted from the table, deleteProc will be called. See the manual * entry for details on the calling sequence. * *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
2577 2578 2579 2580 2581 2582 2583 |
{
Interp *iPtr = (Interp *) interp;
ImportRef *oldRefPtr = NULL;
Namespace *nsPtr;
Command *cmdPtr;
Tcl_HashEntry *hPtr;
const char *tail;
| | < | 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 |
{
Interp *iPtr = (Interp *) interp;
ImportRef *oldRefPtr = NULL;
Namespace *nsPtr;
Command *cmdPtr;
Tcl_HashEntry *hPtr;
const char *tail;
int isNew = 0, deleted = 0;
ImportedCmdData *dataPtr;
if (iPtr->flags & DELETED) {
/*
* The interpreter is being deleted. Don't create any new commands;
* it's not safe to muck with the interpreter anymore.
*/
|
| ︙ | ︙ | |||
2651 2652 2653 2654 2655 2656 2657 |
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
oldRefPtr = cmdPtr->importRefPtr;
cmdPtr->importRefPtr = NULL;
}
TclCleanupCommandMacro(cmdPtr);
| | | 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 |
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
oldRefPtr = cmdPtr->importRefPtr;
cmdPtr->importRefPtr = NULL;
}
TclCleanupCommandMacro(cmdPtr);
deleted = 1;
}
if (!isNew) {
/*
* If the deletion callback recreated the command, just throw away the
* new command (if we try to delete it again, we could get stuck in an
* infinite loop).
|
| ︙ | ︙ | |||
2693 2694 2695 2696 2697 2698 2699 |
cmdPtr = (Command *)Tcl_Alloc(sizeof(Command));
Tcl_SetHashValue(hPtr, cmdPtr);
cmdPtr->hPtr = hPtr;
cmdPtr->nsPtr = nsPtr;
cmdPtr->refCount = 1;
cmdPtr->cmdEpoch = 0;
cmdPtr->compileProc = NULL;
| | | | | | 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 |
cmdPtr = (Command *)Tcl_Alloc(sizeof(Command));
Tcl_SetHashValue(hPtr, cmdPtr);
cmdPtr->hPtr = hPtr;
cmdPtr->nsPtr = nsPtr;
cmdPtr->refCount = 1;
cmdPtr->cmdEpoch = 0;
cmdPtr->compileProc = NULL;
cmdPtr->objProc = InvokeStringCommand;
cmdPtr->objClientData = cmdPtr;
cmdPtr->proc = proc;
cmdPtr->clientData = clientData;
cmdPtr->deleteProc = deleteProc;
cmdPtr->deleteData = clientData;
cmdPtr->flags = 0;
cmdPtr->importRefPtr = NULL;
cmdPtr->tracePtr = NULL;
cmdPtr->nreProc = NULL;
/*
* Plug in any existing import references found above. Be sure to update
* all of these references to point to the new command.
*/
if (oldRefPtr != NULL) {
cmdPtr->importRefPtr = oldRefPtr;
while (oldRefPtr != NULL) {
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
dataPtr = (ImportedCmdData *)refCmdPtr->objClientData;
dataPtr->realCmdPtr = cmdPtr;
oldRefPtr = oldRefPtr->nextPtr;
}
}
/*
* We just created a command, so in its namespace and all of its parent
|
| ︙ | ︙ | |||
2747 2748 2749 2750 2751 2752 2753 | * * Side effects: * If a command named "cmdName" already exists for interp, it is * first deleted. Then the new command is created from the arguments. * * In the future, during bytecode evaluation when "cmdName" is seen as * the name of a command by Tcl_EvalObj or Tcl_Eval, the object-based | | < | | | | | | | | < | < | | | < | | | 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 |
*
* Side effects:
* If a command named "cmdName" already exists for interp, it is
* first deleted. Then the new command is created from the arguments.
*
* In the future, during bytecode evaluation when "cmdName" is seen as
* the name of a command by Tcl_EvalObj or Tcl_Eval, the object-based
* Tcl_ObjCmdProc proc will be called. When the command is deleted from
* the table, deleteProc will be called. See the manual entry for details
* on the calling sequence.
*
*----------------------------------------------------------------------
*/
typedef struct {
Tcl_ObjCmdProc2 *proc;
void *clientData; /* Arbitrary value to pass to proc function. */
Tcl_CmdDeleteProc *deleteProc;
void *deleteData; /* Arbitrary value to pass to deleteProc function. */
Tcl_ObjCmdProc2 *nreProc;
} CmdWrapperInfo;
static int
CmdWrapperProc(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj * const *objv)
{
CmdWrapperInfo *info = (CmdWrapperInfo *) clientData;
if (objc < 0) {
objc = -1;
}
return info->proc(info->clientData, interp, objc, objv);
}
static void
CmdWrapperDeleteProc(
void *clientData)
{
CmdWrapperInfo *info = (CmdWrapperInfo *) clientData;
clientData = info->deleteData;
Tcl_CmdDeleteProc *deleteProc = info->deleteProc;
Tcl_Free(info);
if (deleteProc != NULL) {
deleteProc(clientData);
}
}
Tcl_Command
Tcl_CreateObjCommand2(
Tcl_Interp *interp, /* Token for command interpreter (returned by
* previous call to Tcl_CreateInterp). */
const char *cmdName, /* Name of command. If it contains namespace
* qualifiers, the new command is put in the
* specified namespace; otherwise it is put in
* the global namespace. */
Tcl_ObjCmdProc2 *proc, /* Object-based function to associate with
* name. */
void *clientData, /* Arbitrary value to pass to object
* function. */
Tcl_CmdDeleteProc *deleteProc)
/* If not NULL, gives a function to call when
* this command is deleted. */
{
CmdWrapperInfo *info = (CmdWrapperInfo *)Tcl_Alloc(sizeof(CmdWrapperInfo));
info->proc = proc;
info->clientData = clientData;
info->deleteProc = deleteProc;
info->deleteData = clientData;
return Tcl_CreateObjCommand(interp, cmdName,
(proc ? CmdWrapperProc : NULL),
info, CmdWrapperDeleteProc);
}
Tcl_Command
Tcl_CreateObjCommand(
Tcl_Interp *interp, /* Token for command interpreter (returned by
* previous call to Tcl_CreateInterp). */
const char *cmdName, /* Name of command. If it contains namespace
* qualifiers, the new command is put in the
* specified namespace; otherwise it is put in
* the global namespace. */
Tcl_ObjCmdProc *proc, /* Object-based function to associate with
* name. */
void *clientData, /* Arbitrary value to pass to object
* function. */
Tcl_CmdDeleteProc *deleteProc)
/* If not NULL, gives a function to call when
* this command is deleted. */
{
|
| ︙ | ︙ | |||
2878 2879 2880 2881 2882 2883 2884 |
Tcl_Command
TclCreateObjCommandInNs(
Tcl_Interp *interp,
const char *cmdName, /* Name of command, without any namespace
* components. */
Tcl_Namespace *namesp, /* The namespace to create the command in */
| | | < | 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 |
Tcl_Command
TclCreateObjCommandInNs(
Tcl_Interp *interp,
const char *cmdName, /* Name of command, without any namespace
* components. */
Tcl_Namespace *namesp, /* The namespace to create the command in */
Tcl_ObjCmdProc *proc, /* Object-based function to associate with
* name. */
void *clientData, /* Arbitrary value to pass to object
* function. */
Tcl_CmdDeleteProc *deleteProc)
/* If not NULL, gives a function to call when
* this command is deleted. */
{
int deleted = 0, isNew = 0;
Command *cmdPtr;
ImportRef *oldRefPtr = NULL;
ImportedCmdData *dataPtr;
Tcl_HashEntry *hPtr;
Namespace *nsPtr = (Namespace *) namesp;
/*
|
| ︙ | ︙ | |||
2947 2948 2949 2950 2951 2952 2953 |
TclNsDecrRefCount(cmdPtr->nsPtr);
if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
oldRefPtr = cmdPtr->importRefPtr;
cmdPtr->importRefPtr = NULL;
}
TclCleanupCommandMacro(cmdPtr);
| | | 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 |
TclNsDecrRefCount(cmdPtr->nsPtr);
if (cmdPtr->flags & CMD_REDEF_IN_PROGRESS) {
oldRefPtr = cmdPtr->importRefPtr;
cmdPtr->importRefPtr = NULL;
}
TclCleanupCommandMacro(cmdPtr);
deleted = 1;
}
if (!isNew) {
/*
* If the deletion callback recreated the command, just throw away the
* new command (if we try to delete it again, we could get stuck in an
* infinite loop).
*/
|
| ︙ | ︙ | |||
2988 2989 2990 2991 2992 2993 2994 |
cmdPtr = (Command *)Tcl_Alloc(sizeof(Command));
Tcl_SetHashValue(hPtr, cmdPtr);
cmdPtr->hPtr = hPtr;
cmdPtr->nsPtr = nsPtr;
cmdPtr->refCount = 1;
cmdPtr->cmdEpoch = 0;
cmdPtr->compileProc = NULL;
| | | | | | 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 |
cmdPtr = (Command *)Tcl_Alloc(sizeof(Command));
Tcl_SetHashValue(hPtr, cmdPtr);
cmdPtr->hPtr = hPtr;
cmdPtr->nsPtr = nsPtr;
cmdPtr->refCount = 1;
cmdPtr->cmdEpoch = 0;
cmdPtr->compileProc = NULL;
cmdPtr->objProc = proc;
cmdPtr->objClientData = clientData;
cmdPtr->proc = NULL;
cmdPtr->clientData = NULL;
cmdPtr->deleteProc = deleteProc;
cmdPtr->deleteData = clientData;
cmdPtr->flags = 0;
cmdPtr->importRefPtr = NULL;
cmdPtr->tracePtr = NULL;
cmdPtr->nreProc = NULL;
/*
* Plug in any existing import references found above. Be sure to update
* all of these references to point to the new command.
*/
if (oldRefPtr != NULL) {
cmdPtr->importRefPtr = oldRefPtr;
while (oldRefPtr != NULL) {
Command *refCmdPtr = oldRefPtr->importedCmdPtr;
dataPtr = (ImportedCmdData*)refCmdPtr->objClientData;
cmdPtr->refCount++;
TclCleanupCommandMacro(dataPtr->realCmdPtr);
dataPtr->realCmdPtr = cmdPtr;
oldRefPtr = oldRefPtr->nextPtr;
}
}
|
| ︙ | ︙ | |||
3033 3034 3035 3036 3037 3038 3039 | } /* *---------------------------------------------------------------------- * * InvokeStringCommand -- * | | | | | < | | < < < < < < | | 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 |
}
/*
*----------------------------------------------------------------------
*
* InvokeStringCommand --
*
* "Wrapper" Tcl_ObjCmdProc used to call an existing string-based
* Tcl_CmdProc if no object-based function exists for a command. A
* pointer to this function is stored as the Tcl_ObjCmdProc in a Command
* structure. It simply turns around and calls the string Tcl_CmdProc in
* the Command structure.
*
* Results:
* A standard Tcl object result value.
*
* Side effects:
* Besides those side effects of the called Tcl_CmdProc,
* InvokeStringCommand allocates and frees storage.
*
*----------------------------------------------------------------------
*/
int
InvokeStringCommand(
void *clientData, /* Points to command's Command structure. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Command *cmdPtr = (Command *)clientData;
int i, result;
const char **argv = (const char **)
TclStackAlloc(interp, (objc + 1) * sizeof(char *));
for (i = 0; i < objc; i++) {
argv[i] = TclGetString(objv[i]);
}
argv[objc] = 0;
/*
* Invoke the command's string-based Tcl_CmdProc.
*/
result = cmdPtr->proc(cmdPtr->clientData, interp, objc, argv);
TclStackFree(interp, (void *) argv);
return result;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
3344 3345 3346 3347 3348 3349 3350 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | < | | > > > | | | | | | > > > | < | | | | | | | | < | | | | | < < < | | | | < < | 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
InvokeObj2Command(
void *clientData, /* Points to command's Command structure. */
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result;
Command *cmdPtr = (Command *)clientData;
if (objc > INT_MAX) {
return TclCommandWordLimitError(interp, objc);
}
if (cmdPtr->objProc != NULL) {
result = cmdPtr->objProc(cmdPtr->objClientData, interp, (int)objc, objv);
} else {
result = Tcl_NRCallObjProc(interp, cmdPtr->nreProc,
cmdPtr->objClientData, (int)objc, objv);
}
return result;
}
static int
CmdWrapper2Proc(
void *clientData,
Tcl_Interp *interp,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
Command *cmdPtr = (Command *) clientData;
if (objc > INT_MAX) {
return TclCommandWordLimitError(interp, objc);
}
return cmdPtr->objProc(cmdPtr->objClientData, interp, (int)objc, objv);
}
int
Tcl_SetCommandInfoFromToken(
Tcl_Command cmd,
const Tcl_CmdInfo *infoPtr)
{
Command *cmdPtr; /* Internal representation of the command */
if (cmd == NULL) {
return 0;
}
/*
* The isNativeObjectProc and nsPtr members of *infoPtr are ignored.
*/
cmdPtr = (Command *) cmd;
cmdPtr->proc = infoPtr->proc;
cmdPtr->clientData = infoPtr->clientData;
if (infoPtr->objProc == NULL) {
cmdPtr->objProc = InvokeStringCommand;
cmdPtr->objClientData = cmdPtr;
cmdPtr->nreProc = NULL;
} else {
if (infoPtr->objProc != cmdPtr->objProc) {
cmdPtr->nreProc = NULL;
cmdPtr->objProc = infoPtr->objProc;
}
cmdPtr->objClientData = infoPtr->objClientData;
}
if (cmdPtr->deleteProc == CmdWrapperDeleteProc) {
CmdWrapperInfo *info = (CmdWrapperInfo *) cmdPtr->deleteData;
if (infoPtr->objProc2 == NULL) {
info->proc = InvokeObj2Command;
info->clientData = cmdPtr;
info->nreProc = NULL;
} else {
if (infoPtr->objProc2 != info->proc) {
info->nreProc = NULL;
info->proc = infoPtr->objProc2;
}
info->clientData = infoPtr->objClientData2;
}
info->deleteProc = infoPtr->deleteProc;
info->deleteData = infoPtr->deleteData;
} else {
if ((infoPtr->objProc2 != NULL) && (infoPtr->objProc2 != CmdWrapper2Proc)) {
CmdWrapperInfo *info = (CmdWrapperInfo *)Tcl_Alloc(sizeof(CmdWrapperInfo));
info->proc = infoPtr->objProc2;
info->clientData = infoPtr->objClientData2;
info->nreProc = NULL;
info->deleteProc = infoPtr->deleteProc;
info->deleteData = infoPtr->deleteData;
cmdPtr->deleteProc = CmdWrapperDeleteProc;
cmdPtr->deleteData = info;
} else {
cmdPtr->deleteProc = infoPtr->deleteProc;
cmdPtr->deleteData = infoPtr->deleteData;
}
}
return 1;
}
|
| ︙ | ︙ | |||
3513 3514 3515 3516 3517 3518 3519 |
* Set isNativeObjectProc 1 if objProc was registered by a call to
* Tcl_CreateObjCommand. Set isNativeObjectProc 2 if objProc was
* registered by a call to Tcl_CreateObjCommand2. Otherwise set it to 0.
*/
cmdPtr = (Command *) cmd;
infoPtr->isNativeObjectProc =
| | | | < | | | | | < < < | | < | 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 |
* Set isNativeObjectProc 1 if objProc was registered by a call to
* Tcl_CreateObjCommand. Set isNativeObjectProc 2 if objProc was
* registered by a call to Tcl_CreateObjCommand2. Otherwise set it to 0.
*/
cmdPtr = (Command *) cmd;
infoPtr->isNativeObjectProc =
(cmdPtr->objProc != InvokeStringCommand);
infoPtr->objProc = cmdPtr->objProc;
infoPtr->objClientData = cmdPtr->objClientData;
infoPtr->proc = cmdPtr->proc;
infoPtr->clientData = cmdPtr->clientData;
if (cmdPtr->deleteProc == CmdWrapperDeleteProc) {
CmdWrapperInfo *info = (CmdWrapperInfo *)cmdPtr->deleteData;
infoPtr->deleteProc = info->deleteProc;
infoPtr->deleteData = info->deleteData;
infoPtr->objProc2 = info->proc;
infoPtr->objClientData2 = info->clientData;
if (cmdPtr->objProc == CmdWrapperProc) {
infoPtr->isNativeObjectProc = 2;
}
} else {
infoPtr->deleteProc = cmdPtr->deleteProc;
infoPtr->deleteData = cmdPtr->deleteData;
infoPtr->objProc2 = CmdWrapper2Proc;
infoPtr->objClientData2 = cmdPtr;
}
infoPtr->namespacePtr = (Tcl_Namespace *) cmdPtr->nsPtr;
return 1;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
3851 3852 3853 3854 3855 3856 3857 |
/*
* A number of tests for particular kinds of commands are done by checking
* whether the objProc field holds a known value. Set the field to NULL so
* that such tests won't have false positives when applied to deleted
* commands.
*/
| | | 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 |
/*
* A number of tests for particular kinds of commands are done by checking
* whether the objProc field holds a known value. Set the field to NULL so
* that such tests won't have false positives when applied to deleted
* commands.
*/
cmdPtr->objProc = NULL;
/*
* Now free the Command structure, unless there is another reference to it
* from a CmdName Tcl object in some ByteCode code sequence. In that case,
* delay the cleanup until all references are either discarded (when a
* ByteCode is freed) or replaced by a new reference (when a cached
* CmdName Command reference is found to be invalid and
|
| ︙ | ︙ | |||
3925 3926 3927 3928 3929 3930 3931 |
return NULL;
}
}
cmdPtr->flags |= CMD_TRACE_ACTIVE;
result = NULL;
active.nextPtr = iPtr->activeCmdTracePtr;
| | | 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 |
return NULL;
}
}
cmdPtr->flags |= CMD_TRACE_ACTIVE;
result = NULL;
active.nextPtr = iPtr->activeCmdTracePtr;
active.reverseScan = 0;
iPtr->activeCmdTracePtr = &active;
if (flags & TCL_TRACE_DELETE) {
flags |= TCL_TRACE_DESTROYED;
}
active.cmdPtr = cmdPtr;
|
| ︙ | ︙ | |||
4084 4085 4086 4087 4088 4089 4090 | * deleted or when the last ByteCode referring to it is freed. * *---------------------------------------------------------------------- */ void TclCleanupCommand( | | | 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 |
* deleted or when the last ByteCode referring to it is freed.
*
*----------------------------------------------------------------------
*/
void
TclCleanupCommand(
Command *cmdPtr) /* Points to the Command structure to
* be freed. */
{
if (cmdPtr->refCount-- <= 1) {
Tcl_Free(cmdPtr);
}
}
|
| ︙ | ︙ | |||
4439 4440 4441 4442 4443 4444 4445 |
*/
int
Tcl_EvalObjv(
Tcl_Interp *interp, /* Interpreter in which to evaluate the
* command. Also used for error reporting. */
Tcl_Size objc, /* Number of words in command. */
| | | | 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 |
*/
int
Tcl_EvalObjv(
Tcl_Interp *interp, /* Interpreter in which to evaluate the
* command. Also used for error reporting. */
Tcl_Size objc, /* Number of words in command. */
Tcl_Obj *const objv[], /* An array of pointers to objects that are
* the words that make up the command. */
int flags) /* Collection of OR-ed bits that control the
* evaluation of the script. Only
* TCL_EVAL_GLOBAL, TCL_EVAL_INVOKE and
* TCL_EVAL_NOERR are currently supported. */
{
int result;
NRE_callback *rootPtr = TOP_CB(interp);
result = TclNREvalObjv(interp, objc, objv, flags, NULL);
return TclNRRunCallbacks(interp, result, rootPtr);
}
int
TclNREvalObjv(
Tcl_Interp *interp, /* Interpreter in which to evaluate the
* command. Also used for error reporting. */
Tcl_Size objc, /* Number of words in command. */
Tcl_Obj *const objv[], /* An array of pointers to objects that are
* the words that make up the command. */
int flags, /* Collection of OR-ed bits that control the
* evaluation of the script. Only
* TCL_EVAL_GLOBAL, TCL_EVAL_INVOKE and
* TCL_EVAL_NOERR are currently supported. */
Command *cmdPtr) /* NULL if the Command is to be looked up
* here, otherwise the pointer to the
|
| ︙ | ︙ | |||
4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 |
}
/*
* Configure evaluation context to match the requested flags.
*/
if (iPtr->lookupNsPtr) {
/*
* Capture the namespace we should do command name resolution in, as
* instructed by our caller sneaking it in to us in a private interp
* field. Clear that field right away so we cannot possibly have its
* use leak where it should not. The sneaky message pass is done.
*
* Use of this mechanism overrides the TCL_EVAL_GLOBAL flag.
* TODO: Is that a bug?
*/
lookupNsPtr = iPtr->lookupNsPtr;
iPtr->lookupNsPtr = NULL;
} else if (flags & TCL_EVAL_INVOKE) {
lookupNsPtr = iPtr->globalNsPtr;
} else {
/*
* TCL_EVAL_INVOKE was not set: clear rewrite rules
*/
TclResetRewriteEnsemble(interp, 1);
if (flags & TCL_EVAL_GLOBAL) {
| > > | 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 |
}
/*
* Configure evaluation context to match the requested flags.
*/
if (iPtr->lookupNsPtr) {
/*
* Capture the namespace we should do command name resolution in, as
* instructed by our caller sneaking it in to us in a private interp
* field. Clear that field right away so we cannot possibly have its
* use leak where it should not. The sneaky message pass is done.
*
* Use of this mechanism overrides the TCL_EVAL_GLOBAL flag.
* TODO: Is that a bug?
*/
lookupNsPtr = iPtr->lookupNsPtr;
iPtr->lookupNsPtr = NULL;
} else if (flags & TCL_EVAL_INVOKE) {
lookupNsPtr = iPtr->globalNsPtr;
} else {
/*
* TCL_EVAL_INVOKE was not set: clear rewrite rules
*/
TclResetRewriteEnsemble(interp, 1);
if (flags & TCL_EVAL_GLOBAL) {
|
| ︙ | ︙ | |||
4646 4647 4648 4649 4650 4651 4652 |
cmdPtr->refCount++;
TclNRAddCallback(interp, TEOV_RunLeaveTraces, INT2PTR(objc),
commandPtr, cmdPtr, objv);
}
TclNRAddCallback(interp, Dispatch,
| | | | | < | 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 |
cmdPtr->refCount++;
TclNRAddCallback(interp, TEOV_RunLeaveTraces, INT2PTR(objc),
commandPtr, cmdPtr, objv);
}
TclNRAddCallback(interp, Dispatch,
cmdPtr->nreProc ? cmdPtr->nreProc : cmdPtr->objProc,
cmdPtr->objClientData, INT2PTR(objc), objv);
return TCL_OK;
}
static int
Dispatch(
void *data[],
Tcl_Interp *interp,
TCL_UNUSED(int) /*result*/)
{
Tcl_ObjCmdProc *objProc = (Tcl_ObjCmdProc *)data[0];
void *clientData = data[1];
Tcl_Size objc = PTR2INT(data[2]);
Tcl_Obj **objv = (Tcl_Obj **)data[3];
Interp *iPtr = (Interp *) interp;
#ifdef USE_DTRACE
if (TCL_DTRACE_CMD_ARGS_ENABLED()) {
const char *a[10];
Tcl_Size i = 0;
while (i < 10) {
a[i] = i < objc ? TclGetString(objv[i]) : NULL; i++;
}
TCL_DTRACE_CMD_ARGS(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
a[8], a[9]);
}
if (TCL_DTRACE_CMD_INFO_ENABLED() && iPtr->cmdFramePtr) {
Tcl_Obj *info = TclInfoFrame(interp, iPtr->cmdFramePtr);
const char *a[6];
|
| ︙ | ︙ | |||
4775 4776 4777 4778 4779 4780 4781 |
*----------------------------------------------------------------------
*/
static void
TEOV_PushExceptionHandlers(
Tcl_Interp *interp,
Tcl_Size objc,
| | | > | 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 |
*----------------------------------------------------------------------
*/
static void
TEOV_PushExceptionHandlers(
Tcl_Interp *interp,
Tcl_Size objc,
Tcl_Obj *const objv[],
int flags)
{
Interp *iPtr = (Interp *) interp;
/*
* If any error processing is necessary, push the appropriate records.
* Note that we have to push them in the inverse order: first the one that
* has to run last.
*/
if (!(flags & TCL_EVAL_INVOKE)) {
/*
* Error messages
*/
TclNRAddCallback(interp, TEOV_Error, INT2PTR(objc),
objv, NULL, NULL);
}
if (iPtr->numLevels == 1) {
/*
* No CONTINUE or BREAK at level 0, manage RETURN
*/
|
| ︙ | ︙ | |||
4815 4816 4817 4818 4819 4820 4821 |
Interp *iPtr = (Interp *) interp;
/*
* Change the varFrame to be the rootVarFrame, and push a record to
* restore things at the end.
*/
| | | | | 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 |
Interp *iPtr = (Interp *) interp;
/*
* Change the varFrame to be the rootVarFrame, and push a record to
* restore things at the end.
*/
TclNRAddCallback(interp, TEOV_RestoreVarFrame, iPtr->varFramePtr, NULL,
NULL, NULL);
iPtr->varFramePtr = iPtr->rootFramePtr;
}
static int
TEOV_RestoreVarFrame(
void *data[],
Tcl_Interp *interp,
int result)
{
((Interp *) interp)->varFramePtr = (CallFrame *)data[0];
return result;
}
static int
TEOV_Exception(
void *data[],
Tcl_Interp *interp,
int result)
{
Interp *iPtr = (Interp *) interp;
int allowExceptions = (PTR2INT(data[0]) & TCL_ALLOW_EXCEPTIONS);
if (result != TCL_OK) {
if (result == TCL_RETURN) {
result = TclUpdateReturnInfo(iPtr);
}
if ((result != TCL_OK) && (result != TCL_ERROR) && !allowExceptions) {
ProcessUnexpectedResult(interp, result);
|
| ︙ | ︙ | |||
4892 4893 4894 4895 4896 4897 4898 |
return result;
}
static int
TEOV_NotFound(
Tcl_Interp *interp,
Tcl_Size objc,
| | | 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 |
return result;
}
static int
TEOV_NotFound(
Tcl_Interp *interp,
Tcl_Size objc,
Tcl_Obj *const objv[],
Namespace *lookupNsPtr)
{
Command * cmdPtr;
Interp *iPtr = (Interp *) interp;
Tcl_Size i, newObjc, handlerObjc;
Tcl_Obj **newObjv, **handlerObjv;
CallFrame *varFramePtr = iPtr->varFramePtr;
|
| ︙ | ︙ | |||
4980 4981 4982 4983 4984 4985 4986 |
}
if (lookupNsPtr) {
savedNsPtr = varFramePtr->nsPtr;
varFramePtr->nsPtr = lookupNsPtr;
}
TclSkipTailcall(interp);
| | | | 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 |
}
if (lookupNsPtr) {
savedNsPtr = varFramePtr->nsPtr;
varFramePtr->nsPtr = lookupNsPtr;
}
TclSkipTailcall(interp);
TclNRAddCallback(interp, TEOV_NotFoundCallback, INT2PTR(handlerObjc),
newObjv, savedNsPtr, NULL);
return TclNREvalObjv(interp, newObjc, newObjv, TCL_EVAL_NOERR, NULL);
}
static int
TEOV_NotFoundCallback(
void *data[],
Tcl_Interp *interp,
|
| ︙ | ︙ | |||
5020 5021 5022 5023 5024 5025 5026 |
static int
TEOV_RunEnterTraces(
Tcl_Interp *interp,
Command **cmdPtrPtr,
Tcl_Obj *commandPtr,
Tcl_Size objc,
| | | 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 |
static int
TEOV_RunEnterTraces(
Tcl_Interp *interp,
Command **cmdPtrPtr,
Tcl_Obj *commandPtr,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
Interp *iPtr = (Interp *) interp;
Command *cmdPtr = *cmdPtrPtr;
Tcl_Size length, newEpoch, cmdEpoch = cmdPtr->cmdEpoch;
int traceCode = TCL_OK;
const char *command = TclGetStringFromObj(commandPtr, &length);
|
| ︙ | ︙ | |||
5214 5215 5216 5217 5218 5219 5220 |
const char *script, /* First character of script to evaluate. */
Tcl_Size numBytes, /* Number of bytes in script. If -1, the
* script consists of all bytes up to the
* first NUL character. */
int flags, /* Collection of OR-ed bits that control the
* evaluation of the script. Only
* TCL_EVAL_GLOBAL is currently supported. */
| | | 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 |
const char *script, /* First character of script to evaluate. */
Tcl_Size numBytes, /* Number of bytes in script. If -1, the
* script consists of all bytes up to the
* first NUL character. */
int flags, /* Collection of OR-ed bits that control the
* evaluation of the script. Only
* TCL_EVAL_GLOBAL is currently supported. */
Tcl_Size line, /* The line the script starts on. */
Tcl_Size *clNextOuter, /* Information about an outer context for */
const char *outerScript) /* continuation line data. This is set only in
* TclSubstTokens(), to properly handle
* [...]-nested commands. The 'outerScript'
* refers to the most-outer script containing
* the embedded command, which is referred to
* by 'script'. The 'clNextOuter' refers to
|
| ︙ | ︙ | |||
5237 5238 5239 5240 5241 5242 5243 |
* generating arguments for which this is
* true. */
{
Interp *iPtr = (Interp *) interp;
const char *p, *next;
const int minObjs = 20;
Tcl_Obj **objv, **objvSpace;
| | | | < | | | | | 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 |
* generating arguments for which this is
* true. */
{
Interp *iPtr = (Interp *) interp;
const char *p, *next;
const int minObjs = 20;
Tcl_Obj **objv, **objvSpace;
int *expand;
Tcl_Size *lines, *lineSpace;
Tcl_Token *tokenPtr;
int expandRequested, code = TCL_OK;
Tcl_Size bytesLeft, commandLength;
CallFrame *savedVarFramePtr;/* Saves old copy of iPtr->varFramePtr in case
* TCL_EVAL_GLOBAL was set. */
int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS);
int gotParse = 0;
Tcl_Size i, objectsUsed = 0;
/* These variables keep track of how much
* state has been allocated while evaluating
* the script, so that it can be freed
* properly if an error occurs. */
Tcl_Parse *parsePtr = (Tcl_Parse *)TclStackAlloc(interp, sizeof(Tcl_Parse));
CmdFrame *eeFramePtr = (CmdFrame *)TclStackAlloc(interp, sizeof(CmdFrame));
Tcl_Obj **stackObjArray = (Tcl_Obj **)TclStackAlloc(interp, minObjs * sizeof(Tcl_Obj *));
int *expandStack = (int *)TclStackAlloc(interp, minObjs * sizeof(int));
Tcl_Size *linesStack = (Tcl_Size *)TclStackAlloc(interp, minObjs * sizeof(Tcl_Size));
/* TIP #280 Structures for tracking of command
* locations. */
Tcl_Size *clNext = NULL; /* Pointer for the tracking of invisible
* continuation lines. Initialized only if the
* caller gave us a table of locations to
* track, via scriptCLLocPtr. It always refers
* to the table entry holding the location of
|
| ︙ | ︙ | |||
5372 5373 5374 5375 5376 5377 5378 | * block, and do not forget invisible continuation lines. */ TclAdvanceLines(&line, p, parsePtr->commandStart); TclAdvanceContinuations(&line, &clNext, parsePtr->commandStart - outerScript); | | | | | | | > > | 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 |
* block, and do not forget invisible continuation lines.
*/
TclAdvanceLines(&line, p, parsePtr->commandStart);
TclAdvanceContinuations(&line, &clNext,
parsePtr->commandStart - outerScript);
gotParse = 1;
if (parsePtr->numWords > 0) {
/*
* TIP #280. Track lines within the words of the current
* command. We use a separate pointer into the table of
* continuation line locations to not lose our position for the
* per-command parsing.
*/
Tcl_Size wordLine = line;
const char *wordStart = parsePtr->commandStart;
Tcl_Size *wordCLNext = clNext;
Tcl_Size objectsNeeded = 0;
Tcl_Size numWords = parsePtr->numWords;
/*
* Generate an array of objects for the words of the command.
*/
if (numWords > minObjs) {
expand = (int *)Tcl_Alloc(numWords * sizeof(int));
objvSpace = (Tcl_Obj **)
Tcl_Alloc(numWords * sizeof(Tcl_Obj *));
lineSpace = (Tcl_Size *)
Tcl_Alloc(numWords * sizeof(Tcl_Size));
}
expandRequested = 0;
objv = objvSpace;
lines = lineSpace;
iPtr->cmdFramePtr = eeFramePtr->nextPtr;
for (objectsUsed = 0, tokenPtr = parsePtr->tokenPtr;
objectsUsed < numWords;
objectsUsed++, tokenPtr += tokenPtr->numComponents + 1) {
Tcl_Size additionalObjsCount;
/*
* TIP #280. Track lines to current word. Save the information
* on a per-word basis, signaling dynamic words as needed.
* Make the information available to the recursively called
* evaluator as well, including the type of context (source
* vs. eval).
*/
|
| ︙ | ︙ | |||
5452 5453 5454 5455 5456 5457 5458 | */ Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf( "\n (expanding word %" TCL_SIZE_MODIFIER "d)", objectsUsed)); Tcl_DecrRefCount(objv[objectsUsed]); break; } | | | > > > > > > | > > > > | | | 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 |
*/
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (expanding word %" TCL_SIZE_MODIFIER "d)", objectsUsed));
Tcl_DecrRefCount(objv[objectsUsed]);
break;
}
expandRequested = 1;
expand[objectsUsed] = 1;
additionalObjsCount = (numElements ? numElements : 1);
} else {
expand[objectsUsed] = 0;
additionalObjsCount = 1;
}
/* Currently max command words in INT_MAX */
if (additionalObjsCount > INT_MAX ||
objectsNeeded > (INT_MAX - additionalObjsCount)) {
code = TclCommandWordLimitError(interp, -1);
Tcl_DecrRefCount(objv[objectsUsed]);
break;
}
objectsNeeded += additionalObjsCount;
if (wordCLNext) {
TclContinuationsEnterDerived(objv[objectsUsed],
wordStart - outerScript, wordCLNext);
}
} /* for loop */
iPtr->cmdFramePtr = eeFramePtr;
if (code != TCL_OK) {
goto error;
}
if (expandRequested) {
/*
* Some word expansion was requested. Check for objv resize.
*/
Tcl_Obj **copy = objvSpace;
Tcl_Size *lcopy = lineSpace;
Tcl_Size wordIdx = numWords;
Tcl_Size objIdx = objectsNeeded - 1;
if ((numWords > minObjs) || (objectsNeeded > minObjs)) {
objv = objvSpace = (Tcl_Obj **)Tcl_Alloc(objectsNeeded * sizeof(Tcl_Obj *));
lines = lineSpace = (Tcl_Size *)Tcl_Alloc(objectsNeeded * sizeof(Tcl_Size));
}
objectsUsed = 0;
while (wordIdx--) {
if (expand[wordIdx]) {
Tcl_Size numElements;
Tcl_Obj **elements, *temp = copy[wordIdx];
|
| ︙ | ︙ | |||
5586 5587 5588 5589 5590 5591 5592 | */ next = parsePtr->commandStart + parsePtr->commandSize; bytesLeft -= next - p; p = next; TclAdvanceLines(&line, parsePtr->commandStart, p); Tcl_FreeParse(parsePtr); | | | 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 |
*/
next = parsePtr->commandStart + parsePtr->commandSize;
bytesLeft -= next - p;
p = next;
TclAdvanceLines(&line, parsePtr->commandStart, p);
Tcl_FreeParse(parsePtr);
gotParse = 0;
} while (bytesLeft > 0);
iPtr->varFramePtr = savedVarFramePtr;
code = TCL_OK;
goto cleanup_return;
error:
/*
|
| ︙ | ︙ | |||
5681 5682 5683 5684 5685 5686 5687 | * * TIP #280 *---------------------------------------------------------------------- */ void TclAdvanceLines( | | | 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 |
*
* TIP #280
*----------------------------------------------------------------------
*/
void
TclAdvanceLines(
Tcl_Size *line,
const char *start,
const char *end)
{
const char *p;
for (p = start; p < end; p++) {
if (*p == '\n') {
|
| ︙ | ︙ | |||
5716 5717 5718 5719 5720 5721 5722 | * * TIP #280 *---------------------------------------------------------------------- */ void TclAdvanceContinuations( | | | | 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 |
*
* TIP #280
*----------------------------------------------------------------------
*/
void
TclAdvanceContinuations(
Tcl_Size *line,
Tcl_Size **clNextPtrPtr,
int loc)
{
/*
* Track the invisible continuation lines embedded in a script, if any.
* Here they are just spaces (already). They were removed by
* TclSubstTokens via TclParseBackslash.
*
* *clNextPtrPtr <=> We have continuation lines to track.
|
| ︙ | ︙ | |||
5891 5892 5893 5894 5895 5896 5897 |
* TIP #280
*----------------------------------------------------------------------
*/
void
TclArgumentBCEnter(
Tcl_Interp *interp,
| | | | 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 |
* TIP #280
*----------------------------------------------------------------------
*/
void
TclArgumentBCEnter(
Tcl_Interp *interp,
Tcl_Obj *objv[],
Tcl_Size objc,
void *codePtr,
CmdFrame *cfPtr,
Tcl_Size cmd,
Tcl_Size pc)
{
ExtCmdLoc *eclPtr;
Tcl_Size word;
ECL *ePtr;
CFWordBC *lastPtr = NULL;
Interp *iPtr = (Interp *) interp;
Tcl_HashEntry *hePtr = Tcl_FindHashEntry(iPtr->lineBCPtr, codePtr);
if (!hePtr) {
return;
|
| ︙ | ︙ | |||
5964 5965 5966 5967 5968 5969 5970 |
*/
cfwPtr->prevPtr = NULL;
} else {
/*
* The object is already on the stack, however it may have
* a different location now (literal sharing may map
| | | 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 |
*/
cfwPtr->prevPtr = NULL;
} else {
/*
* The object is already on the stack, however it may have
* a different location now (literal sharing may map
* multiple location to a single Tcl_Obj*. Save the old
* information in the new structure.
*/
cfwPtr->prevPtr = (CFWordBC *)Tcl_GetHashValue(hPtr);
}
Tcl_SetHashValue(hPtr, cfwPtr);
|
| ︙ | ︙ | |||
6052 6053 6054 6055 6056 6057 6058 |
*/
void
TclArgumentGet(
Tcl_Interp *interp,
Tcl_Obj *obj,
CmdFrame **cfPtrPtr,
| | | 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 |
*/
void
TclArgumentGet(
Tcl_Interp *interp,
Tcl_Obj *obj,
CmdFrame **cfPtrPtr,
int *wordPtr)
{
Interp *iPtr = (Interp *) interp;
Tcl_HashEntry *hPtr;
CmdFrame *framePtr;
/*
* An object which either has no string rep or else is a canonical list is
|
| ︙ | ︙ | |||
6152 6153 6154 6155 6156 6157 6158 |
* a previous call to Tcl_CreateInterp). */
Tcl_Obj *objPtr, /* Pointer to object containing commands to
* execute. */
int flags, /* Collection of OR-ed bits that control the
* evaluation of the script. Supported values
* are TCL_EVAL_GLOBAL and TCL_EVAL_DIRECT. */
const CmdFrame *invoker, /* Frame of the command doing the eval. */
| | | | 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 |
* a previous call to Tcl_CreateInterp). */
Tcl_Obj *objPtr, /* Pointer to object containing commands to
* execute. */
int flags, /* Collection of OR-ed bits that control the
* evaluation of the script. Supported values
* are TCL_EVAL_GLOBAL and TCL_EVAL_DIRECT. */
const CmdFrame *invoker, /* Frame of the command doing the eval. */
int word) /* Index of the word which is in objPtr. */
{
int result = TCL_OK;
NRE_callback *rootPtr = TOP_CB(interp);
result = TclNREvalObjEx(interp, objPtr, flags, invoker, word);
return TclNRRunCallbacks(interp, result, rootPtr);
}
int
TclNREvalObjEx(
Tcl_Interp *interp, /* Token for command interpreter (returned by
* a previous call to Tcl_CreateInterp). */
Tcl_Obj *objPtr, /* Pointer to object containing commands to
* execute. */
int flags, /* Collection of OR-ed bits that control the
* evaluation of the script. Supported values
* are TCL_EVAL_GLOBAL and TCL_EVAL_DIRECT. */
const CmdFrame *invoker, /* Frame of the command doing the eval. */
int word) /* Index of the word which is in objPtr. */
{
Interp *iPtr = (Interp *) interp;
int result;
/*
* This function consists of three independent blocks for: direct
* evaluation of canonical lists, compilation and bytecode execution and
|
| ︙ | ︙ | |||
6250 6251 6252 6253 6254 6255 6256 | iPtr->cmdFramePtr = eoFramePtr; flags |= TCL_EVAL_SOURCE_IN_FRAME; } TclMarkTailcall(interp); | | | | | | | | 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 |
iPtr->cmdFramePtr = eoFramePtr;
flags |= TCL_EVAL_SOURCE_IN_FRAME;
}
TclMarkTailcall(interp);
TclNRAddCallback(interp, TEOEx_ListCallback, listPtr, eoFramePtr,
objPtr, NULL);
TclListObjGetElements(NULL, listPtr, &objc, &objv);
return TclNREvalObjv(interp, objc, objv, flags, NULL);
}
if (!(flags & TCL_EVAL_DIRECT)) {
/*
* Let the compiler/engine subsystem do the evaluation.
*
* TIP #280 The invoker provides us with the context for the script.
* We transfer this to the byte code compiler.
*/
int allowExceptions = (iPtr->evalFlags & TCL_ALLOW_EXCEPTIONS);
ByteCode *codePtr;
CallFrame *savedVarFramePtr = NULL; /* Saves old copy of
* iPtr->varFramePtr in case
* TCL_EVAL_GLOBAL was set. */
if (TclInterpReady(interp) != TCL_OK) {
return TCL_ERROR;
}
if (flags & TCL_EVAL_GLOBAL) {
savedVarFramePtr = iPtr->varFramePtr;
iPtr->varFramePtr = iPtr->rootFramePtr;
}
Tcl_IncrRefCount(objPtr);
codePtr = TclCompileObj(interp, objPtr, invoker, word);
TclNRAddCallback(interp, TEOEx_ByteCodeCallback, savedVarFramePtr,
objPtr, INT2PTR(allowExceptions), NULL);
return TclNRExecuteByteCode(interp, codePtr);
}
{
/*
* We're not supposed to use the compiler or byte-code
* interpreter. Let Tcl_EvalEx evaluate the command directly (and
* probably more slowly).
*/
const char *script;
Tcl_Size numSrcBytes;
/*
* Now we check if we have data about invisible continuation lines for
* the script, and make it available to the direct script parser and
* evaluator we are about to call, if so.
*
* It may be possible that the script Tcl_Obj* can be free'd while the
* evaluator is using it, leading to the release of the associated
* ContLineLoc structure as well. To ensure that the latter doesn't
* happen we set a lock on it. We release this lock later in this
* function, after the evaluator is done. The relevant "lineCLPtr"
* hashtable is managed in the file "tclObj.c".
*
* Another important action is to save (and later restore) the
|
| ︙ | ︙ | |||
6340 6341 6342 6343 6344 6345 6346 |
void *data[],
Tcl_Interp *interp,
int result)
{
Interp *iPtr = (Interp *) interp;
CallFrame *savedVarFramePtr = (CallFrame *)data[0];
Tcl_Obj *objPtr = (Tcl_Obj *)data[1];
| | | 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 |
void *data[],
Tcl_Interp *interp,
int result)
{
Interp *iPtr = (Interp *) interp;
CallFrame *savedVarFramePtr = (CallFrame *)data[0];
Tcl_Obj *objPtr = (Tcl_Obj *)data[1];
int allowExceptions = (int)PTR2INT(data[2]);
if (iPtr->numLevels == 0) {
if (result == TCL_RETURN) {
result = TclUpdateReturnInfo(iPtr);
}
if ((result != TCL_OK) && (result != TCL_ERROR) && !allowExceptions) {
const char *script;
|
| ︙ | ︙ | |||
6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 |
}
return result;
}
/*
*----------------------------------------------------------------------
*
* TclObjInvoke --
*
* Invokes a Tcl command, given an objv/objc, from the hidden set of
* commands in the given interpreter. Only supported for calls via
* "internal" stub table.
*
* Results:
* A standard Tcl object result.
*
* Side effects:
* Whatever the command does.
*
*----------------------------------------------------------------------
*/
int
TclObjInvoke(
Tcl_Interp *interp, /* Interpreter in which command is to be
* invoked. */
Tcl_Size objc, /* Count of arguments. */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 |
}
return result;
}
/*
*----------------------------------------------------------------------
*
* TclObjInvokeNamespace --
*
* Object version: Invokes a Tcl command, given an objv/objc, from either
* the exposed or hidden set of commands in the given interpreter.
*
* NOTE: The command is invoked in the global stack frame of the
* interpreter or namespace, thus it cannot see any current state on the
* stack of that interpreter.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Whatever the command does.
*
*----------------------------------------------------------------------
*/
int
TclObjInvokeNamespace(
Tcl_Interp *interp, /* Interpreter in which command is to be
* invoked. */
Tcl_Size objc, /* Count of arguments. */
Tcl_Obj *const objv[], /* Argument objects; objv[0] points to the
* name of the command to invoke. */
Tcl_Namespace *nsPtr, /* The namespace to use. */
int flags) /* Combination of flags controlling the call:
* TCL_INVOKE_HIDDEN, TCL_INVOKE_NO_UNKNOWN,
* or TCL_INVOKE_NO_TRACEBACK. */
{
int result;
Tcl_CallFrame *framePtr;
/*
* Make the specified namespace the current namespace and invoke the
* command.
*/
(void) TclPushStackFrame(interp, &framePtr, nsPtr, /*isProcFrame*/0);
result = TclObjInvoke(interp, objc, objv, flags);
TclPopStackFrame(interp);
return result;
}
/*
*----------------------------------------------------------------------
*
* TclObjInvoke --
*
* Invokes a Tcl command, given an objv/objc, from the hidden set of
* commands in the given interpreter. Only supported for calls via
* "internal" stub table.
*
* Results:
* A standard Tcl object result.
*
* Side effects:
* Whatever the command does.
*
*----------------------------------------------------------------------
*/
int
TclObjInvoke(
Tcl_Interp *interp, /* Interpreter in which command is to be
* invoked. */
Tcl_Size objc, /* Count of arguments. */
Tcl_Obj *const objv[], /* Argument objects; objv[0] points to the
* name of the command to invoke. */
int flags) /* Combination of flags controlling the call:
* TCL_INVOKE_HIDDEN, TCL_INVOKE_NO_UNKNOWN,
* or TCL_INVOKE_NO_TRACEBACK. Only
* TCL_INVOKE_HIDDEN is now supported, and
* must be supplied. */
{
if (interp == NULL) {
return TCL_ERROR;
}
if ((objc < 1) || (objv == NULL)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"illegal argument vector", TCL_INDEX_NONE));
return TCL_ERROR;
}
if ((flags & TCL_INVOKE_HIDDEN) == 0) {
Tcl_Panic("TclObjInvoke: called without TCL_INVOKE_HIDDEN");
}
return Tcl_NRCallObjProc(interp, TclNRInvoke, NULL, objc, objv);
}
int
TclNRInvoke(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Interp *iPtr = (Interp *) interp;
Tcl_HashTable *hTblPtr; /* Table of hidden commands. */
const char *cmdName; /* Name of the command from objv[0]. */
Tcl_HashEntry *hPtr = NULL;
Command *cmdPtr;
|
| ︙ | ︙ | |||
6741 6742 6743 6744 6745 6746 6747 |
cmdPtr = (Command *)Tcl_GetHashValue(hPtr);
/*
* Avoid the exception-handling brain damage when numLevels == 0
*/
iPtr->numLevels++;
| | | | | 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 |
cmdPtr = (Command *)Tcl_GetHashValue(hPtr);
/*
* Avoid the exception-handling brain damage when numLevels == 0
*/
iPtr->numLevels++;
Tcl_NRAddCallback(interp, NRPostInvoke, NULL, NULL, NULL, NULL);
/*
* Normal command resolution of objv[0] isn't going to find cmdPtr.
* That's the whole point of **hidden** commands. So tell the Eval core
* machinery not to even try (and risk finding something wrong).
*/
return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NORESOLVE, cmdPtr);
}
static int
NRPostInvoke(
TCL_UNUSED(void **),
Tcl_Interp *interp,
int result)
{
Interp *iPtr = (Interp *)interp;
iPtr->numLevels--;
|
| ︙ | ︙ | |||
7039 7040 7041 7042 7043 7044 7045 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | < < < < < < < < < < < < < < < < < < < < < < | | | 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
ExprCeilFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter list. */
{
int code;
double d;
mp_int big;
if (objc != 2) {
MathFuncWrongNumArgs(interp, 2, objc, objv);
return TCL_ERROR;
}
code = Tcl_GetDoubleFromObj(interp, objv[1], &d);
#ifdef ACCEPT_NAN
if (code != TCL_OK) {
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objv[1], &tclDoubleType);
if (irPtr) {
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
|
| ︙ | ︙ | |||
7106 7107 7108 7109 7110 7111 7112 |
}
static int
ExprFloorFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 |
}
static int
ExprFloorFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter list. */
{
int code;
double d;
mp_int big;
if (objc != 2) {
|
| ︙ | ︙ | |||
7145 7146 7147 7148 7149 7150 7151 |
return TCL_OK;
}
static int
ExprIsqrtFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute. */
| | | | 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 |
return TCL_OK;
}
static int
ExprIsqrtFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter list. */
{
void *ptr;
int type;
double d;
Tcl_WideInt w;
mp_int big;
int exact = 0; /* Flag ==1 if the argument can be represented
* in a double as an exact integer. */
/*
* Check syntax.
*/
if (objc != 2) {
|
| ︙ | ︙ | |||
7184 7185 7186 7187 7188 7189 7190 |
case TCL_NUMBER_DOUBLE:
d = *((const double *) ptr);
if (d < 0) {
goto negarg;
}
#ifdef IEEE_FLOATING_POINT
if (d <= MAX_EXACT) {
| | | 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 |
case TCL_NUMBER_DOUBLE:
d = *((const double *) ptr);
if (d < 0) {
goto negarg;
}
#ifdef IEEE_FLOATING_POINT
if (d <= MAX_EXACT) {
exact = 1;
}
#endif
if (!exact) {
if (Tcl_InitBignumFromDouble(interp, d, &big) != TCL_OK) {
return TCL_ERROR;
}
}
|
| ︙ | ︙ | |||
7212 7213 7214 7215 7216 7217 7218 |
}
if (w < 0) {
goto negarg;
}
d = (double) w;
#ifdef IEEE_FLOATING_POINT
if (d < MAX_EXACT) {
| | | 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 |
}
if (w < 0) {
goto negarg;
}
d = (double) w;
#ifdef IEEE_FLOATING_POINT
if (d < MAX_EXACT) {
exact = 1;
}
#endif
if (!exact) {
Tcl_GetBignumFromObj(interp, objv[1], &big);
}
break;
}
|
| ︙ | ︙ | |||
7252 7253 7254 7255 7256 7257 7258 |
}
static int
ExprSqrtFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 |
}
static int
ExprSqrtFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter list. */
{
int code;
double d;
mp_int big;
if (objc != 2) {
|
| ︙ | ︙ | |||
7306 7307 7308 7309 7310 7311 7312 |
static int
ExprUnaryFunc(
void *clientData, /* Contains the address of a function that
* takes one double argument and returns a
* double result. */
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | > < > | > | | < | < < < < < < < < < | < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 |
static int
ExprUnaryFunc(
void *clientData, /* Contains the address of a function that
* takes one double argument and returns a
* double result. */
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
int code;
double d;
BuiltinUnaryFunc *func = (BuiltinUnaryFunc *) clientData;
if (objc != 2) {
MathFuncWrongNumArgs(interp, 2, objc, objv);
return TCL_ERROR;
}
code = Tcl_GetDoubleFromObj(interp, objv[1], &d);
#ifdef ACCEPT_NAN
if (code != TCL_OK) {
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objv[1], &tclDoubleType);
if (irPtr) {
d = irPtr->doubleValue;
Tcl_ResetResult(interp);
code = TCL_OK;
}
}
#endif
if (code != TCL_OK) {
return TCL_ERROR;
}
errno = 0;
return CheckDoubleResult(interp, func(d));
}
static int
CheckDoubleResult(
Tcl_Interp *interp,
double dResult)
{
#ifndef ACCEPT_NAN
if (isnan(dResult)) {
|
| ︙ | ︙ | |||
7410 7411 7412 7413 7414 7415 7416 |
static int
ExprBinaryFunc(
void *clientData, /* Contains the address of a function that
* takes two double arguments and returns a
* double result. */
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | > > > > > > > > > > > | > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 |
static int
ExprBinaryFunc(
void *clientData, /* Contains the address of a function that
* takes two double arguments and returns a
* double result. */
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Parameter vector. */
{
int code;
double d1, d2;
BuiltinBinaryFunc *func = (BuiltinBinaryFunc *)clientData;
if (objc != 3) {
MathFuncWrongNumArgs(interp, 3, objc, objv);
return TCL_ERROR;
}
code = Tcl_GetDoubleFromObj(interp, objv[1], &d1);
#ifdef ACCEPT_NAN
if (code != TCL_OK) {
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objv[1], &tclDoubleType);
if (irPtr) {
d1 = irPtr->doubleValue;
Tcl_ResetResult(interp);
code = TCL_OK;
}
}
#endif
if (code != TCL_OK) {
return TCL_ERROR;
}
code = Tcl_GetDoubleFromObj(interp, objv[2], &d2);
#ifdef ACCEPT_NAN
if (code != TCL_OK) {
const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objv[1], &tclDoubleType);
if (irPtr) {
d2 = irPtr->doubleValue;
Tcl_ResetResult(interp);
code = TCL_OK;
}
}
#endif
if (code != TCL_OK) {
return TCL_ERROR;
}
errno = 0;
return CheckDoubleResult(interp, func(d1, d2));
}
static int
ExprAbsFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Parameter vector. */
{
void *ptr;
int type;
mp_int big;
if (objc != 2) {
|
| ︙ | ︙ | |||
7578 7579 7580 7581 7582 7583 7584 |
}
static int
ExprBoolFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | | | 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 |
}
static int
ExprBoolFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
int value;
if (objc != 2) {
MathFuncWrongNumArgs(interp, 2, objc, objv);
return TCL_ERROR;
}
if (Tcl_GetBooleanFromObj(interp, objv[1], &value) != TCL_OK) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(value));
return TCL_OK;
}
static int
ExprDoubleFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
double dResult;
if (objc != 2) {
MathFuncWrongNumArgs(interp, 2, objc, objv);
return TCL_ERROR;
|
| ︙ | ︙ | |||
7626 7627 7628 7629 7630 7631 7632 |
}
static int
ExprIntFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 |
}
static int
ExprIntFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
double d;
int type;
void *ptr;
if (objc != 2) {
|
| ︙ | ︙ | |||
7682 7683 7684 7685 7686 7687 7688 |
}
static int
ExprWideFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | | | 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 |
}
static int
ExprWideFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
Tcl_WideInt wResult;
if (ExprIntFunc(NULL, interp, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
TclGetWideBitsFromObj(NULL, Tcl_GetObjResult(interp), &wResult);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(wResult));
return TCL_OK;
}
/*
* Common implmentation of max() and min().
*/
static int
ExprMaxMinFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv, /* Actual parameter vector. */
int op) /* Comparison direction */
{
Tcl_Obj *res;
double d;
int type;
int i;
void *ptr;
if (objc < 2) {
MathFuncWrongNumArgs(interp, 2, objc, objv);
return TCL_ERROR;
}
res = objv[1];
|
| ︙ | ︙ | |||
7744 7745 7746 7747 7748 7749 7750 |
}
static int
ExprMaxFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | | | 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 |
}
static int
ExprMaxFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
return ExprMaxMinFunc(NULL, interp, objc, objv, MP_GT);
}
static int
ExprMinFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
return ExprMaxMinFunc(NULL, interp, objc, objv, MP_LT);
}
static int
ExprRandFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
Interp *iPtr = (Interp *) interp;
double dResult;
long tmp; /* Algorithm assumes at least 32 bits. Only
* long guarantees that. See below. */
Tcl_Obj *oResult;
|
| ︙ | ︙ | |||
7859 7860 7861 7862 7863 7864 7865 |
}
static int
ExprRoundFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 |
}
static int
ExprRoundFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Parameter vector. */
{
double d;
void *ptr;
int type;
if (objc != 2) {
|
| ︙ | ︙ | |||
7938 7939 7940 7941 7942 7943 7944 |
}
static int
ExprSrandFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 |
}
static int
ExprSrandFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Parameter vector. */
{
Interp *iPtr = (Interp *) interp;
Tcl_WideInt w = 0; /* Initialized to avoid compiler warning. */
/*
* Convert argument and use it to reset the seed.
|
| ︙ | ︙ | |||
7976 7977 7978 7979 7980 7981 7982 |
* To avoid duplicating the random number generation code we simply clean
* up our state and call the real random number function. That function
* will always succeed.
*/
return ExprRandFunc(NULL, interp, 1, objv);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 |
* To avoid duplicating the random number generation code we simply clean
* up our state and call the real random number function. That function
* will always succeed.
*/
return ExprRandFunc(NULL, interp, 1, objv);
}
/*
*----------------------------------------------------------------------
*
* Double Classification Functions --
*
* This page contains the functions that implement all of the built-in
|
| ︙ | ︙ | |||
8234 8235 8236 8237 8238 8239 8240 |
}
*fpClsPtr = ClassifyDouble(d);
return TCL_OK;
}
static inline int
DoubleObjIsClass(
Tcl_Interp *interp,
| | | 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 |
}
*fpClsPtr = ClassifyDouble(d);
return TCL_OK;
}
static inline int
DoubleObjIsClass(
Tcl_Interp *interp,
int objc, /* Actual parameter count */
Tcl_Obj *const *objv, /* Actual parameter list */
int cmpCls, /* FP class to compare. */
int positive) /* 1 if compare positive, 0 - otherwise */
{
int dCls;
if (objc != 2) {
|
| ︙ | ︙ | |||
8263 8264 8265 8266 8267 8268 8269 |
}
static int
ExprIsFiniteFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | | | | | | 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 |
}
static int
ExprIsFiniteFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
return DoubleObjIsClass(interp, objc, objv, FP_INFINITE, 0);
}
static int
ExprIsInfinityFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
return DoubleObjIsClass(interp, objc, objv, FP_INFINITE, 1);
}
static int
ExprIsNaNFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
return DoubleObjIsClass(interp, objc, objv, FP_NAN, 1);
}
static int
ExprIsNormalFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
return DoubleObjIsClass(interp, objc, objv, FP_NORMAL, 1);
}
static int
ExprIsSubnormalFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
return DoubleObjIsClass(interp, objc, objv, FP_SUBNORMAL, 1);
}
static int
ExprIsUnorderedFunc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
int dCls, dCls2;
if (objc != 3) {
MathFuncWrongNumArgs(interp, 3, objc, objv);
return TCL_ERROR;
|
| ︙ | ︙ | |||
8343 8344 8345 8346 8347 8348 8349 |
}
static int
FloatClassifyObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
| | | 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 |
}
static int
FloatClassifyObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter in which to execute the
* function. */
int objc, /* Actual parameter count */
Tcl_Obj *const *objv) /* Actual parameter list */
{
double d;
Tcl_Obj *objPtr;
void *ptr;
int type;
|
| ︙ | ︙ | |||
8393 8394 8395 8396 8397 8398 8399 |
Tcl_SetObjResult(interp, objPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 |
Tcl_SetObjResult(interp, objPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* MathFuncWrongNumArgs --
*
* Generate an error message when a math function presents the wrong
* number of arguments.
*
* Results:
* None.
*
* Side effects:
* An error message is stored in the interpreter result.
*
*----------------------------------------------------------------------
*/
static void
MathFuncWrongNumArgs(
Tcl_Interp *interp, /* Tcl interpreter */
Tcl_Size expected, /* Formal parameter count. */
Tcl_Size found, /* Actual parameter count. */
Tcl_Obj *const *objv) /* Actual parameter vector. */
{
const char *name = TclGetString(objv[0]);
const char *tail = name + strlen(name);
while (tail > name + 1) {
tail--;
|
| ︙ | ︙ | |||
8680 8681 8682 8683 8684 8685 8686 |
*----------------------------------------------------------------------
*/
static int
DTraceObjCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
| | | | 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 |
*----------------------------------------------------------------------
*/
static int
DTraceObjCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (TCL_DTRACE_TCL_PROBE_ENABLED()) {
char *a[10];
int i = 0;
while (i++ < 10) {
a[i-1] = i < objc ? TclGetString(objv[i]) : NULL;
|
| ︙ | ︙ | |||
8823 8824 8825 8826 8827 8828 8829 | * Side effects: * Depends on the objProc. * *---------------------------------------------------------------------- */ int | | | | < | | | > > > | < | | | < | | | | < | | < < | < < < < < < < < | < < < < < < < < < < < < | < | < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 |
* Side effects:
* Depends on the objProc.
*
*----------------------------------------------------------------------
*/
int
Tcl_NRCallObjProc(
Tcl_Interp *interp,
Tcl_ObjCmdProc *objProc,
void *clientData,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
NRE_callback *rootPtr = TOP_CB(interp);
TclNRAddCallback(interp, Dispatch, objProc, clientData,
INT2PTR(objc), objv);
return TclNRRunCallbacks(interp, TCL_OK, rootPtr);
}
static int
WrapperNRObjProc(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CmdWrapperInfo *info = (CmdWrapperInfo *) clientData;
clientData = info->clientData;
Tcl_ObjCmdProc2 *proc = info->proc;
Tcl_Free(info);
if (objc < 0) {
objc = -1;
}
return proc(clientData, interp, objc, objv);
}
int
Tcl_NRCallObjProc2(
Tcl_Interp *interp,
Tcl_ObjCmdProc2 *objProc,
void *clientData,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
if (objc > INT_MAX) {
Tcl_WrongNumArgs(interp, 1, objv, "?args?");
return TCL_ERROR;
}
NRE_callback *rootPtr = TOP_CB(interp);
CmdWrapperInfo *info = (CmdWrapperInfo *)Tcl_Alloc(sizeof(CmdWrapperInfo));
info->clientData = clientData;
info->proc = objProc;
TclNRAddCallback(interp, Dispatch, WrapperNRObjProc, info,
INT2PTR(objc), objv);
return TclNRRunCallbacks(interp, TCL_OK, rootPtr);
}
/*
*----------------------------------------------------------------------
*
* Tcl_NRCreateCommand --
*
* Define a new NRE-enabled object-based command in a command table.
*
* Results:
* The return value is a token for the command, which can be used in
* future calls to Tcl_GetCommandName.
*
* Side effects:
* If no command named "cmdName" already exists for interp, one is
* created. Otherwise, if a command does exist, then if the object-based
* Tcl_ObjCmdProc is InvokeStringCommand, we assume Tcl_CreateCommand
* was called previously for the same command and just set its
* Tcl_ObjCmdProc to the argument "proc"; otherwise, we delete the old
* command.
*
* In the future, during bytecode evaluation when "cmdName" is seen as
* the name of a command by Tcl_EvalObj or Tcl_Eval, the object-based
* Tcl_ObjCmdProc proc will be called. When the command is deleted from
* the table, deleteProc will be called. See the manual entry for details
* on the calling sequence.
*
*----------------------------------------------------------------------
*/
static int
CmdWrapperNreProc(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CmdWrapperInfo *info = (CmdWrapperInfo *) clientData;
if (objc < 0) {
objc = -1;
}
return info->nreProc(info->clientData, interp, objc, objv);
}
Tcl_Command
Tcl_NRCreateCommand2(
Tcl_Interp *interp, /* Token for command interpreter (returned by
* previous call to Tcl_CreateInterp). */
const char *cmdName, /* Name of command. If it contains namespace
* qualifiers, the new command is put in the
* specified namespace; otherwise it is put in
* the global namespace. */
Tcl_ObjCmdProc2 *proc, /* Object-based function to associate with
* name, provides direct access for direct
* calls. */
Tcl_ObjCmdProc2 *nreProc, /* Object-based function to associate with
* name, provides NR implementation */
void *clientData, /* Arbitrary value to pass to object
* function. */
Tcl_CmdDeleteProc *deleteProc)
/* If not NULL, gives a function to call when
* this command is deleted. */
{
CmdWrapperInfo *info = (CmdWrapperInfo *)Tcl_Alloc(sizeof(CmdWrapperInfo));
info->proc = proc;
info->clientData = clientData;
info->nreProc = nreProc;
info->deleteProc = deleteProc;
info->deleteData = clientData;
return Tcl_NRCreateCommand(interp, cmdName,
(proc ? CmdWrapperProc : NULL),
(nreProc ? CmdWrapperNreProc : NULL),
info, CmdWrapperDeleteProc);
}
Tcl_Command
Tcl_NRCreateCommand(
Tcl_Interp *interp, /* Token for command interpreter (returned by
* previous call to Tcl_CreateInterp). */
const char *cmdName, /* Name of command. If it contains namespace
* qualifiers, the new command is put in the
* specified namespace; otherwise it is put in
* the global namespace. */
Tcl_ObjCmdProc *proc, /* Object-based function to associate with
* name, provides direct access for direct
* calls. */
Tcl_ObjCmdProc *nreProc, /* Object-based function to associate with
* name, provides NR implementation */
void *clientData, /* Arbitrary value to pass to object
* function. */
Tcl_CmdDeleteProc *deleteProc)
/* If not NULL, gives a function to call when
* this command is deleted. */
{
Command *cmdPtr = (Command *)
Tcl_CreateObjCommand(interp, cmdName, proc, clientData,
deleteProc);
cmdPtr->nreProc = nreProc;
return (Tcl_Command) cmdPtr;
}
Tcl_Command
TclNRCreateCommandInNs(
Tcl_Interp *interp,
const char *cmdName,
Tcl_Namespace *nsPtr,
Tcl_ObjCmdProc *proc,
Tcl_ObjCmdProc *nreProc,
void *clientData,
Tcl_CmdDeleteProc *deleteProc)
{
Command *cmdPtr = (Command *)
TclCreateObjCommandInNs(interp, cmdName, nsPtr, proc, clientData,
deleteProc);
cmdPtr->nreProc = nreProc;
return (Tcl_Command) cmdPtr;
}
/****************************************************************************
* Stuff for the public api
****************************************************************************/
|
| ︙ | ︙ | |||
9015 9016 9017 9018 9019 9020 9021 |
}
int
Tcl_NREvalObjv(
Tcl_Interp *interp, /* Interpreter in which to evaluate the
* command. Also used for error reporting. */
Tcl_Size objc, /* Number of words in command. */
| | | | 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 |
}
int
Tcl_NREvalObjv(
Tcl_Interp *interp, /* Interpreter in which to evaluate the
* command. Also used for error reporting. */
Tcl_Size objc, /* Number of words in command. */
Tcl_Obj *const objv[], /* An array of pointers to objects that are
* the words that make up the command. */
int flags) /* Collection of OR-ed bits that control the
* evaluation of the script. Only
* TCL_EVAL_GLOBAL, TCL_EVAL_INVOKE and
* TCL_EVAL_NOERR are currently supported. */
{
return TclNREvalObjv(interp, objc, objv, flags, NULL);
}
int
Tcl_NRCmdSwap(
Tcl_Interp *interp,
Tcl_Command cmd,
Tcl_Size objc,
Tcl_Obj *const objv[],
int flags)
{
return TclNREvalObjv(interp, objc, objv, flags|TCL_EVAL_NOERR,
(Command *) cmd);
}
/*****************************************************************************
|
| ︙ | ︙ | |||
9072 9073 9074 9075 9076 9077 9078 |
void
TclMarkTailcall(
Tcl_Interp *interp)
{
Interp *iPtr = (Interp *) interp;
if (iPtr->deferredCallbacks == NULL) {
| | > | 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 |
void
TclMarkTailcall(
Tcl_Interp *interp)
{
Interp *iPtr = (Interp *) interp;
if (iPtr->deferredCallbacks == NULL) {
TclNRAddCallback(interp, NRCommand, NULL, NULL,
NULL, NULL);
iPtr->deferredCallbacks = TOP_CB(interp);
}
}
void
TclSkipTailcall(
Tcl_Interp *interp)
|
| ︙ | ︙ | |||
9150 9151 9152 9153 9154 9155 9156 |
*----------------------------------------------------------------------
*/
int
TclNRTailcallObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 |
*----------------------------------------------------------------------
*/
int
TclNRTailcallObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Interp *iPtr = (Interp *) interp;
if (objc < 1) {
Tcl_WrongNumArgs(interp, 1, objv, "?command? ?arg ...?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
9194 9195 9196 9197 9198 9199 9200 | /* * 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); TclListObjSetElement(NULL, listPtr, 0, TclNewNamespaceObj(nsPtr)); | < | 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 |
/*
* 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);
TclListObjSetElement(NULL, listPtr, 0, TclNewNamespaceObj(nsPtr));
iPtr->varFramePtr->tailcallPtr = listPtr;
}
return TCL_RETURN;
}
/*
|
| ︙ | ︙ | |||
9245 9246 9247 9248 9249 9250 9251 |
}
/*
* Perform the tailcall
*/
TclMarkTailcall(interp);
| | | 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 |
}
/*
* Perform the tailcall
*/
TclMarkTailcall(interp);
TclNRAddCallback(interp, TclNRReleaseValues, listPtr, NULL, NULL,NULL);
iPtr->lookupNsPtr = (Namespace *) nsPtr;
return TclNREvalObjv(interp, objc - 1, objv + 1, 0, NULL);
}
int
TclNRReleaseValues(
void *data[],
|
| ︙ | ︙ | |||
9312 9313 9314 9315 9316 9317 9318 |
#define iPtr ((Interp *) interp)
int
TclNRYieldObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | | | | | | 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 |
#define iPtr ((Interp *) interp)
int
TclNRYieldObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?returnValue?");
return TCL_ERROR;
}
if (!corPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"yield can only be called in a coroutine", TCL_INDEX_NONE));
Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD", (char *)NULL);
return TCL_ERROR;
}
if (objc == 2) {
Tcl_SetObjResult(interp, objv[1]);
}
NRE_ASSERT(!COR_IS_SUSPENDED(corPtr));
TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
clientData, NULL, NULL);
return TCL_OK;
}
int
TclNRYieldToObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
Tcl_Namespace *nsPtr = TclGetCurrentNamespace(interp);
Tcl_Obj *listPtr;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?");
|
| ︙ | ︙ | |||
9414 9415 9416 9417 9418 9419 9420 |
Tcl_InterpState state = Tcl_SaveInterpState(interp, result);
NRE_ASSERT(COR_IS_SUSPENDED(corPtr));
NRE_ASSERT(corPtr->eePtr != NULL);
NRE_ASSERT(corPtr->eePtr != iPtr->execEnvPtr);
corPtr->eePtr->rewind = 1;
| | > | 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 |
Tcl_InterpState state = Tcl_SaveInterpState(interp, result);
NRE_ASSERT(COR_IS_SUSPENDED(corPtr));
NRE_ASSERT(corPtr->eePtr != NULL);
NRE_ASSERT(corPtr->eePtr != iPtr->execEnvPtr);
corPtr->eePtr->rewind = 1;
TclNRAddCallback(interp, RewindCoroutineCallback, state,
NULL, NULL, NULL);
return TclNRInterpCoroutine(corPtr, interp, 0, NULL);
}
static void
DeleteCoroutine(
void *clientData)
{
|
| ︙ | ︙ | |||
9639 9640 9641 9642 9643 9644 9645 |
*----------------------------------------------------------------------
*/
static int
CoroTypeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 |
*----------------------------------------------------------------------
*/
static int
CoroTypeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Command *cmdPtr;
CoroutineData *corPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "coroName");
return TCL_ERROR;
}
/*
* Look up the coroutine.
*/
cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objv[1]);
if ((!cmdPtr) || (cmdPtr->nreProc != TclNRInterpCoroutine)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"can only get coroutine type of a coroutine", TCL_INDEX_NONE));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COROUTINE",
TclGetString(objv[1]), (char *)NULL);
return TCL_ERROR;
}
/*
* An active coroutine is "active". Can't tell what it might do in the
* future.
*/
corPtr = (CoroutineData *)cmdPtr->objClientData;
if (!COR_IS_SUSPENDED(corPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("active", TCL_INDEX_NONE));
return TCL_OK;
}
/*
* Inactive coroutines are classified by the (effective) command used to
|
| ︙ | ︙ | |||
9716 9717 9718 9719 9720 9721 9722 |
{
/*
* How to get a coroutine from its handle.
*/
Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objPtr);
| | | | | | 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 |
{
/*
* How to get a coroutine from its handle.
*/
Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objPtr);
if ((!cmdPtr) || (cmdPtr->nreProc != TclNRInterpCoroutine)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(errMsg, TCL_INDEX_NONE));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COROUTINE",
TclGetString(objPtr), (char *)NULL);
return NULL;
}
return (CoroutineData *)cmdPtr->objClientData;
}
static int
TclNRCoroInjectObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CoroutineData *corPtr;
/*
* Usage more or less like tailcall:
* coroinject coroName cmd ?arg1 arg2 ...?
*/
|
| ︙ | ︙ | |||
9774 9775 9776 9777 9778 9779 9780 |
return TCL_OK;
}
static int
TclNRCoroProbeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 |
return TCL_OK;
}
static int
TclNRCoroProbeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CoroutineData *corPtr;
/*
* Usage more or less like tailcall:
* coroprobe coroName cmd ?arg1 arg2 ...?
*/
|
| ︙ | ︙ | |||
9955 9956 9957 9958 9959 9960 9961 |
return result;
}
int
TclNRInterpCoroutine(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 |
return result;
}
int
TclNRInterpCoroutine(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
CoroutineData *corPtr = (CoroutineData *)clientData;
if (!COR_IS_SUSPENDED(corPtr)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"coroutine \"%s\" is already running",
TclGetString(objv[0])));
|
| ︙ | ︙ | |||
10019 10020 10021 10022 10023 10024 10025 |
*----------------------------------------------------------------------
*/
int
TclNRCoroutineObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 |
*----------------------------------------------------------------------
*/
int
TclNRCoroutineObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Command *cmdPtr;
CoroutineData *corPtr;
const char *procName, *simpleName;
Namespace *nsPtr, *altNsPtr, *cxtNsPtr,
*inNsPtr = (Namespace *)TclGetCurrentNamespace(interp);
Namespace *lookupNsPtr = iPtr->varFramePtr->nsPtr;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name cmd ?arg ...?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 |
Tcl_HashEntry *hePtr;
corPtr->lineLABCPtr = (Tcl_HashTable *)Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(corPtr->lineLABCPtr, TCL_ONE_WORD_KEYS);
for (hePtr = Tcl_FirstHashEntry(iPtr->lineLABCPtr,&hSearch);
hePtr; hePtr = Tcl_NextHashEntry(&hSearch)) {
Tcl_HashEntry *newPtr =
Tcl_CreateHashEntry(corPtr->lineLABCPtr,
Tcl_GetHashKey(iPtr->lineLABCPtr, hePtr),
| > | | 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 |
Tcl_HashEntry *hePtr;
corPtr->lineLABCPtr = (Tcl_HashTable *)Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(corPtr->lineLABCPtr, TCL_ONE_WORD_KEYS);
for (hePtr = Tcl_FirstHashEntry(iPtr->lineLABCPtr,&hSearch);
hePtr; hePtr = Tcl_NextHashEntry(&hSearch)) {
int isNew;
Tcl_HashEntry *newPtr =
Tcl_CreateHashEntry(corPtr->lineLABCPtr,
Tcl_GetHashKey(iPtr->lineLABCPtr, hePtr),
&isNew);
Tcl_SetHashValue(newPtr, Tcl_GetHashValue(hePtr));
}
}
/*
* Create the base context.
|
| ︙ | ︙ | |||
10145 10146 10147 10148 10149 10150 10151 |
TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
NULL, NULL, NULL);
return TCL_OK;
}
/*
| < < | | < | < < | | | 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 |
TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
NULL, NULL, NULL);
return TCL_OK;
}
/*
* This is used in the [info] ensemble
*/
int
TclInfoCoroutineCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ |
Changes to generic/tclBinary.c.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | #include <math.h> /* * The following constants are used by GetFormatSpec to indicate various * special conditions in the parsing of a format specifier. */ | | | | < | | | < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include <math.h> /* * The following constants are used by GetFormatSpec to indicate various * special conditions in the parsing of a format specifier. */ #define BINARY_ALL -1 /* Use all elements in the argument. */ #define BINARY_NOCOUNT -2 /* No count was specified in format. */ /* * The following flags may be OR'ed together and returned by GetFormatSpec */ #define BINARY_SIGNED 0 /* Field to be read as signed data */ #define BINARY_UNSIGNED 1 /* Field to be read as unsigned data */ /* * The following defines the maximum number of different (integer) numbers * placed in the object cache by 'binary scan' before it bails out and * switches back to Plan A (creating a new object for each value.) * Theoretically, it would be possible to keep the cache about for the values * that are already in it, but that makes the code slower in practice when |
| ︙ | ︙ | |||
69 70 71 72 73 74 75 | Tcl_Obj *objPtr); static void UpdateStringOfByteArray(Tcl_Obj *listPtr); static void DeleteScanNumberCache(Tcl_HashTable *numberCachePtr); static int NeedReversing(int format); static void CopyNumber(const void *from, void *to, size_t length, int type); /* Binary ensemble commands */ | | | | | | | | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
Tcl_Obj *objPtr);
static void UpdateStringOfByteArray(Tcl_Obj *listPtr);
static void DeleteScanNumberCache(Tcl_HashTable *numberCachePtr);
static int NeedReversing(int format);
static void CopyNumber(const void *from, void *to,
size_t length, int type);
/* Binary ensemble commands */
static Tcl_ObjCmdProc BinaryFormatCmd;
static Tcl_ObjCmdProc BinaryScanCmd;
/* Binary encoding sub-ensemble commands */
static Tcl_ObjCmdProc BinaryEncodeHex;
static Tcl_ObjCmdProc BinaryDecodeHex;
static Tcl_ObjCmdProc BinaryEncode64;
static Tcl_ObjCmdProc BinaryDecode64;
static Tcl_ObjCmdProc BinaryEncodeUu;
static Tcl_ObjCmdProc BinaryDecodeUu;
/*
* The following tables are used by the binary encoders
*/
static const char HexDigits[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
|
| ︙ | ︙ | |||
116 117 118 119 120 121 122 |
'='
};
/*
* How to construct the ensembles.
*/
| | | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
'='
};
/*
* How to construct the ensembles.
*/
static const EnsembleImplMap binaryMap[] = {
{ "format", BinaryFormatCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0 },
{ "scan", BinaryScanCmd, TclCompileBasicMin2ArgCmd, NULL, NULL, 0 },
{ "encode", NULL, NULL, NULL, NULL, 0 },
{ "decode", NULL, NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
static const EnsembleImplMap encodeMap[] = {
{ "hex", BinaryEncodeHex, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
{ "uuencode", BinaryEncodeUu, NULL, NULL, NULL, 0 },
{ "base64", BinaryEncode64, NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
static const EnsembleImplMap decodeMap[] = {
{ "hex", BinaryDecodeHex, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
{ "uuencode", BinaryDecodeUu, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
{ "base64", BinaryDecode64, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
/*
|
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
*/
static const Tcl_ObjType properByteArrayType = {
"bytearray",
FreeProperByteArrayInternalRep,
DupProperByteArrayInternalRep,
UpdateStringOfByteArray,
| | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
*/
static const Tcl_ObjType properByteArrayType = {
"bytearray",
FreeProperByteArrayInternalRep,
DupProperByteArrayInternalRep,
UpdateStringOfByteArray,
NULL,
TCL_OBJTYPE_V0
};
/*
* The following structure is the internal rep for a ByteArray object. Keeps
* track of how much memory has been used and how much has been allocated for
* the byte array to enable growing and shrinking of the ByteArray object with
|
| ︙ | ︙ | |||
381 382 383 384 385 386 387 |
if (numBytesPtr != NULL) {
*numBytesPtr = baPtr->used;
}
return baPtr->bytes;
}
| | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
if (numBytesPtr != NULL) {
*numBytesPtr = baPtr->used;
}
return baPtr->bytes;
}
#if !defined(TCL_NO_DEPRECATED)
unsigned char *
TclGetBytesFromObj(
Tcl_Interp *interp, /* For error reporting */
Tcl_Obj *objPtr, /* Value to extract from */
void *numBytesPtr) /* If non-NULL, write the number of bytes
* in the array here */
{
|
| ︙ | ︙ | |||
490 491 492 493 494 495 496 | * limit bytes) are a proper representation of (a limited prefix of) * the string. Writes a pointer to the generated ByteArray to * *byteArrayPtrPtr. If not NULL it needs to be released with Tcl_Free(). * *---------------------------------------------------------------------- */ | | | | | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
* limit bytes) are a proper representation of (a limited prefix of)
* the string. Writes a pointer to the generated ByteArray to
* *byteArrayPtrPtr. If not NULL it needs to be released with Tcl_Free().
*
*----------------------------------------------------------------------
*/
static int
MakeByteArray(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
Tcl_Size limit,
int demandProper,
ByteArray **byteArrayPtrPtr)
{
Tcl_Size length;
const char *src = TclGetStringFromObj(objPtr, &length);
Tcl_Size numBytes = (limit >= 0 && limit < length) ? limit : length;
ByteArray *byteArrayPtr = (ByteArray *)Tcl_Alloc(BYTEARRAY_SIZE(numBytes));
unsigned char *dst = byteArrayPtr->bytes;
unsigned char *dstEnd = dst + numBytes;
const char *srcEnd = src + length;
int proper = 1;
for (; src < srcEnd && dst < dstEnd; ) {
int ch;
int count = TclUtfToUniChar(src, &ch);
if (ch > 255) {
proper = 0;
if (demandProper) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected code point values below 0xff but value at byte offset %"
TCL_Z_MODIFIER "u was 0x%x",
dst - byteArrayPtr->bytes, ch));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "BYTES", (char *)NULL);
|
| ︙ | ︙ | |||
544 545 546 547 548 549 550 |
TclNarrowToBytes(
Tcl_Obj *objPtr)
{
if (NULL == TclFetchInternalRep(objPtr, &properByteArrayType)) {
Tcl_ObjInternalRep ir;
ByteArray *byteArrayPtr;
| | | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
TclNarrowToBytes(
Tcl_Obj *objPtr)
{
if (NULL == TclFetchInternalRep(objPtr, &properByteArrayType)) {
Tcl_ObjInternalRep ir;
ByteArray *byteArrayPtr;
if (0 == MakeByteArray(NULL, objPtr, TCL_INDEX_NONE, 0, &byteArrayPtr)) {
TclNewObj(objPtr);
TclInvalidateStringRep(objPtr);
}
SET_BYTEARRAY(&ir, byteArrayPtr);
Tcl_StoreInternalRep(objPtr, &properByteArrayType, &ir);
}
Tcl_IncrRefCount(objPtr);
|
| ︙ | ︙ | |||
580 581 582 583 584 585 586 |
Tcl_Interp *interp, /* For error reporting. */
Tcl_Size limit, /* Create no more than this many bytes */
Tcl_Obj *objPtr) /* The object to convert to type ByteArray. */
{
ByteArray *byteArrayPtr;
Tcl_ObjInternalRep ir;
| | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
Tcl_Interp *interp, /* For error reporting. */
Tcl_Size limit, /* Create no more than this many bytes */
Tcl_Obj *objPtr) /* The object to convert to type ByteArray. */
{
ByteArray *byteArrayPtr;
Tcl_ObjInternalRep ir;
if (0 == MakeByteArray(interp, objPtr, limit, 1, &byteArrayPtr)) {
return TCL_ERROR;
}
SET_BYTEARRAY(&ir, byteArrayPtr);
Tcl_StoreInternalRep(objPtr, &properByteArrayType, &ir);
return TCL_OK;
}
|
| ︙ | ︙ | |||
767 768 769 770 771 772 773 |
if ((BYTEARRAY_MAX_LEN - byteArrayPtr->used) < len) {
/* Will wrap around !! */
Tcl_Panic("max size of a byte array exceeded");
}
needed = byteArrayPtr->used + len;
if (needed > byteArrayPtr->allocated) {
Tcl_Size newCapacity;
| | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 |
if ((BYTEARRAY_MAX_LEN - byteArrayPtr->used) < len) {
/* Will wrap around !! */
Tcl_Panic("max size of a byte array exceeded");
}
needed = byteArrayPtr->used + len;
if (needed > byteArrayPtr->allocated) {
Tcl_Size newCapacity;
byteArrayPtr =
(ByteArray *)TclReallocElemsEx(byteArrayPtr,
needed,
1,
offsetof(ByteArray, bytes),
&newCapacity);
byteArrayPtr->allocated = newCapacity;
SET_BYTEARRAY(irPtr, byteArrayPtr);
}
if (bytes) {
memcpy(byteArrayPtr->bytes + byteArrayPtr->used, bytes, len);
}
byteArrayPtr->used += len;
TclInvalidateStringRep(objPtr);
}
/*
*----------------------------------------------------------------------
*
* TclInitBinaryCmd --
*
* This function is called to create the "binary" Tcl command. See the
* user documentation for details on what it does.
*
* Results:
* A command token for the new command.
*
* Side effects:
* Creates a new binary command as a mapped ensemble.
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitBinaryCmd(
Tcl_Interp *interp)
{
Tcl_Command binaryEnsemble;
binaryEnsemble = TclMakeEnsemble(interp, "binary", binaryMap);
TclMakeEnsemble(interp, "binary encode", encodeMap);
TclMakeEnsemble(interp, "binary decode", decodeMap);
return binaryEnsemble;
}
/*
*----------------------------------------------------------------------
*
* BinaryFormatCmd --
*
* This procedure implements the "binary format" Tcl command.
|
| ︙ | ︙ | |||
801 802 803 804 805 806 807 |
*----------------------------------------------------------------------
*/
static int
BinaryFormatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 |
*----------------------------------------------------------------------
*/
static int
BinaryFormatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int arg; /* Index of next argument to consume. */
int value = 0; /* Current integer value to be packed.
* Initialized to avoid compiler warning. */
char cmd; /* Current format character. */
Tcl_Size count; /* Count associated with current format
* character. */
int flags; /* Format field flags */
const char *format; /* Pointer to current position in format
|
| ︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 |
}
break;
}
}
Tcl_SetObjResult(interp, resultPtr);
return TCL_OK;
| | | | | | | 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 |
}
break;
}
}
Tcl_SetObjResult(interp, resultPtr);
return TCL_OK;
badValue:
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected %s string but got \"%s\" instead",
errorString, errorValue));
return TCL_ERROR;
badCount:
errorString = "missing count for \"@\" field specifier";
goto error;
badIndex:
errorString = "not enough arguments for all format specifiers";
goto error;
badField:
{
Tcl_UniChar ch = 0;
char buf[5] = "";
TclUtfToUniChar(errorString, &ch);
buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad field specifier \"%s\"", buf));
return TCL_ERROR;
}
error:
Tcl_SetObjResult(interp, Tcl_NewStringObj(errorString, -1));
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1313 1314 1315 1316 1317 1318 1319 |
*----------------------------------------------------------------------
*/
static int
BinaryScanCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 |
*----------------------------------------------------------------------
*/
static int
BinaryScanCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int arg; /* Index of next argument to consume. */
int value = 0; /* Current integer value to be packed.
* Initialized to avoid compiler warning. */
char cmd; /* Current format character. */
Tcl_Size count; /* Count associated with current format
* character. */
int flags; /* Format field flags */
const char *format; /* Pointer to current position in format
|
| ︙ | ︙ | |||
1643 1644 1645 1646 1647 1648 1649 |
}
}
/*
* Set the result to the last position of the cursor.
*/
| | | | | | | 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 |
}
}
/*
* Set the result to the last position of the cursor.
*/
done:
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(arg - 3));
DeleteScanNumberCache(numberCachePtr);
return TCL_OK;
badCount:
errorString = "missing count for \"@\" field specifier";
goto error;
badIndex:
errorString = "not enough arguments for all format specifiers";
goto error;
badField:
{
Tcl_UniChar ch = 0;
char buf[5] = "";
TclUtfToUniChar(errorString, &ch);
buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad field specifier \"%s\"", buf));
return TCL_ERROR;
}
error:
Tcl_SetObjResult(interp, Tcl_NewStringObj(errorString, -1));
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2005 2006 2007 2008 2009 2010 2011 |
* valid range for float.
*/
if (fabs(dvalue) > (double) FLT_MAX) {
if (fabs(dvalue) > (FLT_MAX + pow(2, (FLT_MAX_EXP - FLT_MANT_DIG - 1)))) {
fvalue = (dvalue >= 0.0) ? INFINITY : -INFINITY; // c99
} else {
| | | 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 |
* valid range for float.
*/
if (fabs(dvalue) > (double) FLT_MAX) {
if (fabs(dvalue) > (FLT_MAX + pow(2, (FLT_MAX_EXP - FLT_MANT_DIG - 1)))) {
fvalue = (dvalue >= 0.0) ? INFINITY : -INFINITY; // c99
} else {
fvalue = (dvalue >= 0.0) ? FLT_MAX : -FLT_MAX;
}
} else {
fvalue = (float) dvalue;
}
CopyNumber(&fvalue, *cursorPtr, sizeof(float), type);
*cursorPtr += sizeof(float);
return TCL_OK;
|
| ︙ | ︙ | |||
2397 2398 2399 2400 2401 2402 2403 |
*----------------------------------------------------------------------
*/
static int
BinaryEncodeHex(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 |
*----------------------------------------------------------------------
*/
static int
BinaryEncodeHex(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *resultObj = NULL;
unsigned char *data = NULL;
unsigned char *cursor = NULL;
Tcl_Size offset = 0, count = 0;
if (objc != 2) {
|
| ︙ | ︙ | |||
2445 2446 2447 2448 2449 2450 2451 |
*----------------------------------------------------------------------
*/
static int
BinaryDecodeHex(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 |
*----------------------------------------------------------------------
*/
static int
BinaryDecodeHex(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *resultObj = NULL;
unsigned char *data, *datastart, *dataend;
unsigned char *begin, *cursor, c;
int i, index, value, pure = 1, strict = 0;
Tcl_Size size, cut = 0, count = 0;
int ucs4;
enum {OPT_STRICT };
static const char *const optStrings[] = { "-strict", NULL };
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?options? data");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2572 2573 2574 2575 2576 2577 2578 |
} \
} while (0)
static int
BinaryEncode64(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 |
} \
} while (0)
static int
BinaryEncode64(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *resultObj;
unsigned char *data, *limit;
Tcl_WideInt maxlen = 0;
const char *wrapchar = "\n";
Tcl_Size wrapcharlen = 1;
int index, purewrap = 1;
Tcl_Size i, offset, size, outindex = 0, count = 0;
enum { OPT_MAXLEN, OPT_WRAPCHAR };
static const char *const optStrings[] = { "-maxlen", "-wrapchar", NULL };
if (objc < 2 || objc % 2 != 0) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-maxlen len? ?-wrapchar char? data");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2634 2635 2636 2637 2638 2639 2640 |
}
TclNewObj(resultObj);
if (count > 0) {
unsigned char *cursor = NULL;
size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */
if (maxlen > 0 && size > maxlen) {
| | | 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 |
}
TclNewObj(resultObj);
if (count > 0) {
unsigned char *cursor = NULL;
size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */
if (maxlen > 0 && size > maxlen) {
int adjusted = size + (wrapcharlen * (size / maxlen));
if (size % maxlen == 0) {
adjusted -= wrapcharlen;
}
size = adjusted;
if (purewrap == 0) {
|
| ︙ | ︙ | |||
2700 2701 2702 2703 2704 2705 2706 |
*----------------------------------------------------------------------
*/
static int
BinaryEncodeUu(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > > | < | | 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 |
*----------------------------------------------------------------------
*/
static int
BinaryEncodeUu(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *resultObj;
unsigned char *data, *start, *cursor;
int i, bits;
unsigned int n;
int lineLength = 61;
const unsigned char SingleNewline[] = { UCHAR('\n') };
const unsigned char *wrapchar = SingleNewline;
Tcl_Size j, rawLength, offset, count = 0, wrapcharlen = sizeof(SingleNewline);
enum { OPT_MAXLEN, OPT_WRAPCHAR } index;
static const char *const optStrings[] = { "-maxlen", "-wrapchar", NULL };
if (objc < 2 || objc % 2 != 0) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-maxlen len? ?-wrapchar char? data");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2851 2852 2853 2854 2855 2856 2857 |
*----------------------------------------------------------------------
*/
static int
BinaryDecodeUu(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 |
*----------------------------------------------------------------------
*/
static int
BinaryDecodeUu(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *resultObj = NULL;
unsigned char *data, *datastart, *dataend;
unsigned char *begin, *cursor;
int i, index, pure = 1, strict = 0, lineLen;
Tcl_Size size, count = 0;
unsigned char c;
int ucs4;
enum { OPT_STRICT };
static const char *const optStrings[] = { "-strict", NULL };
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?options? data");
|
| ︙ | ︙ | |||
2942 2943 2944 2945 2946 2947 2948 |
}
/*
* Translate that grouping into (up to) three binary bytes output.
*/
if (lineLen > 0) {
| | | | | | 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 |
}
/*
* Translate that grouping into (up to) three binary bytes output.
*/
if (lineLen > 0) {
*cursor++ = (((d[0] - 0x20) & 0x3F) << 2)
| (((d[1] - 0x20) & 0x3F) >> 4);
if (--lineLen > 0) {
*cursor++ = (((d[1] - 0x20) & 0x3F) << 4)
| (((d[2] - 0x20) & 0x3F) >> 2);
if (--lineLen > 0) {
*cursor++ = (((d[2] - 0x20) & 0x3F) << 6)
| (((d[3] - 0x20) & 0x3F));
lineLen--;
}
}
}
/*
* If we've reached the end of the line, skip until we process a
|
| ︙ | ︙ | |||
3027 3028 3029 3030 3031 3032 3033 |
*----------------------------------------------------------------------
*/
static int
BinaryDecode64(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 |
*----------------------------------------------------------------------
*/
static int
BinaryDecode64(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *resultObj = NULL;
unsigned char *data, *datastart, *dataend, c = '\0';
unsigned char *begin = NULL;
unsigned char *cursor = NULL;
int pure = 1, strict = 0;
int i, index, cut = 0;
Tcl_Size size, count = 0;
int ucs4;
enum { OPT_STRICT };
static const char *const optStrings[] = { "-strict", NULL };
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?options? data");
return TCL_ERROR;
|
| ︙ | ︙ |
Changes to generic/tclCkalloc.c.
| ︙ | ︙ | |||
90 91 92 93 94 95 96 | ((size_t) (&((struct mem_header *) 0)->body)) static size_t total_mallocs = 0; static size_t total_frees = 0; static size_t current_bytes_malloced = 0; static size_t maximum_bytes_malloced = 0; static size_t current_malloc_packets = 0; | | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | ((size_t) (&((struct mem_header *) 0)->body)) static size_t total_mallocs = 0; static size_t total_frees = 0; static size_t current_bytes_malloced = 0; static size_t maximum_bytes_malloced = 0; static size_t current_malloc_packets = 0; static size_t maximum_malloc_packets = 0; static size_t break_on_malloc = 0; static size_t trace_on_at_malloc = 0; static int alloc_tracing = FALSE; static int init_malloced_bodies = TRUE; #ifdef MEM_VALIDATE static int validate_memory = TRUE; #else |
| ︙ | ︙ | |||
122 123 124 125 126 127 128 | * Mutex to serialize allocations. This is a low-level mutex that must be * explicitly initialized. This is necessary because the self initializing * mutexes use Tcl_Alloc... */ static Tcl_Mutex *ckallocMutexPtr; static int ckallocInit = 0; | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | * Mutex to serialize allocations. This is a low-level mutex that must be * explicitly initialized. This is necessary because the self initializing * mutexes use Tcl_Alloc... */ static Tcl_Mutex *ckallocMutexPtr; static int ckallocInit = 0; /* *---------------------------------------------------------------------- * * TclInitDbCkalloc -- * * Initialize the locks used by the allocator. This is only appropriate * to call in a single threaded environment, such as during |
| ︙ | ︙ | |||
271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
Tcl_Panic("Memory validation failure");
}
if (nukeGuards) {
memset(memHeaderP->low_guard, 0, LOW_GUARD_SIZE);
memset(hiPtr, 0, HIGH_GUARD_SIZE);
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_ValidateAllMemory --
*
| > | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
Tcl_Panic("Memory validation failure");
}
if (nukeGuards) {
memset(memHeaderP->low_guard, 0, LOW_GUARD_SIZE);
memset(hiPtr, 0, HIGH_GUARD_SIZE);
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_ValidateAllMemory --
*
|
| ︙ | ︙ | |||
793 794 795 796 797 798 799 |
*
*----------------------------------------------------------------------
*/
static int
MemoryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | < | < < < < < < < < < < < < < < < < < > < > > > < > > < > > | | > > < > > < > > < > > > | > | > > < > > | < | > > > > > > | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 |
*
*----------------------------------------------------------------------
*/
static int
MemoryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Obj values of arguments. */
{
const char *fileName;
FILE *fileP;
Tcl_DString buffer;
int result;
size_t len;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option [args..]");
return TCL_ERROR;
}
if (strcmp(TclGetString(objv[1]), "active") == 0 || strcmp(TclGetString(objv[1]), "display") == 0) {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "file");
return TCL_ERROR;
}
fileName = Tcl_TranslateFileName(interp, TclGetString(objv[2]), &buffer);
if (fileName == NULL) {
return TCL_ERROR;
}
result = Tcl_DumpActiveMemory(fileName);
Tcl_DStringFree(&buffer);
if (result != TCL_OK) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf("error accessing %s: %s",
TclGetString(objv[2]), Tcl_PosixError(interp)));
return TCL_ERROR;
}
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]),"break_on_malloc") == 0) {
Tcl_WideInt value;
if (objc != 3) {
goto argError;
}
if (TclGetWideIntFromObj(interp, objv[2], &value) != TCL_OK) {
return TCL_ERROR;
}
break_on_malloc = value;
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]),"info") == 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%-25s %10" TCL_Z_MODIFIER "u\n%-25s %10" TCL_Z_MODIFIER "u\n%-25s %10" TCL_Z_MODIFIER "u\n%-25s %10" TCL_Z_MODIFIER "u\n%-25s %10" TCL_Z_MODIFIER "u\n%-25s %10" TCL_Z_MODIFIER "u\n",
"total mallocs", total_mallocs, "total frees", total_frees,
"current packets allocated", current_malloc_packets,
"current bytes allocated", current_bytes_malloced,
"maximum packets allocated", maximum_malloc_packets,
"maximum bytes allocated", maximum_bytes_malloced));
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]), "init") == 0) {
if (objc != 3) {
goto bad_suboption;
}
init_malloced_bodies = (strcmp(TclGetString(objv[2]),"on") == 0);
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]), "objs") == 0) {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "file");
return TCL_ERROR;
}
fileName = Tcl_TranslateFileName(interp, TclGetString(objv[2]), &buffer);
if (fileName == NULL) {
return TCL_ERROR;
}
fileP = fopen(fileName, "w");
if (fileP == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"cannot open output file: %s",
Tcl_PosixError(interp)));
return TCL_ERROR;
}
TclDbDumpActiveObjects(fileP);
fclose(fileP);
Tcl_DStringFree(&buffer);
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]),"onexit") == 0) {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "file");
return TCL_ERROR;
}
fileName = Tcl_TranslateFileName(interp, TclGetString(objv[2]), &buffer);
if (fileName == NULL) {
return TCL_ERROR;
}
onExitMemDumpFileName = dumpFile;
strcpy(onExitMemDumpFileName,fileName);
Tcl_DStringFree(&buffer);
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]),"tag") == 0) {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "file");
return TCL_ERROR;
}
if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) {
TclpFree(curTagPtr);
}
len = strlen(TclGetString(objv[2]));
curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(len));
curTagPtr->refCount = 0;
memcpy(curTagPtr->string, TclGetString(objv[2]), len + 1);
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]),"trace") == 0) {
if (objc != 3) {
goto bad_suboption;
}
alloc_tracing = (strcmp(TclGetString(objv[2]),"on") == 0);
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]),"trace_on_at_malloc") == 0) {
Tcl_WideInt value;
if (objc != 3) {
goto argError;
}
if (TclGetWideIntFromObj(interp, objv[2], &value) != TCL_OK) {
return TCL_ERROR;
}
trace_on_at_malloc = value;
return TCL_OK;
}
if (strcmp(TclGetString(objv[1]),"validate") == 0) {
if (objc != 3) {
goto bad_suboption;
}
validate_memory = (strcmp(TclGetString(objv[2]),"on") == 0);
return TCL_OK;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad option \"%s\": should be active, break_on_malloc, info, "
"init, objs, onexit, tag, trace, trace_on_at_malloc, or validate",
TclGetString(objv[1])));
return TCL_ERROR;
argError:
Tcl_WrongNumArgs(interp, 2, objv, "count");
return TCL_ERROR;
bad_suboption:
Tcl_WrongNumArgs(interp, 2, objv, "on|off");
|
| ︙ | ︙ | |||
963 964 965 966 967 968 969 |
*
*----------------------------------------------------------------------
*/
static int
CheckmemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for evaluation. */
| | | | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
*
*----------------------------------------------------------------------
*/
static int
CheckmemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for evaluation. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Obj values of arguments. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "fileName");
return TCL_ERROR;
}
tclMemDumpFileName = dumpFile;
strcpy(tclMemDumpFileName, TclGetString(objv[1]));
|
| ︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 |
void
Tcl_InitMemory(
Tcl_Interp *interp) /* Interpreter in which commands should be
* added */
{
TclInitDbCkalloc();
| | | | 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 |
void
Tcl_InitMemory(
Tcl_Interp *interp) /* Interpreter in which commands should be
* added */
{
TclInitDbCkalloc();
Tcl_CreateObjCommand(interp, "memory", MemoryCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "checkmem", CheckmemCmd, NULL, NULL);
}
#else /* TCL_MEM_DEBUG */
/* This is the !TCL_MEM_DEBUG case */
#undef Tcl_InitMemory
|
| ︙ | ︙ | |||
1228 1229 1230 1231 1232 1233 1234 | #endif /* TCL_MEM_DEBUG */ /* *------------------------------------------------------------------------ * * TclAllocElemsEx -- * | | | | | | | | | > | | | > | | | 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 |
#endif /* TCL_MEM_DEBUG */
/*
*------------------------------------------------------------------------
*
* TclAllocElemsEx --
*
* See TclAttemptAllocElemsEx. This function differs in that it panics
* on failure.
*
* Results:
* Non-NULL pointer to allocated memory block.
*
* Side effects:
* Panics if memory of at least the requested size could not be
* allocated.
*
*------------------------------------------------------------------------
*/
void *
TclAllocElemsEx(
Tcl_Size elemCount, /* Allocation will store at least these many... */
Tcl_Size elemSize, /* ...elements of this size */
Tcl_Size leadSize, /* Additional leading space in bytes */
Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored here if
* non-NULL. Only modified on success */
{
void *ptr = TclAttemptReallocElemsEx(
NULL, elemCount, elemSize, leadSize, capacityPtr);
if (ptr == NULL) {
Tcl_Panic("Failed to allocate %" TCL_SIZE_MODIFIER
"d elements of size %" TCL_SIZE_MODIFIER "d bytes.",
elemCount,
elemSize);
}
return ptr;
}
/*
*------------------------------------------------------------------------
*
* TclAttemptReallocElemsEx --
*
* Attempts to allocate (oldPtr == NULL) or reallocate memory of the
* requested size plus some more for future growth. The amount of
* reallocation is adjusted depending on failure.
*
*
* Results:
* Pointer to allocated memory block which is at least as large
* as the requested size or NULL if allocation failed.
*
*------------------------------------------------------------------------
*/
void *
TclAttemptReallocElemsEx(
void *oldPtr, /* Pointer to memory block to reallocate or
* NULL to indicate this is a new allocation */
|
| ︙ | ︙ | |||
1331 1332 1333 1334 1335 1336 1337 | } /* *------------------------------------------------------------------------ * * TclReallocElemsEx -- * | | | | | | | | | > | 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 |
}
/*
*------------------------------------------------------------------------
*
* TclReallocElemsEx --
*
* See TclAttemptReallocElemsEx. This function differs in that it panics
* on failure.
*
* Results:
* Non-NULL pointer to allocated memory block.
*
* Side effects:
* Panics if memory of at least the requested size could not be
* allocated.
*
*------------------------------------------------------------------------
*/
void *
TclReallocElemsEx(
void *oldPtr, /* Pointer to memory block to reallocate */
Tcl_Size elemCount, /* Allocation will store at least these many... */
Tcl_Size elemSize, /* ...elements of this size */
Tcl_Size leadSize, /* Additional leading space in bytes */
Tcl_Size *capacityPtr) /* OUTPUT: Actual capacity is stored here if
* non-NULL. Only modified on success */
{
void *ptr = TclAttemptReallocElemsEx(
oldPtr, elemCount, elemSize, leadSize, capacityPtr);
if (ptr == NULL) {
Tcl_Panic("Failed to reallocate %" TCL_SIZE_MODIFIER
"d elements of size %" TCL_SIZE_MODIFIER "d bytes.",
elemCount,
elemSize);
}
return ptr;
}
/*
*---------------------------------------------------------------------------
*
|
| ︙ | ︙ |
Changes to generic/tclClock.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | #include "tclTomMath.h" #include "tclStrIdxTree.h" #include "tclDate.h" #if defined(_WIN32) && defined (__clang__) && (__clang_major__ > 20) #pragma clang diagnostic ignored "-Wc++-keyword" #endif | < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#include "tclTomMath.h"
#include "tclStrIdxTree.h"
#include "tclDate.h"
#if defined(_WIN32) && defined (__clang__) && (__clang_major__ > 20)
#pragma clang diagnostic ignored "-Wc++-keyword"
#endif
/*
* Table of the days in each month, leap and common years
*/
static const int hath[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
| ︙ | ︙ | |||
73 74 75 76 77 78 79 | TclDateFields *, Tcl_Size, Tcl_Obj *const[], Tcl_WideInt *rangesVal); static int ConvertUTCToLocalUsingC(Tcl_Interp *, TclDateFields *, int); static int ConvertLocalToUTC(ClockClientData *, Tcl_Interp *, TclDateFields *, Tcl_Obj *timezoneObj, int); static int ConvertLocalToUTCUsingTable(Tcl_Interp *, | | | | | | | | | | | | < | | | > | | | < < < < < | > | | > > | > | | | | < < < | < < < < < < < < < < < < < < < < | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
TclDateFields *, Tcl_Size, Tcl_Obj *const[],
Tcl_WideInt *rangesVal);
static int ConvertUTCToLocalUsingC(Tcl_Interp *,
TclDateFields *, int);
static int ConvertLocalToUTC(ClockClientData *, Tcl_Interp *,
TclDateFields *, Tcl_Obj *timezoneObj, int);
static int ConvertLocalToUTCUsingTable(Tcl_Interp *,
TclDateFields *, int, Tcl_Obj *const[],
Tcl_WideInt *rangesVal);
static int ConvertLocalToUTCUsingC(Tcl_Interp *,
TclDateFields *, int);
static Tcl_ObjCmdProc ClockConfigureObjCmd;
static void GetYearWeekDay(TclDateFields *, int);
static void GetGregorianEraYearDay(TclDateFields *, int);
static void GetJulianDayFromEraYearMonthDay(
TclDateFields *fields, int changeover);
static void GetMonthDay(TclDateFields *);
static Tcl_WideInt WeekdayOnOrBefore(int, Tcl_WideInt);
static Tcl_ObjCmdProc ClockClicksObjCmd;
static Tcl_ObjCmdProc ClockConvertlocaltoutcObjCmd;
static int ClockGetDateFields(ClockClientData *,
Tcl_Interp *interp, TclDateFields *fields,
Tcl_Obj *timezoneObj, int changeover);
static void GetJulianDayFromEraYearWeekDay(
TclDateFields *fields, int changeover);
static Tcl_ObjCmdProc ClockGetdatefieldsObjCmd;
static Tcl_ObjCmdProc ClockGetjuliandayfromerayearmonthdayObjCmd;
static Tcl_ObjCmdProc ClockGetjuliandayfromerayearweekdayObjCmd;
static Tcl_ObjCmdProc ClockGetenvObjCmd;
static Tcl_ObjCmdProc ClockMicrosecondsObjCmd;
static Tcl_ObjCmdProc ClockMillisecondsObjCmd;
static Tcl_ObjCmdProc ClockSecondsObjCmd;
static Tcl_ObjCmdProc ClockFormatObjCmd;
static Tcl_ObjCmdProc ClockScanObjCmd;
static int ClockScanCommit(DateInfo *info,
ClockFmtScnCmdArgs *opts);
static int ClockFreeScan(DateInfo *info,
Tcl_Obj *strObj, ClockFmtScnCmdArgs *opts);
static int ClockCalcRelTime(DateInfo *info,
ClockFmtScnCmdArgs *opts);
static Tcl_ObjCmdProc ClockAddObjCmd;
static int ClockValidDate(DateInfo *,
ClockFmtScnCmdArgs *, int stage);
static struct tm * ThreadSafeLocalTime(const time_t *);
static size_t TzsetIfNecessary(void);
static void ClockDeleteCmdProc(void *);
static Tcl_ObjCmdProc ClockSafeCatchCmd;
static void ClockFinalize(void *);
/*
* Structure containing description of "native" clock commands to create.
*/
struct ClockCommand {
const char *name; /* The tail of the command name. The full name
* is "::tcl::clock::<name>". When NULL marks
* the end of the table. */
Tcl_ObjCmdProc *objCmdProc; /* Function that implements the command. This
* will always have the ClockClientData sent
* to it, but may well ignore this data. */
CompileProc *compileProc; /* The compiler for the command. */
void *clientData; /* Any clientData to give the command (if NULL
* a reference to ClockClientData will be sent) */
};
static const struct ClockCommand clockCommands[] = {
{"add", ClockAddObjCmd, TclCompileBasicMin1ArgCmd, NULL},
{"clicks", ClockClicksObjCmd, TclCompileClockClicksCmd, NULL},
{"format", ClockFormatObjCmd, TclCompileBasicMin1ArgCmd, NULL},
{"getenv", ClockGetenvObjCmd, TclCompileBasicMin1ArgCmd, NULL},
{"microseconds", ClockMicrosecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(1)},
{"milliseconds", ClockMillisecondsObjCmd,TclCompileClockReadingCmd, INT2PTR(2)},
{"scan", ClockScanObjCmd, TclCompileBasicMin1ArgCmd, NULL},
{"seconds", ClockSecondsObjCmd, TclCompileClockReadingCmd, INT2PTR(3)},
{"ConvertLocalToUTC", ClockConvertlocaltoutcObjCmd, NULL, NULL},
{"GetDateFields", ClockGetdatefieldsObjCmd, NULL, NULL},
{"GetJulianDayFromEraYearMonthDay",
ClockGetjuliandayfromerayearmonthdayObjCmd, NULL, NULL},
{"GetJulianDayFromEraYearWeekDay",
ClockGetjuliandayfromerayearweekdayObjCmd, NULL, NULL},
{"catch", ClockSafeCatchCmd, TclCompileBasicMin1ArgCmd, NULL},
{NULL, NULL, NULL, NULL}
};
/*
*----------------------------------------------------------------------
*
* TclClockInit --
*
|
| ︙ | ︙ | |||
191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
*----------------------------------------------------------------------
*/
void
TclClockInit(
Tcl_Interp *interp) /* Tcl interpreter */
{
static int initialized = 0; /* global clock engine initialized (in process) */
/*
* Register handler to finalize clock on exit.
*/
if (!initialized) {
Tcl_CreateExitHandler(ClockFinalize, NULL);
| > > > > > > | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
*----------------------------------------------------------------------
*/
void
TclClockInit(
Tcl_Interp *interp) /* Tcl interpreter */
{
const struct ClockCommand *clockCmdPtr;
char cmdName[50]; /* Buffer large enough to hold the string
*::tcl::clock::GetJulianDayFromEraYearMonthDay
* plus a terminating NUL. */
Command *cmdPtr;
static int initialized = 0; /* global clock engine initialized (in process) */
/*
* Register handler to finalize clock on exit.
*/
if (!initialized) {
Tcl_CreateExitHandler(ClockFinalize, NULL);
|
| ︙ | ︙ | |||
216 217 218 219 220 221 222 |
/*
* Create the client data, which is a refcounted literal pool.
*/
ClockClientData *data = (ClockClientData *)Tcl_Alloc(sizeof(ClockClientData));
data->refCount = 0;
| | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
/*
* Create the client data, which is a refcounted literal pool.
*/
ClockClientData *data = (ClockClientData *)Tcl_Alloc(sizeof(ClockClientData));
data->refCount = 0;
data->literals = (Tcl_Obj **)Tcl_Alloc(LIT__END * sizeof(Tcl_Obj*));
int i;
for (i = 0; i < LIT__END; ++i) {
TclInitObjRef(data->literals[i], Tcl_NewStringObj(
Literals[i], TCL_AUTO_LENGTH));
}
data->mcLiterals = NULL;
data->mcLitIdxs = NULL;
|
| ︙ | ︙ | |||
267 268 269 270 271 272 273 |
data->defFlags = CLF_VALIDATE;
/*
* Install the commands.
*/
| | | | | > > | | | | > > | > | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
data->defFlags = CLF_VALIDATE;
/*
* Install the commands.
*/
#define TCL_CLOCK_PREFIX_LEN 14 /* == strlen("::tcl::clock::") */
memcpy(cmdName, "::tcl::clock::", TCL_CLOCK_PREFIX_LEN);
for (clockCmdPtr=clockCommands ; clockCmdPtr->name!=NULL ; clockCmdPtr++) {
void *clientData;
strcpy(cmdName + TCL_CLOCK_PREFIX_LEN, clockCmdPtr->name);
if (!(clientData = clockCmdPtr->clientData)) {
clientData = data;
data->refCount++;
}
cmdPtr = (Command *)Tcl_CreateObjCommand(interp, cmdName,
clockCmdPtr->objCmdProc, clientData,
clockCmdPtr->clientData ? NULL : ClockDeleteCmdProc);
cmdPtr->compileProc = clockCmdPtr->compileProc ?
clockCmdPtr->compileProc : TclCompileBasicMin0ArgCmd;
}
cmdPtr = (Command *) Tcl_CreateObjCommand(interp,
"::tcl::unsupported::clock::configure",
ClockConfigureObjCmd, data, ClockDeleteCmdProc);
data->refCount++;
cmdPtr->compileProc = TclCompileBasicMin0ArgCmd;
}
/*
*----------------------------------------------------------------------
*
* ClockConfigureClear --
*
|
| ︙ | ︙ | |||
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
TclClockMCDict(
ClockFmtScnCmdArgs *opts)
{
ClockClientData *dataPtr = opts->dataPtr;
/* if dict not yet retrieved */
if (opts->mcDictObj == NULL) {
/* if locale was not yet used */
if (!(opts->flags & CLF_LOCALE_USED)) {
opts->localeObj = NormLocaleObj(dataPtr, opts->interp,
opts->localeObj, &opts->mcDictObj);
if (opts->localeObj == NULL) {
Tcl_SetObjResult(opts->interp, Tcl_NewStringObj(
"locale not specified and no default locale set",
TCL_AUTO_LENGTH));
Tcl_SetErrorCode(opts->interp, "CLOCK", "badOption", (char *)NULL);
return NULL;
}
opts->flags |= CLF_LOCALE_USED;
/* check locale literals already available (on demand creation) */
if (dataPtr->mcLiterals == NULL) {
int i;
dataPtr->mcLiterals = (Tcl_Obj **)
| > | | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
TclClockMCDict(
ClockFmtScnCmdArgs *opts)
{
ClockClientData *dataPtr = opts->dataPtr;
/* if dict not yet retrieved */
if (opts->mcDictObj == NULL) {
/* if locale was not yet used */
if (!(opts->flags & CLF_LOCALE_USED)) {
opts->localeObj = NormLocaleObj(dataPtr, opts->interp,
opts->localeObj, &opts->mcDictObj);
if (opts->localeObj == NULL) {
Tcl_SetObjResult(opts->interp, Tcl_NewStringObj(
"locale not specified and no default locale set",
TCL_AUTO_LENGTH));
Tcl_SetErrorCode(opts->interp, "CLOCK", "badOption", (char *)NULL);
return NULL;
}
opts->flags |= CLF_LOCALE_USED;
/* check locale literals already available (on demand creation) */
if (dataPtr->mcLiterals == NULL) {
int i;
dataPtr->mcLiterals = (Tcl_Obj **)
Tcl_Alloc(MCLIT__END * sizeof(Tcl_Obj*));
for (i = 0; i < MCLIT__END; ++i) {
TclInitObjRef(dataPtr->mcLiterals[i], Tcl_NewStringObj(
MsgCtLiterals[i], TCL_AUTO_LENGTH));
}
}
}
|
| ︙ | ︙ | |||
902 903 904 905 906 907 908 |
}
}
/* if literal storage for indices not yet created */
if (dataPtr->mcLitIdxs == NULL) {
int i;
| | | 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 |
}
}
/* if literal storage for indices not yet created */
if (dataPtr->mcLitIdxs == NULL) {
int i;
dataPtr->mcLitIdxs = (Tcl_Obj **)Tcl_Alloc(MCLIT__END * sizeof(Tcl_Obj*));
for (i = 0; i < MCLIT__END; ++i) {
TclInitObjRef(dataPtr->mcLitIdxs[i],
Tcl_NewStringObj(MsgCtLitIdxs[i], TCL_AUTO_LENGTH));
}
}
return Tcl_DictObjPut(opts->interp, opts->mcDictObj,
|
| ︙ | ︙ | |||
962 963 964 965 966 967 968 |
*----------------------------------------------------------------------
*/
static int
ClockConfigureObjCmd(
void *clientData, /* Client data containing literal pool */
Tcl_Interp *interp, /* Tcl interpreter */
| | | | | | | 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 |
*----------------------------------------------------------------------
*/
static int
ClockConfigureObjCmd(
void *clientData, /* Client data containing literal pool */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const objv[]) /* Parameter vector */
{
ClockClientData *dataPtr = (ClockClientData *)clientData;
static const char *const options[] = {
"-default-locale", "-clear", "-current-locale",
"-year-century", "-century-switch",
"-min-year", "-max-year", "-max-jdn", "-validate",
"-init-complete", "-setup-tz", "-system-tz", NULL
};
enum optionInd {
CLOCK_DEFAULT_LOCALE, CLOCK_CLEAR_CACHE, CLOCK_CURRENT_LOCALE,
CLOCK_YEAR_CENTURY, CLOCK_CENTURY_SWITCH,
CLOCK_MIN_YEAR, CLOCK_MAX_YEAR, CLOCK_MAX_JDN, CLOCK_VALIDATE,
CLOCK_INIT_COMPLETE, CLOCK_SETUP_TZ, CLOCK_SYSTEM_TZ
};
int optionIndex; /* Index of an option. */
Tcl_Size i;
for (i = 1; i < objc; i++) {
if (Tcl_GetIndexFromObj(interp, objv[i++], options,
"option", 0, &optionIndex) != TCL_OK) {
|
| ︙ | ︙ | |||
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 |
Tcl_SetObjResult(interp,
Tcl_NewBooleanObj(dataPtr->defFlags & CLF_VALIDATE));
}
break;
case CLOCK_CLEAR_CACHE:
ClockConfigureClear(dataPtr);
break;
default:
TCL_UNREACHABLE();
}
}
return TCL_OK;
}
| > > > > > > > > > > > > > > > > > > > > | 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 |
Tcl_SetObjResult(interp,
Tcl_NewBooleanObj(dataPtr->defFlags & CLF_VALIDATE));
}
break;
case CLOCK_CLEAR_CACHE:
ClockConfigureClear(dataPtr);
break;
case CLOCK_INIT_COMPLETE: {
/*
* Init completed.
* Compile clock ensemble (performance purposes).
*/
Tcl_Command token = Tcl_FindCommand(interp, "::clock",
NULL, TCL_GLOBAL_ONLY);
if (!token) {
return TCL_ERROR;
}
int ensFlags = 0;
if (Tcl_GetEnsembleFlags(interp, token, &ensFlags) != TCL_OK) {
return TCL_ERROR;
}
ensFlags |= ENSEMBLE_COMPILE;
if (Tcl_SetEnsembleFlags(interp, token, ensFlags) != TCL_OK) {
return TCL_ERROR;
}
break;
}
default:
TCL_UNREACHABLE();
}
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 |
*----------------------------------------------------------------------
*/
static int
ClockConvertlocaltoutcObjCmd(
void *clientData, /* Literal table */
Tcl_Interp *interp, /* Tcl interpreter */
| | | | 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 |
*----------------------------------------------------------------------
*/
static int
ClockConvertlocaltoutcObjCmd(
void *clientData, /* Literal table */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter vector */
{
ClockClientData *dataPtr = (ClockClientData *)clientData;
Tcl_Obj *secondsObj;
Tcl_Obj *dict;
int changeover;
TclDateFields fields;
int created = 0;
fields.tzName = NULL;
/*
* Check params and convert time.
*/
if (objc != 4) {
|
| ︙ | ︙ | |||
1439 1440 1441 1442 1443 1444 1445 |
/*
* Copy-on-write; set the 'seconds' field in the dictionary and place the
* modified dictionary in the interpreter result.
*/
if (Tcl_IsShared(dict)) {
dict = Tcl_DuplicateObj(dict);
| | | 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 |
/*
* Copy-on-write; set the 'seconds' field in the dictionary and place the
* modified dictionary in the interpreter result.
*/
if (Tcl_IsShared(dict)) {
dict = Tcl_DuplicateObj(dict);
created = 1;
Tcl_IncrRefCount(dict);
}
int result = Tcl_DictObjPut(interp, dict, dataPtr->literals[LIT_SECONDS],
Tcl_NewWideIntObj(fields.seconds));
if (result == TCL_OK) {
Tcl_SetObjResult(interp, dict);
}
|
| ︙ | ︙ | |||
1486 1487 1488 1489 1490 1491 1492 |
*----------------------------------------------------------------------
*/
int
ClockGetdatefieldsObjCmd(
void *clientData, /* Opaque pointer to literal pool, etc. */
Tcl_Interp *interp, /* Tcl interpreter */
| | | 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 |
*----------------------------------------------------------------------
*/
int
ClockGetdatefieldsObjCmd(
void *clientData, /* Opaque pointer to literal pool, etc. */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter vector */
{
TclDateFields fields;
Tcl_Obj *dict;
ClockClientData *dataPtr = (ClockClientData *)clientData;
Tcl_Obj *const *lit = dataPtr->literals;
int changeover;
|
| ︙ | ︙ | |||
1680 1681 1682 1683 1684 1685 1686 |
return TclGetIntFromObj(interp, value, storePtr);
}
static int
ClockGetjuliandayfromerayearmonthdayObjCmd(
void *clientData, /* Opaque pointer to literal pool, etc. */
Tcl_Interp *interp, /* Tcl interpreter */
| | | 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 |
return TclGetIntFromObj(interp, value, storePtr);
}
static int
ClockGetjuliandayfromerayearmonthdayObjCmd(
void *clientData, /* Opaque pointer to literal pool, etc. */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter vector */
{
TclDateFields fields;
Tcl_Obj *dict;
ClockClientData *data = (ClockClientData *)clientData;
Tcl_Obj *const *lit = data->literals;
int changeover;
|
| ︙ | ︙ | |||
1769 1770 1771 1772 1773 1774 1775 |
*----------------------------------------------------------------------
*/
static int
ClockGetjuliandayfromerayearweekdayObjCmd(
void *clientData, /* Opaque pointer to literal pool, etc. */
Tcl_Interp *interp, /* Tcl interpreter */
| | | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 |
*----------------------------------------------------------------------
*/
static int
ClockGetjuliandayfromerayearweekdayObjCmd(
void *clientData, /* Opaque pointer to literal pool, etc. */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter vector */
{
TclDateFields fields;
Tcl_Obj *dict;
ClockClientData *data = (ClockClientData *)clientData;
Tcl_Obj *const *lit = data->literals;
int changeover;
|
| ︙ | ︙ | |||
1992 1993 1994 1995 1996 1997 1998 |
*----------------------------------------------------------------------
*/
static int
ConvertLocalToUTCUsingTable(
Tcl_Interp *interp, /* Tcl interpreter */
TclDateFields *fields, /* Time to convert, with 'seconds' filled in */
| | | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 |
*----------------------------------------------------------------------
*/
static int
ConvertLocalToUTCUsingTable(
Tcl_Interp *interp, /* Tcl interpreter */
TclDateFields *fields, /* Time to convert, with 'seconds' filled in */
int rowc, /* Number of points at which time changes */
Tcl_Obj *const rowv[], /* Points at which time changes */
Tcl_WideInt *rangesVal) /* Return bounds for time period */
{
Tcl_Obj *row;
Tcl_Size cellc;
Tcl_Obj **cellv;
struct {
|
| ︙ | ︙ | |||
3019 3020 3021 3022 3023 3024 3025 |
*----------------------------------------------------------------------
*/
int
ClockGetenvObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 |
*----------------------------------------------------------------------
*/
int
ClockGetenvObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
#ifdef _WIN32
const WCHAR *varName;
const WCHAR *varValue;
Tcl_DString ds;
#else
const char *varName;
|
| ︙ | ︙ | |||
3123 3124 3125 3126 3127 3128 3129 |
*----------------------------------------------------------------------
*/
int
ClockClicksObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
| | > | > | | 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 |
*----------------------------------------------------------------------
*/
int
ClockClicksObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter values */
{
static const char *const clicksSwitches[] = {
"-milliseconds", "-microseconds", NULL
};
enum ClicksSwitch {
CLICKS_MILLIS, CLICKS_MICROS, CLICKS_NATIVE
};
int index = CLICKS_NATIVE;
Tcl_Time now;
Tcl_WideInt clicks = 0;
switch (objc) {
case 1:
break;
case 2:
if (Tcl_GetIndexFromObj(interp, objv[1], clicksSwitches, "option", 0,
&index) != TCL_OK) {
return TCL_ERROR;
}
break;
default:
Tcl_WrongNumArgs(interp, 0, objv, "clock clicks ?-switch?");
return TCL_ERROR;
}
switch (index) {
case CLICKS_MILLIS:
Tcl_GetTime(&now);
clicks = now.sec * 1000LL + now.usec / 1000;
break;
case CLICKS_NATIVE:
#ifdef TCL_WIDE_CLICKS
clicks = TclpGetWideClicks();
#else
clicks = (Tcl_WideInt)TclpGetClicks();
#endif
break;
case CLICKS_MICROS:
clicks = TclpGetMicroseconds();
break;
default:
TCL_UNREACHABLE();
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(clicks));
return TCL_OK;
|
| ︙ | ︙ | |||
3193 3194 3195 3196 3197 3198 3199 |
*----------------------------------------------------------------------
*/
int
ClockMillisecondsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
| | > > | > | 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 |
*----------------------------------------------------------------------
*/
int
ClockMillisecondsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter values */
{
Tcl_Time now;
Tcl_Obj *timeObj;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 0, objv, "clock milliseconds");
return TCL_ERROR;
}
Tcl_GetTime(&now);
TclNewUIntObj(timeObj, (Tcl_WideUInt)
now.sec * 1000 + now.usec / 1000);
Tcl_SetObjResult(interp, timeObj);
return TCL_OK;
}
/*----------------------------------------------------------------------
*
* ClockMicrosecondsObjCmd -
|
| ︙ | ︙ | |||
3229 3230 3231 3232 3233 3234 3235 |
*----------------------------------------------------------------------
*/
int
ClockMicrosecondsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
| | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 |
*----------------------------------------------------------------------
*/
int
ClockMicrosecondsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter values */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 0, objv, "clock microseconds");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(TclpGetMicroseconds()));
return TCL_OK;
}
static inline void
ClockInitFmtScnArgs(
ClockClientData *dataPtr,
Tcl_Interp *interp,
|
| ︙ | ︙ | |||
3320 3321 3322 3323 3324 3325 3326 |
static int
ClockParseFmtScnArgs(
ClockFmtScnCmdArgs *opts, /* Result vector: format, locale, timezone... */
TclDateFields *date, /* Extracted date-time corresponding base
* (by scan or add) resp. clockval (by format) */
Tcl_Size objc, /* Parameter count */
| | | 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 |
static int
ClockParseFmtScnArgs(
ClockFmtScnCmdArgs *opts, /* Result vector: format, locale, timezone... */
TclDateFields *date, /* Extracted date-time corresponding base
* (by scan or add) resp. clockval (by format) */
Tcl_Size objc, /* Parameter count */
Tcl_Obj *const objv[], /* Parameter vector */
ClockOperation operation, /* What operation are we doing: format, scan, add */
const char *syntax) /* Syntax of the current command */
{
Tcl_Interp *interp = opts->interp;
ClockClientData *dataPtr = opts->dataPtr;
int gmtFlag = 0;
static const char *const options[] = {
|
| ︙ | ︙ | |||
3496 3497 3498 3499 3500 3501 3502 |
|| baseVal < TCL_MIN_SECONDS || baseVal > TCL_MAX_SECONDS) {
baseOverflow:
Tcl_SetObjResult(interp, dataPtr->literals[LIT_INTEGER_VALUE_TOO_LARGE]);
i = baseIdx;
goto badOption;
}
} else {
| | | | | 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 |
|| baseVal < TCL_MIN_SECONDS || baseVal > TCL_MAX_SECONDS) {
baseOverflow:
Tcl_SetObjResult(interp, dataPtr->literals[LIT_INTEGER_VALUE_TOO_LARGE]);
i = baseIdx;
goto badOption;
}
} else {
Tcl_Time now;
baseNow:
Tcl_GetTime(&now);
baseVal = (Tcl_WideInt) now.sec;
}
/*
* Extract year, month and day from the base time for the parser to use as
* defaults
*/
|
| ︙ | ︙ | |||
3564 3565 3566 3567 3568 3569 3570 |
*----------------------------------------------------------------------
*/
int
ClockFormatObjCmd(
void *clientData, /* Client data containing literal pool */
Tcl_Interp *interp, /* Tcl interpreter */
| | | | 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 |
*----------------------------------------------------------------------
*/
int
ClockFormatObjCmd(
void *clientData, /* Client data containing literal pool */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const objv[]) /* Parameter values */
{
ClockClientData *dataPtr = (ClockClientData *)clientData;
static const char *syntax = "clock format clockval|now "
"?-format string? "
"?-gmt boolean? "
"?-locale LOCALE? ?-timezone ZONE?";
int ret;
|
| ︙ | ︙ | |||
3633 3634 3635 3636 3637 3638 3639 |
*----------------------------------------------------------------------
*/
int
ClockScanObjCmd(
void *clientData, /* Client data containing literal pool */
Tcl_Interp *interp, /* Tcl interpreter */
| | | | 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 |
*----------------------------------------------------------------------
*/
int
ClockScanObjCmd(
void *clientData, /* Client data containing literal pool */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const objv[]) /* Parameter values */
{
ClockClientData *dataPtr = (ClockClientData *)clientData;
static const char *syntax = "clock scan string "
"?-base seconds? "
"?-format string? "
"?-gmt boolean? "
"?-locale LOCALE? ?-timezone ZONE? ?-validate boolean?";
|
| ︙ | ︙ | |||
4449 4450 4451 4452 4453 4454 4455 | * ClockAddObjCmd -- , clock add -- * * Adds an offset to a given time. * * Refer to the user documentation to see what it exactly does. * * Syntax: | | | | | | | | | | | | | | | 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 |
* ClockAddObjCmd -- , clock add --
*
* Adds an offset to a given time.
*
* Refer to the user documentation to see what it exactly does.
*
* Syntax:
* clock add clockval ?count unit?... ?-option value?
*
* Parameters:
* clockval -- Starting time value
* count -- Amount of a unit of time to add
* unit -- Unit of time to add, must be one of:
* years year months month weeks week
* days day hours hour minutes minute
* seconds second
*
* Options:
* -gmt BOOLEAN
* Flag synonymous with '-timezone :GMT'
* -timezone ZONE
* Name of the time zone in which calculations are to be done.
* -locale NAME
* Name of the locale in which calculations are to be done.
* Used to determine the Gregorian change date.
*
* Results:
* Returns a standard Tcl result with the given time adjusted
* by the given offset(s) in order.
*
* Notes:
* It is possible that adding a number of months or years will adjust the
* day of the month as well. For instance, the time at one month after
* 31 January is either 28 or 29 February, because February has fewer
* than 31 days.
*
*----------------------------------------------------------------------
*/
int
ClockAddObjCmd(
void *clientData, /* Client data containing literal pool */
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const objv[]) /* Parameter values */
{
static const char *syntax = "clock add clockval|now ?number units?..."
"?-gmt boolean? "
"?-locale LOCALE? ?-timezone ZONE?";
ClockClientData *dataPtr = (ClockClientData *)clientData;
int ret;
ClockFmtScnCmdArgs opts; /* Format, locale, timezone and base */
|
| ︙ | ︙ | |||
4577 4578 4579 4580 4581 4582 4583 | } /* if in-between conversion needed (already have relative date/time), * correct date info, because the local date/time may be changed, so * refresh it now (see test clock-30.34 "clock add jump over DST hole") */ if ((info->flags & CLF_RELCONV) || | | > | 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 |
}
/* if in-between conversion needed (already have relative date/time),
* correct date info, because the local date/time may be changed, so
* refresh it now (see test clock-30.34 "clock add jump over DST hole") */
if ((info->flags & CLF_RELCONV) ||
(yyRelSeconds && unitIndex < CLC_ADD_HOURS)
) {
if (ClockCalcRelTime(info, &opts) != TCL_OK) {
goto done;
}
}
/* process increment by offset + unit */
switch (unitIndex) {
|
| ︙ | ︙ | |||
4667 4668 4669 4670 4671 4672 4673 |
*----------------------------------------------------------------------
*/
int
ClockSecondsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
| | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 |
*----------------------------------------------------------------------
*/
int
ClockSecondsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const *objv) /* Parameter values */
{
Tcl_Time now;
Tcl_Obj *timeObj;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 0, objv, "clock seconds");
return TCL_ERROR;
}
Tcl_GetTime(&now);
TclNewUIntObj(timeObj, (Tcl_WideUInt)now.sec);
Tcl_SetObjResult(interp, timeObj);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ClockSafeCatchCmd --
*
* Same as "::catch" command but avoids overwriting of interp state.
*
* See [554117edde] for more info (and proper solution).
*
*----------------------------------------------------------------------
*/
int
ClockSafeCatchCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
typedef struct {
int status; /* return code status */
int flags; /* Each remaining field saves the */
int returnLevel; /* corresponding field of the Interp */
int returnCode; /* struct. These fields taken together are */
Tcl_Obj *errorInfo; /* the "state" of the interp. */
Tcl_Obj *errorCode;
Tcl_Obj *returnOpts;
Tcl_Obj *objResult;
Tcl_Obj *errorStack;
int resetErrorStack;
} InterpState;
Interp *iPtr = (Interp *)interp;
int ret, flags = 0;
InterpState *statePtr;
if (objc == 1) {
/* wrong # args : */
return Tcl_CatchObjCmd(NULL, interp, objc, objv);
}
statePtr = (InterpState *)Tcl_SaveInterpState(interp, 0);
if (!statePtr->errorInfo) {
/* todo: avoid traced get of errorInfo here */
TclInitObjRef(statePtr->errorInfo,
Tcl_ObjGetVar2(interp, iPtr->eiVar, NULL, 0));
flags |= ERR_LEGACY_COPY;
}
if (!statePtr->errorCode) {
/* todo: avoid traced get of errorCode here */
TclInitObjRef(statePtr->errorCode,
Tcl_ObjGetVar2(interp, iPtr->ecVar, NULL, 0));
flags |= ERR_LEGACY_COPY;
}
/* original catch */
ret = Tcl_CatchObjCmd(NULL, interp, objc, objv);
if (ret == TCL_ERROR) {
Tcl_DiscardInterpState((Tcl_InterpState)statePtr);
return TCL_ERROR;
}
/* overwrite result in state with catch result */
TclSetObjRef(statePtr->objResult, Tcl_GetObjResult(interp));
/* set result (together with restore state) to interpreter */
(void) Tcl_RestoreInterpState(interp, (Tcl_InterpState)statePtr);
/* todo: unless ERR_LEGACY_COPY not set in restore (branch [bug-554117edde] not merged yet) */
iPtr->flags |= (flags & ERR_LEGACY_COPY);
return ret;
}
/*
*----------------------------------------------------------------------
*
* TzsetIfNecessary --
*
* Calls the tzset() library function if the contents of the TZ
|
| ︙ | ︙ | |||
4726 4727 4728 4729 4730 4731 4732 |
TZ_INIT_MARKER, 0, 0, 0
};
static size_t
TzsetIfNecessary(void)
{
const WCHAR *tzNow; /* Current value of TZ. */
| | | | | | 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 |
TZ_INIT_MARKER, 0, 0, 0
};
static size_t
TzsetIfNecessary(void)
{
const WCHAR *tzNow; /* Current value of TZ. */
Tcl_Time now; /* Current time. */
size_t epoch; /* The tz.epoch that the TZ was read at. */
/*
* Prevent performance regression on some platforms by resolving of system time zone:
* small latency for check whether environment was changed (once per second)
* no latency if environment was changed with tcl-env (compare both epoch values)
*/
Tcl_GetTime(&now);
if (now.sec == tz.lastRefresh && tz.envEpoch == TclEnvEpoch) {
return tz.epoch;
}
tz.envEpoch = TclEnvEpoch;
tz.lastRefresh = now.sec;
/* check in lock */
Tcl_MutexLock(&clockMutex);
tzNow = getenv("TCL_TZ");
if (tzNow == NULL) {
tzNow = getenv("TZ");
}
|
| ︙ | ︙ |
Changes to generic/tclClockFmt.c.
1 2 3 4 5 6 | /* * tclClockFmt.c -- * * Contains the date format (and scan) routines. This code is back-ported * from the time and date facilities of tclSE engine, by Serg G. Brester. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * tclClockFmt.c -- * * Contains the date format (and scan) routines. This code is back-ported * from the time and date facilities of tclSE engine, by Serg G. Brester. * * Copyright (c) 2015 by Sergey G. Brester aka sebres. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclStrIdxTree.h" |
| ︙ | ︙ | |||
80 81 82 83 84 85 86 |
const char *p,
const char *e,
int sign)
{
char last;
int val = 0;
| | | | | > | | | | > | | | | | | > | | | | > | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
const char *p,
const char *e,
int sign)
{
char last;
int val = 0;
if (e - p > 10) { /* definitely overflows */
return TCL_ERROR;
}
/*
* Overflow impossible for max 9 digits ("9..9"),
* or for 10 digits if it starts with 1 ("19..9").
*/
if (e - p <= 9 || *p <= '1' ) {
while (p < e) {
val = val * 10 + (*p++ - '0');
}
*out = (sign >= 0) ? val : -val;
return TCL_OK;
}
/* 10 digits and it may overflow at last char */
e--;
while (p < e) {
val = val * 10 + (*p++ - '0');
}
last = *p - '0';
if (sign >= 0) {
if ( (val > INT_MAX / 10)
|| ((val == INT_MAX / 10) && (last > INT_MAX % 10))
) {
return TCL_ERROR; /* overflow*/
}
val = val * 10 + last;
} else {
val = -val;
if ( (val < INT_MIN / 10)
|| ((val == INT_MIN / 10) && ((INT_MIN % 10 < 0) ?
(last > -(INT_MIN % 10)) : (last > 10-(INT_MIN % 10))
))
) {
return TCL_ERROR; /* overflow*/
}
val = val * 10 - last;
}
*out = val;
return TCL_OK;
}
static inline int
Clock_str2wideInt(
Tcl_WideInt *out,
const char *p,
const char *e,
int sign)
{
char last;
Tcl_WideInt val = 0;
if (e - p > 19) { /* definitely overflows */
return TCL_ERROR;
}
/*
* Overflow impossible for max 18 digits ("9..9"),
* or for 19 digits if it starts with 8 ("89..9").
*/
if (e - p <= 18 || *p <= '8' ) {
while (p < e) {
val = val * 10 + (*p++ - '0');
}
*out = (sign >= 0) ? val : -val;
return TCL_OK;
}
/* 19 digits and it may overflow at last char */
e--;
while (p < e) {
val = val * 10 + (*p++ - '0');
}
last = *p - '0';
if (sign >= 0) {
if ( (val > WIDE_MAX / 10)
|| ((val == WIDE_MAX / 10) && (last > WIDE_MAX % 10))
) {
return TCL_ERROR; /* overflow*/
}
val = val * 10 + last;
} else {
val = -val;
if ( (val < WIDE_MIN / 10)
|| ((val == WIDE_MIN / 10) && ((WIDE_MIN % 10 < 0) ?
(last > -(WIDE_MIN % 10)) : (last > 10-(WIDE_MIN % 10))
))
) {
return TCL_ERROR; /* overflow*/
}
val = val * 10 - last;
}
*out = val;
return TCL_OK;
}
|
| ︙ | ︙ | |||
282 283 284 285 286 287 288 |
/* sign by non 0 padding */
if (padchar == '0') {
*p = '-';
}
return buf + width;
}
| < | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
/* sign by non 0 padding */
if (padchar == '0') {
*p = '-';
}
return buf + width;
}
char *
TclItoAw(
char *buf,
int val,
char padchar,
unsigned short width)
{
|
| ︙ | ︙ | |||
411 412 413 414 415 416 417 |
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
static struct ClockFmtScnStorage_GC {
ClockFmtScnStorage *stackPtr;
ClockFmtScnStorage *stackBound;
unsigned count;
} ClockFmtScnStorage_GC = {NULL, NULL, 0};
| | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
static struct ClockFmtScnStorage_GC {
ClockFmtScnStorage *stackPtr;
ClockFmtScnStorage *stackBound;
unsigned count;
} ClockFmtScnStorage_GC = {NULL, NULL, 0};
/*
*----------------------------------------------------------------------
*
* ClockFmtScnStorageGC_In --
*
* Adds an format storage object to GC.
*
|
| ︙ | ︙ | |||
454 455 456 457 458 459 460 |
TclSpliceOut(delEnt, ClockFmtScnStorage_GC.stackPtr);
ClockFmtScnStorage_GC.count--;
delEnt->prevPtr = delEnt->nextPtr = NULL;
/* remove it now */
ClockFmtScnStorageDelete(delEnt);
}
}
| | | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
TclSpliceOut(delEnt, ClockFmtScnStorage_GC.stackPtr);
ClockFmtScnStorage_GC.count--;
delEnt->prevPtr = delEnt->nextPtr = NULL;
/* remove it now */
ClockFmtScnStorageDelete(delEnt);
}
}
/*
*----------------------------------------------------------------------
*
* ClockFmtScnStorage_GC_Out --
*
* Restores (for reusing) given format storage object from GC.
*
|
| ︙ | ︙ | |||
493 494 495 496 497 498 499 | * * Used for fast searching by format string. */ static Tcl_HashTable FmtScnHashTable; static int initialized = 0; /* | | > > > > > > > | < | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
*
* Used for fast searching by format string.
*/
static Tcl_HashTable FmtScnHashTable;
static int initialized = 0;
/*
* Wrappers between pointers to hash entry and format storage object
*/
static inline Tcl_HashEntry *
HashEntry4FmtScn(
ClockFmtScnStorage *fss)
{
return (Tcl_HashEntry*)(fss + 1);
}
static inline ClockFmtScnStorage *
FmtScn4HashEntry(
Tcl_HashEntry *hKeyPtr)
{
return (ClockFmtScnStorage*)(((char*)hKeyPtr) - sizeof(ClockFmtScnStorage));
}
/*
*----------------------------------------------------------------------
*
* ClockFmtScnStorageAllocProc --
*
|
| ︙ | ︙ | |||
526 527 528 529 530 531 532 |
TCL_UNUSED(Tcl_HashTable *),/* Hash table. */
void *keyPtr) /* Key to store in the hash table entry. */
{
ClockFmtScnStorage *fss;
const char *string = (const char *) keyPtr;
Tcl_HashEntry *hPtr;
size_t size = strlen(string) + 1;
| | > | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
TCL_UNUSED(Tcl_HashTable *),/* Hash table. */
void *keyPtr) /* Key to store in the hash table entry. */
{
ClockFmtScnStorage *fss;
const char *string = (const char *) keyPtr;
Tcl_HashEntry *hPtr;
size_t size = strlen(string) + 1;
size_t allocsize = sizeof(ClockFmtScnStorage) + sizeof(Tcl_HashEntry);
allocsize += size;
if (size > sizeof(hPtr->key)) {
allocsize -= sizeof(hPtr->key);
}
fss = (ClockFmtScnStorage *)Tcl_AttemptAlloc(allocsize);
if (!fss) {
return NULL;
}
/* initialize */
memset(fss, 0, sizeof(*fss));
hPtr = HashEntry4FmtScn(fss);
memcpy(&hPtr->key.string, string, size);
hPtr->clientData = 0; /* currently unused */
return hPtr;
}
/*
|
| ︙ | ︙ | |||
597 598 599 600 601 602 603 604 605 606 607 |
*----------------------------------------------------------------------
*/
static void
ClockFmtScnStorageDelete(
ClockFmtScnStorage *fss)
{
/*
* This will delete a hash entry and call "Tcl_Free" for storage self, if
* some additionally handling required, freeEntryProc can be used instead
*/
| > | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
*----------------------------------------------------------------------
*/
static void
ClockFmtScnStorageDelete(
ClockFmtScnStorage *fss)
{
Tcl_HashEntry *hPtr = HashEntry4FmtScn(fss);
/*
* This will delete a hash entry and call "Tcl_Free" for storage self, if
* some additionally handling required, freeEntryProc can be used instead
*/
Tcl_DeleteHashEntry(hPtr);
}
/*
* Type definition of clock-format tcl object type.
*/
static const Tcl_ObjType ClockFmtObjType = {
|
| ︙ | ︙ | |||
709 710 711 712 713 714 715 |
Tcl_Obj *objPtr)
{
const char *name = "UNKNOWN";
size_t len;
ClockFmtScnStorage *fss = ObjClockFmtScn(objPtr);
if (fss != NULL) {
| > | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
Tcl_Obj *objPtr)
{
const char *name = "UNKNOWN";
size_t len;
ClockFmtScnStorage *fss = ObjClockFmtScn(objPtr);
if (fss != NULL) {
Tcl_HashEntry *hPtr = HashEntry4FmtScn(fss);
name = hPtr->key.string;
}
len = strlen(name);
objPtr->length = len++,
objPtr->bytes = (char *)Tcl_AttemptAlloc(len);
if (objPtr->bytes) {
memcpy(objPtr->bytes, name, len);
}
|
| ︙ | ︙ | |||
740 741 742 743 744 745 746 | * Side effects: * Converts given format object to ClockFmtObjType on demand for caching * the key inside its internal representation. * *---------------------------------------------------------------------- */ | | < < < < | | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
* Side effects:
* Converts given format object to ClockFmtObjType on demand for caching
* the key inside its internal representation.
*
*----------------------------------------------------------------------
*/
Tcl_Obj*
ClockFrmObjGetLocFmtKey(
Tcl_Interp *interp,
Tcl_Obj *objPtr)
{
Tcl_Obj *keyObj;
if (objPtr->typePtr != &ClockFmtObjType) {
if (ClockFmtObj_SetFromAny(interp, objPtr) != TCL_OK) {
return NULL;
}
}
keyObj = ObjLocFmtKey(objPtr);
if (keyObj) {
return keyObj;
}
keyObj = Tcl_ObjPrintf("FMT_%s", TclGetString(objPtr));
TclInitObjRef(ObjLocFmtKey(objPtr), keyObj);
return keyObj;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
813 814 815 816 817 818 819 |
Tcl_InitCustomHashTable(&FmtScnHashTable, TCL_CUSTOM_TYPE_KEYS,
&ClockFmtScnStorageHashKeyType);
initialized = 1;
}
/* get or create entry (and alocate storage) */
| | | 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 |
Tcl_InitCustomHashTable(&FmtScnHashTable, TCL_CUSTOM_TYPE_KEYS,
&ClockFmtScnStorageHashKeyType);
initialized = 1;
}
/* get or create entry (and alocate storage) */
hPtr = Tcl_CreateHashEntry(&FmtScnHashTable, strFmt, &isNew);
if (hPtr != NULL) {
fss = FmtScn4HashEntry(hPtr);
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
/* unlink if it is currently in GC */
if (isNew == 0 && fss->objRefCount == 0) {
ClockFmtScnStorage_GC_Out(fss);
|
| ︙ | ︙ | |||
970 971 972 973 974 975 976 |
if (valObj->typePtr == &ClockFmtObjType) {
TclUnsetObjRef(ObjLocFmtKey(valObj));
ObjLocFmtKey(valObj) = valObj;
}
}
}
| | > | 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
if (valObj->typePtr == &ClockFmtObjType) {
TclUnsetObjRef(ObjLocFmtKey(valObj));
ObjLocFmtKey(valObj) = valObj;
}
}
}
done:
TclUnsetObjRef(keyObj);
return (opts->formatObj = valObj);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 |
/* regards all possible spaces here (because they are optional) */
end = p + tok->lookAhMax + yySpaceCount + 1;
if (end > info->dateEnd) {
end = info->dateEnd;
}
p += tok->lookAhMin;
if (laTok->map && p < end) {
/* try to find laTok between [lookAhMin, lookAhMax] */
while (minLen < maxLen) {
const char *f = FindTokenBegin(p, end, laTok,
TCL_CLOCK_FULL_COMPAT ? opts->flags : CLF_STRICT);
/* if found (not below lookAhMax) */
if (f < end) {
break;
| > | 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 |
/* regards all possible spaces here (because they are optional) */
end = p + tok->lookAhMax + yySpaceCount + 1;
if (end > info->dateEnd) {
end = info->dateEnd;
}
p += tok->lookAhMin;
if (laTok->map && p < end) {
/* try to find laTok between [lookAhMin, lookAhMax] */
while (minLen < maxLen) {
const char *f = FindTokenBegin(p, end, laTok,
TCL_CLOCK_FULL_COMPAT ? opts->flags : CLF_STRICT);
/* if found (not below lookAhMax) */
if (f < end) {
break;
|
| ︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 |
/* is a list */
if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
return TCL_ERROR;
}
/* search in list */
| | > | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 |
/* is a list */
if (TclListObjGetElements(opts->interp, valObj, &lstc, &lstv) != TCL_OK) {
return TCL_ERROR;
}
/* search in list */
return ObjListSearch(info, val, lstv, lstc,
minLen, maxLen);
}
#endif
/*
*----------------------------------------------------------------------
*
* ClockMCGetListIdxTree --
|
| ︙ | ︙ | |||
1343 1344 1345 1346 1347 1348 1349 |
*
*----------------------------------------------------------------------
*/
static TclStrIdxTree *
ClockMCGetMultiListIdxTree(
ClockFmtScnCmdArgs *opts,
| | | 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 |
*
*----------------------------------------------------------------------
*/
static TclStrIdxTree *
ClockMCGetMultiListIdxTree(
ClockFmtScnCmdArgs *opts,
int mcKey,
const int *mcKeys)
{
TclStrIdxTree * idxTree;
Tcl_Obj *objPtr = TclClockMCGetIdx(opts, mcKey);
if (objPtr != NULL
&& (idxTree = TclStrIdxTreeGetFromObj(objPtr)) != NULL) {
|
| ︙ | ︙ | |||
2133 2134 2135 2136 2137 2138 2139 |
if (++(tok) >= (chain) + (tokCnt)) { \
chain = (type)Tcl_Realloc((char *)(chain), \
(tokCnt + CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE) * sizeof(*(tok))); \
(tok) = (chain) + (tokCnt); \
(tokCnt) += CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE; \
} \
memset(tok, 0, sizeof(*(tok)));
| | < < < < < < < | 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 |
if (++(tok) >= (chain) + (tokCnt)) { \
chain = (type)Tcl_Realloc((char *)(chain), \
(tokCnt + CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE) * sizeof(*(tok))); \
(tok) = (chain) + (tokCnt); \
(tokCnt) += CLOCK_MIN_TOK_CHAIN_BLOCK_SIZE; \
} \
memset(tok, 0, sizeof(*(tok)));
/*
*----------------------------------------------------------------------
*/
static ClockFmtScnStorage *
ClockGetOrParseScanFormat(
Tcl_Interp *interp, /* Tcl interpreter */
Tcl_Obj *formatObj) /* Format container */
{
|
| ︙ | ︙ | |||
2169 2170 2171 2172 2173 2174 2175 |
/* first time scanning - tokenize format */
if (fss->scnTok == NULL) {
ClockScanToken *tok, *scnTok;
unsigned tokCnt;
const char *p, *e, *cp;
| | | 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 |
/* first time scanning - tokenize format */
if (fss->scnTok == NULL) {
ClockScanToken *tok, *scnTok;
unsigned tokCnt;
const char *p, *e, *cp;
e = p = HashEntry4FmtScn(fss)->key.string;
e += strlen(p);
/* estimate token count by % char and format length */
fss->scnTokC = EstimateTokenCount(p, e);
fss->scnSpaceCount = 0;
|
| ︙ | ︙ | |||
2205 2206 2207 2208 2209 2210 2211 | tok->tokWord.end = p + 1; AllocTokenInChain(tok, scnTok, fss->scnTokC, ClockScanToken *); tokCnt++; p++; continue; case 'E': scnMap = ScnETokenMap, | | | 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 | tok->tokWord.end = p + 1; AllocTokenInChain(tok, scnTok, fss->scnTokC, ClockScanToken *); tokCnt++; p++; continue; case 'E': scnMap = ScnETokenMap, mapIndex = ScnETokenMapIndex, aliasIndex = ScnETokenMapAliasIndex; p++; break; case 'O': scnMap = ScnOTokenMap, mapIndex = ScnOTokenMapIndex, aliasIndex = ScnOTokenMapAliasIndex; |
| ︙ | ︙ | |||
2450 2451 2452 2453 2454 2455 2456 |
}
}
DetermineGreedySearchLen(opts, info, tok, &minLen, &size);
if (size < map->minSize) {
/* missing input -> error */
| | | 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 |
}
}
DetermineGreedySearchLen(opts, info, tok, &minLen, &size);
if (size < map->minSize) {
/* missing input -> error */
if ((map->flags & CLF_OPTIONAL)) {
continue;
}
goto not_match;
}
/* string 2 number, put number into info structure by offset */
if (map->offs) {
p = yyInput;
|
| ︙ | ︙ | |||
2481 2482 2483 2484 2485 2486 2487 |
break;
}
case CTOKT_PARSER:
switch (map->parser(opts, info, tok)) {
case TCL_OK:
break;
case TCL_RETURN:
| | | 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 |
break;
}
case CTOKT_PARSER:
switch (map->parser(opts, info, tok)) {
case TCL_OK:
break;
case TCL_RETURN:
if ((map->flags & CLF_OPTIONAL)) {
yyInput = p;
continue;
}
goto not_match;
default:
goto done;
}
|
| ︙ | ︙ | |||
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 |
* Invalidate result
*/
flags |= info->flags;
/* seconds token (%s) take precedence over all other tokens */
if ((opts->flags & CLF_EXTENDED) || !(flags & CLF_POSIXSEC)) {
if (flags & CLF_DATE) {
if (!(flags & CLF_JULIANDAY)) {
info->flags |= CLF_ASSEMBLE_SECONDS|CLF_ASSEMBLE_JULIANDAY;
/* dd precedence below ddd */
switch (flags & (CLF_MONTH|CLF_DAYOFYEAR|CLF_DAYOFMONTH)) {
case (CLF_DAYOFYEAR | CLF_DAYOFMONTH):
/* miss month: ddd over dd (without month) */
| > | 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 |
* Invalidate result
*/
flags |= info->flags;
/* seconds token (%s) take precedence over all other tokens */
if ((opts->flags & CLF_EXTENDED) || !(flags & CLF_POSIXSEC)) {
if (flags & CLF_DATE) {
if (!(flags & CLF_JULIANDAY)) {
info->flags |= CLF_ASSEMBLE_SECONDS|CLF_ASSEMBLE_JULIANDAY;
/* dd precedence below ddd */
switch (flags & (CLF_MONTH|CLF_DAYOFYEAR|CLF_DAYOFMONTH)) {
case (CLF_DAYOFYEAR | CLF_DAYOFMONTH):
/* miss month: ddd over dd (without month) */
|
| ︙ | ︙ | |||
2695 2696 2697 2698 2699 2700 2701 |
Tcl_SetObjResult(opts->interp, Tcl_NewStringObj(
"input string does not match supplied format", TCL_AUTO_LENGTH));
#else
/* to debug where exactly scan breaks */
Tcl_SetObjResult(opts->interp, Tcl_ObjPrintf(
"input string \"%s\" does not match supplied format \"%s\","
" locale \"%s\" - token \"%s\"",
| | | 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 |
Tcl_SetObjResult(opts->interp, Tcl_NewStringObj(
"input string does not match supplied format", TCL_AUTO_LENGTH));
#else
/* to debug where exactly scan breaks */
Tcl_SetObjResult(opts->interp, Tcl_ObjPrintf(
"input string \"%s\" does not match supplied format \"%s\","
" locale \"%s\" - token \"%s\"",
info->dateStart, HashEntry4FmtScn(fss)->key.string,
TclGetString(opts->localeObj),
tok && tok->tokWord.start ? tok->tokWord.start : "NULL"));
#endif
Tcl_SetErrorCode(opts->interp, "CLOCK", "badInputString", (char *)NULL);
goto done;
}
|
| ︙ | ︙ | |||
2816 2817 2818 2819 2820 2821 2822 |
v = dateFmt->date.secondOfDay / (SECONDS_PER_DAY / 10);
if (v < 0) {
v = 10 + v;
}
dateFmt->output = Clock_itoaw(dateFmt->output, v, '0', 1);
return TCL_OK;
}
| < < | 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 |
v = dateFmt->date.secondOfDay / (SECONDS_PER_DAY / 10);
if (v < 0) {
v = 10 + v;
}
dateFmt->output = Clock_itoaw(dateFmt->output, v, '0', 1);
return TCL_OK;
}
static int
ClockFmtToken_WeekOfYear_Proc(
TCL_UNUSED(ClockFmtScnCmdArgs *),
DateFormat *dateFmt,
ClockFormatToken *tok,
int *val)
{
int dow = dateFmt->date.dayOfWeek;
if (*tok->tokWord.start == 'U') {
if (dow == 7) {
dow = 0;
}
dow++;
}
*val = (dateFmt->date.dayOfYear - dow + 7) / 7;
return TCL_OK;
}
static int
ClockFmtToken_JDN_Proc(
TCL_UNUSED(ClockFmtScnCmdArgs *),
DateFormat *dateFmt,
ClockFormatToken *tok,
TCL_UNUSED(int *))
{
|
| ︙ | ︙ | |||
2908 2909 2910 2911 2912 2913 2914 |
p--;
}
*p = '\0';
dateFmt->output = p;
}
return TCL_OK;
}
| < | 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 |
p--;
}
*p = '\0';
dateFmt->output = p;
}
return TCL_OK;
}
static int
ClockFmtToken_TimeZone_Proc(
ClockFmtScnCmdArgs *opts,
DateFormat *dateFmt,
ClockFormatToken *tok,
TCL_UNUSED(int *))
{
|
| ︙ | ︙ | |||
3009 3010 3011 3012 3013 3014 3015 |
return TCL_ERROR;
}
if (rowc != 0) {
dateFmt->localeEra = TclClockLookupLastTransition(opts->interp,
dateFmt->date.localSeconds, rowc, rowv, NULL);
}
if (dateFmt->localeEra == NULL) {
| | | | 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 |
return TCL_ERROR;
}
if (rowc != 0) {
dateFmt->localeEra = TclClockLookupLastTransition(opts->interp,
dateFmt->date.localSeconds, rowc, rowv, NULL);
}
if (dateFmt->localeEra == NULL) {
dateFmt->localeEra = (Tcl_Obj*)1;
}
}
/* if no LOCALE_ERAS in catalog or era not found */
if (dateFmt->localeEra == (Tcl_Obj*)1) {
if (FrmResultAllocate(dateFmt, 11) != TCL_OK) {
return TCL_ERROR;
}
if (*tok->tokWord.start == 'C') { /* %EC */
*val = dateFmt->date.year / 100;
dateFmt->output = Clock_itoaw(dateFmt->output, *val, '0', 2);
} else { /* %Ey */
|
| ︙ | ︙ | |||
3221 3222 3223 3224 3225 3226 3227 |
static const ClockFormatTokenMap FmtWordTokenMap = {
CTOKT_WORD, NULL, 0, 0, 0, 0, 0, NULL, NULL
};
/*
*----------------------------------------------------------------------
| < < < < < < < | 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 |
static const ClockFormatTokenMap FmtWordTokenMap = {
CTOKT_WORD, NULL, 0, 0, 0, 0, 0, NULL, NULL
};
/*
*----------------------------------------------------------------------
*/
static ClockFmtScnStorage *
ClockGetOrParseFmtFormat(
Tcl_Interp *interp, /* Tcl interpreter */
Tcl_Obj *formatObj) /* Format container */
{
ClockFmtScnStorage *fss;
|
| ︙ | ︙ | |||
3254 3255 3256 3257 3258 3259 3260 |
/* first time formatting - tokenize format */
if (fss->fmtTok == NULL) {
ClockFormatToken *tok, *fmtTok;
unsigned tokCnt;
const char *p, *e, *cp;
| | | | | 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 |
/* first time formatting - tokenize format */
if (fss->fmtTok == NULL) {
ClockFormatToken *tok, *fmtTok;
unsigned tokCnt;
const char *p, *e, *cp;
e = p = HashEntry4FmtScn(fss)->key.string;
e += strlen(p);
/* estimate token count by % char and format length */
fss->fmtTokC = EstimateTokenCount(p, e);
fmtTok = tok = (ClockFormatToken *)Tcl_Alloc(sizeof(*tok) * fss->fmtTokC);
memset(tok, 0, sizeof(*tok));
tokCnt = 1;
while (p < e) {
switch (*p) {
case '%': {
const ClockFormatTokenMap *fmtMap = FmtSTokenMap;
const char *mapIndex = FmtSTokenMapIndex;
const char **aliasIndex = FmtSTokenMapAliasIndex;
if (p + 1 >= e) {
goto word_tok;
}
p++;
/* try to find modifier: */
switch (*p) {
case '%':
/* begin new word token - don't join with previous word token,
* because current mapping should be "...%%..." -> "...%..." */
tok->map = &FmtWordTokenMap;
tok->tokWord.start = p;
tok->tokWord.end = p + 1;
AllocTokenInChain(tok, fmtTok, fss->fmtTokC, ClockFormatToken *);
tokCnt++;
p++;
continue;
case 'E':
fmtMap = FmtETokenMap,
mapIndex = FmtETokenMapIndex,
aliasIndex = FmtETokenMapAliasIndex;
p++;
break;
case 'O':
fmtMap = FmtOTokenMap,
mapIndex = FmtOTokenMapIndex,
aliasIndex = FmtOTokenMapAliasIndex;
|
| ︙ | ︙ | |||
3375 3376 3377 3378 3379 3380 3381 |
}
Tcl_MutexUnlock(&ClockFmtMutex);
return fss;
}
/*
| < < < < < < < | 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 |
}
Tcl_MutexUnlock(&ClockFmtMutex);
return fss;
}
/*
*----------------------------------------------------------------------
*/
int
TclClockFormat(
DateFormat *dateFmt, /* Date fields used for parsing & converting */
ClockFmtScnCmdArgs *opts) /* Command options */
{
|
| ︙ | ︙ | |||
3483 3484 3485 3486 3487 3488 3489 |
case CTOKT_WIDE: {
Tcl_WideInt val = *WideFieldAt(dateFmt, map->offs);
if (FrmResultAllocate(dateFmt, 21) != TCL_OK) {
goto error;
}
if (map->width) {
| | < | 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 |
case CTOKT_WIDE: {
Tcl_WideInt val = *WideFieldAt(dateFmt, map->offs);
if (FrmResultAllocate(dateFmt, 21) != TCL_OK) {
goto error;
}
if (map->width) {
dateFmt->output = Clock_witoaw(dateFmt->output, val, *map->tostr, map->width);
} else {
dateFmt->output += sprintf(dateFmt->output, map->tostr, val);
}
break;
}
case CTOKT_CHAR:
if (FrmResultAllocate(dateFmt, 1) != TCL_OK) {
|
| ︙ | ︙ | |||
3560 3561 3562 3563 3564 3565 3566 |
Tcl_SetObjResult(opts->interp, result);
return TCL_OK;
}
return TCL_ERROR;
}
| < < | < < < < < < < | < < < < < < < < < < | 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 |
Tcl_SetObjResult(opts->interp, result);
return TCL_OK;
}
return TCL_ERROR;
}
void
TclClockFrmScnClearCaches(void)
{
Tcl_MutexLock(&ClockFmtMutex);
/* clear caches ... */
Tcl_MutexUnlock(&ClockFmtMutex);
}
void
TclClockFrmScnFinalize(void)
{
if (!initialized) {
return;
}
Tcl_MutexLock(&ClockFmtMutex);
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
/* clear GC */
ClockFmtScnStorage_GC.stackPtr = NULL;
ClockFmtScnStorage_GC.stackBound = NULL;
ClockFmtScnStorage_GC.count = 0;
#endif
if (initialized) {
initialized = 0;
Tcl_DeleteHashTable(&FmtScnHashTable);
}
Tcl_MutexUnlock(&ClockFmtMutex);
Tcl_MutexFinalize(&ClockFmtMutex);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclCmdAH.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | /* * The state structure used by [foreach]. Note that the actual structure has * all its working arrays appended afterwards so they can be allocated and * freed in a single step. */ | | | < < < < | | | | | | | | | | | | < < < < | < < < < < | | | < < | | | | < < | | | | < < < < < < < < < < < < < | | | < < | < < | < < < > | < < < < | | < < < < < | < < | < < | < < < | < < < < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
/*
* The state structure used by [foreach]. Note that the actual structure has
* all its working arrays appended afterwards so they can be allocated and
* freed in a single step.
*/
struct ForeachState {
Tcl_Obj *bodyPtr; /* The script body of the command. */
Tcl_Size bodyIdx; /* The argument index of the body. */
Tcl_Size j, maxj; /* Number of loop iterations. */
Tcl_Size numLists; /* Count of value lists. */
Tcl_Size *index; /* Array of value list indices. */
Tcl_Size *varcList; /* # loop variables per list. */
Tcl_Obj ***varvList; /* Array of var name lists. */
Tcl_Obj **vCopyList; /* Copies of var name list arguments. */
Tcl_Size *argcList; /* Array of value list sizes. */
Tcl_Obj ***argvList; /* Array of value lists. */
Tcl_Obj **aCopyList; /* Copies of value list arguments. */
Tcl_Obj *resultList; /* List of result values from the loop body,
* or NULL if we're not collecting them
* ([lmap] vs [foreach]). */
};
/*
* Prototypes for local procedures defined in this file:
*/
static int CheckAccess(Tcl_Interp *interp, Tcl_Obj *pathPtr,
int mode);
static Tcl_ObjCmdProc EncodingConvertfromObjCmd;
static Tcl_ObjCmdProc EncodingConverttoObjCmd;
static Tcl_ObjCmdProc EncodingDirsObjCmd;
static Tcl_ObjCmdProc EncodingNamesObjCmd;
static Tcl_ObjCmdProc EncodingProfilesObjCmd;
static Tcl_ObjCmdProc EncodingSystemObjCmd;
static Tcl_ObjCmdProc EncodingUserObjCmd;
static inline int ForeachAssignments(Tcl_Interp *interp,
struct ForeachState *statePtr);
static inline void ForeachCleanup(Tcl_Interp *interp,
struct ForeachState *statePtr);
static int GetStatBuf(Tcl_Interp *interp, Tcl_Obj *pathPtr,
Tcl_FSStatProc *statProc, Tcl_StatBuf *statPtr);
static const char * GetTypeFromMode(int mode);
static int StoreStatData(Tcl_Interp *interp, Tcl_Obj *varName,
Tcl_StatBuf *statPtr);
static int EachloopCmd(Tcl_Interp *interp, int collect,
int objc, Tcl_Obj *const objv[]);
static Tcl_NRPostProc CatchObjCmdCallback;
static Tcl_NRPostProc ExprCallback;
static Tcl_NRPostProc ForSetupCallback;
static Tcl_NRPostProc ForCondCallback;
static Tcl_NRPostProc ForNextCallback;
static Tcl_NRPostProc ForPostNextCallback;
static Tcl_NRPostProc ForeachLoopStep;
static Tcl_NRPostProc EvalCmdErrMsg;
static Tcl_ObjCmdProc FileAttrAccessTimeCmd;
static Tcl_ObjCmdProc FileAttrIsDirectoryCmd;
static Tcl_ObjCmdProc FileAttrIsExecutableCmd;
static Tcl_ObjCmdProc FileAttrIsExistingCmd;
static Tcl_ObjCmdProc FileAttrIsFileCmd;
static Tcl_ObjCmdProc FileAttrIsOwnedCmd;
static Tcl_ObjCmdProc FileAttrIsReadableCmd;
static Tcl_ObjCmdProc FileAttrIsWritableCmd;
static Tcl_ObjCmdProc FileAttrLinkStatCmd;
static Tcl_ObjCmdProc FileAttrModifyTimeCmd;
static Tcl_ObjCmdProc FileAttrSizeCmd;
static Tcl_ObjCmdProc FileAttrStatCmd;
static Tcl_ObjCmdProc FileAttrTypeCmd;
static Tcl_ObjCmdProc FilesystemSeparatorCmd;
static Tcl_ObjCmdProc FilesystemVolumesCmd;
static Tcl_ObjCmdProc PathDirNameCmd;
static Tcl_ObjCmdProc PathExtensionCmd;
static Tcl_ObjCmdProc PathFilesystemCmd;
static Tcl_ObjCmdProc PathJoinCmd;
static Tcl_ObjCmdProc PathNativeNameCmd;
static Tcl_ObjCmdProc PathNormalizeCmd;
static Tcl_ObjCmdProc PathRootNameCmd;
static Tcl_ObjCmdProc PathSplitCmd;
static Tcl_ObjCmdProc PathTailCmd;
static Tcl_ObjCmdProc PathTypeCmd;
/*
*----------------------------------------------------------------------
*
* Tcl_BreakObjCmd --
*
* This procedure is invoked to process the "break" Tcl command. See the
|
| ︙ | ︙ | |||
177 178 179 180 181 182 183 |
*----------------------------------------------------------------------
*/
int
Tcl_BreakObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
*----------------------------------------------------------------------
*/
int
Tcl_BreakObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
return TCL_BREAK;
}
|
| ︙ | ︙ | |||
208 209 210 211 212 213 214 |
*----------------------------------------------------------------------
*/
int
Tcl_CatchObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
*----------------------------------------------------------------------
*/
int
Tcl_CatchObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRCatchObjCmd, clientData, objc, objv);
}
int
TclNRCatchObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *varNamePtr = NULL;
Tcl_Obj *optionVarNamePtr = NULL;
Interp *iPtr = (Interp *) interp;
if ((objc < 2) || (objc > 4)) {
Tcl_WrongNumArgs(interp, 1, objv,
"script ?resultVarName? ?optionVarName?");
return TCL_ERROR;
}
if (objc >= 3) {
varNamePtr = objv[2];
}
if (objc == 4) {
optionVarNamePtr = objv[3];
}
TclNRAddCallback(interp, CatchObjCmdCallback, INT2PTR(objc),
varNamePtr, optionVarNamePtr, NULL);
/*
* TIP #280. Make invoking context available to caught script.
*/
return TclNREvalObjEx(interp, objv[1], 0, iPtr->cmdFramePtr, 1);
}
static int
CatchObjCmdCallback(
void *data[],
Tcl_Interp *interp,
int result)
{
Interp *iPtr = (Interp *) interp;
int objc = PTR2INT(data[0]);
Tcl_Obj *varNamePtr = (Tcl_Obj *)data[1];
Tcl_Obj *optionVarNamePtr = (Tcl_Obj *)data[2];
int rewind = iPtr->execEnvPtr->rewind;
/*
* We disable catch in interpreters where the limit has been exceeded.
*/
|
| ︙ | ︙ | |||
313 314 315 316 317 318 319 |
*----------------------------------------------------------------------
*/
int
Tcl_CdObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
*----------------------------------------------------------------------
*/
int
Tcl_CdObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *dir;
int result;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?dirName?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
376 377 378 379 380 381 382 |
*----------------------------------------------------------------------
*/
int
Tcl_ConcatObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
*----------------------------------------------------------------------
*/
int
Tcl_ConcatObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc >= 2) {
Tcl_SetObjResult(interp, Tcl_ConcatObj(objc-1, objv+1));
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
410 411 412 413 414 415 416 |
*----------------------------------------------------------------------
*/
int
Tcl_ContinueObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
*----------------------------------------------------------------------
*/
int
Tcl_ContinueObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
return TCL_CONTINUE;
}
/*
*-----------------------------------------------------------------------------
*
* TclInitEncodingCmd --
*
* This function creates the 'encoding' ensemble.
*
* Results:
* Returns the Tcl_Command so created.
*
* Side effects:
* The ensemble is initialized.
*
* This command is hidden in a safe interpreter.
*/
Tcl_Command
TclInitEncodingCmd(
Tcl_Interp* interp) /* Tcl interpreter */
{
static const EnsembleImplMap encodingImplMap[] = {
{"convertfrom", EncodingConvertfromObjCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0},
{"convertto", EncodingConverttoObjCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0},
{"dirs", EncodingDirsObjCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1},
{"names", EncodingNamesObjCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0},
{"profiles", EncodingProfilesObjCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0},
{"system", EncodingSystemObjCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1},
{"user", EncodingUserObjCmd, TclCompileBasic0ArgCmd, NULL, NULL, 1},
{NULL, NULL, NULL, NULL, NULL, 0}
};
return TclMakeEnsemble(interp, "encoding", encodingImplMap);
}
/*
*------------------------------------------------------------------------
*
* EncodingConvertParseOptions --
*
* Common routine for parsing arguments passed to encoding convertfrom
* and encoding convertto.
*
* Results:
* TCL_OK or TCL_ERROR.
*
* Side effects:
* On success,
* - *encPtr is set to the encoding. Must be freed with Tcl_FreeEncoding
* if non-NULL
* - *dataObjPtr is set to the Tcl_Obj containing the data to encode or
* decode
* - *profilePtr is set to encoding error handling profile
* - *failVarPtr is set to -failindex option value or NULL
* On error, all of the above are uninitialized.
*
*------------------------------------------------------------------------
*/
static int
EncodingConvertParseOptions(
Tcl_Interp *interp, /* For error messages. May be NULL */
int objc, /* Number of arguments */
Tcl_Obj *const objv[], /* Argument objects as passed to command. */
Tcl_Encoding *encPtr, /* Where to store the encoding */
Tcl_Obj **dataObjPtr, /* Where to store ptr to Tcl_Obj containing data */
int *profilePtr, /* Bit mask of encoding option profile */
Tcl_Obj **failVarPtr) /* Where to store -failindex option value */
{
static const char *const options[] = {"-profile", "-failindex", NULL};
enum convertfromOptions { PROFILE, FAILINDEX } optIndex;
|
| ︙ | ︙ | |||
521 522 523 524 525 526 527 |
*encPtr = encoding;
*dataObjPtr = dataObj;
*profilePtr = profile;
*failVarPtr = failVarObj;
return TCL_OK;
}
| | | | | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
*encPtr = encoding;
*dataObjPtr = dataObj;
*profilePtr = profile;
*failVarPtr = failVarObj;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* EncodingConvertfromObjCmd --
*
* This command converts a byte array in an external encoding into a
* Tcl string
*
* Results:
* A standard Tcl result.
*
*----------------------------------------------------------------------
*/
int
EncodingConvertfromObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *data; /* Byte array to convert */
Tcl_DString ds; /* Buffer to hold the string */
Tcl_Encoding encoding; /* Encoding to use */
Tcl_Size length = 0; /* Length of the byte array being converted */
const char *bytesPtr; /* Pointer to the first byte of the array */
int flags;
int result;
Tcl_Obj *failVarObj;
Tcl_Size errorLocation;
if (EncodingConvertParseOptions(interp, objc, objv, &encoding, &data,
|
| ︙ | ︙ | |||
638 639 640 641 642 643 644 |
*----------------------------------------------------------------------
*/
int
EncodingConverttoObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 |
*----------------------------------------------------------------------
*/
int
EncodingConverttoObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *data; /* String to convert */
Tcl_DString ds; /* Buffer to hold the byte array */
Tcl_Encoding encoding; /* Encoding to use */
Tcl_Size length; /* Length of the string being converted */
const char *stringPtr; /* Pointer to the first byte of the string */
int result;
|
| ︙ | ︙ | |||
706 707 708 709 710 711 712 |
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
(unsigned char*) Tcl_DStringValue(&ds),
Tcl_DStringLength(&ds)));
result = TCL_OK;
| | > | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
(unsigned char*) Tcl_DStringValue(&ds),
Tcl_DStringLength(&ds)));
result = TCL_OK;
done:
Tcl_DStringFree(&ds);
if (encoding) {
Tcl_FreeEncoding(encoding);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* EncodingDirsObjCmd --
*
|
| ︙ | ︙ | |||
734 735 736 737 738 739 740 |
*----------------------------------------------------------------------
*/
int
EncodingDirsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 |
*----------------------------------------------------------------------
*/
int
EncodingDirsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *dirListObj;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?dirList?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
777 778 779 780 781 782 783 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingNamesObjCmd(
TCL_UNUSED(void *),
| | | | | 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingNamesObjCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Number of command line args */
Tcl_Obj* const objv[]) /* Vector of command line args */
{
if (objc > 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
Tcl_GetEncodingNames(interp);
return TCL_OK;
|
| ︙ | ︙ | |||
805 806 807 808 809 810 811 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingProfilesObjCmd(
TCL_UNUSED(void *),
| | | | | 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingProfilesObjCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Number of command line args */
Tcl_Obj* const objv[]) /* Vector of command line args */
{
if (objc > 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
TclGetEncodingProfiles(interp);
return TCL_OK;
|
| ︙ | ︙ | |||
836 837 838 839 840 841 842 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingSystemObjCmd(
TCL_UNUSED(void *),
| | | | | 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingSystemObjCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Number of command line args */
Tcl_Obj* const objv[]) /* Vector of command line args */
{
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?encoding?");
return TCL_ERROR;
}
if (objc == 1) {
Tcl_SetObjResult(interp,
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingUserObjCmd(
TCL_UNUSED(void *),
| | | | | | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 |
*
*-----------------------------------------------------------------------------
*/
int
EncodingUserObjCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Number of command line args */
Tcl_Obj* const objv[]) /* Vector of command line args */
{
if (objc > 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
Tcl_DString ds;
Tcl_GetEncodingNameForUser(&ds);
Tcl_DStringResult(interp, &ds);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_ErrorObjCmd --
*
* This procedure is invoked to process the "error" Tcl command. See the
* user documentation for details on what it does.
|
| ︙ | ︙ | |||
904 905 906 907 908 909 910 |
*----------------------------------------------------------------------
*/
int
Tcl_ErrorObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
*----------------------------------------------------------------------
*/
int
Tcl_ErrorObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *options, *optName;
if ((objc < 2) || (objc > 4)) {
Tcl_WrongNumArgs(interp, 1, objv, "message ?errorInfo? ?errorCode?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
966 967 968 969 970 971 972 |
return result;
}
int
Tcl_EvalObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 |
return result;
}
int
Tcl_EvalObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNREvalObjCmd, clientData, objc, objv);
}
int
TclNREvalObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *objPtr;
Interp *iPtr = (Interp *) interp;
CmdFrame *invoker = NULL;
int word = 0;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?");
return TCL_ERROR;
}
if (objc == 2) {
|
| ︙ | ︙ | |||
1035 1036 1037 1038 1039 1040 1041 |
*----------------------------------------------------------------------
*/
int
Tcl_ExitObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 |
*----------------------------------------------------------------------
*/
int
Tcl_ExitObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_WideInt value;
if ((objc != 1) && (objc != 2)) {
Tcl_WrongNumArgs(interp, 1, objv, "?returnCode?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1082 1083 1084 1085 1086 1087 1088 |
*----------------------------------------------------------------------
*/
int
Tcl_ExprObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
*----------------------------------------------------------------------
*/
int
Tcl_ExprObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRExprObjCmd, clientData, objc, objv);
}
int
TclNRExprObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *resultPtr, *objPtr;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "arg ?arg ...?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 |
Tcl_DecrRefCount(resultPtr);
return result;
}
/*
*----------------------------------------------------------------------
*
* FileAttrAccessTimeCmd --
*
* This function is invoked to process the "file atime" Tcl command. See
* the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* May update the access time on the file, if requested by the user.
*
*----------------------------------------------------------------------
*/
static int
FileAttrAccessTimeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
Tcl_DecrRefCount(resultPtr);
return result;
}
/*
*----------------------------------------------------------------------
*
* TclInitFileCmd --
*
* This function builds the "file" Tcl command ensemble. See the user
* documentation for details on what that ensemble does.
*
* PLEASE NOTE THAT THIS FAILS WITH FILENAMES AND PATHS WITH EMBEDDED
* NULLS. With the object-based Tcl_FS APIs, the above NOTE may no longer
* be true. In any case this assertion should be tested.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitFileCmd(
Tcl_Interp *interp)
{
/*
* Note that most subcommands are unsafe because either they manipulate
* the native filesystem or because they reveal information about the
* native filesystem.
*/
static const EnsembleImplMap initMap[] = {
{"atime", FileAttrAccessTimeCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 1},
{"attributes", TclFileAttrsCmd, NULL, NULL, NULL, 1},
{"channels", TclChannelNamesCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"copy", TclFileCopyCmd, NULL, NULL, NULL, 1},
{"delete", TclFileDeleteCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 1},
{"dirname", PathDirNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"executable", FileAttrIsExecutableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"exists", FileAttrIsExistingCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"extension", PathExtensionCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"home", TclFileHomeCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1},
{"isdirectory", FileAttrIsDirectoryCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"isfile", FileAttrIsFileCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"join", PathJoinCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0},
{"link", TclFileLinkCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 1},
{"lstat", FileAttrLinkStatCmd, TclCompileBasic2ArgCmd, NULL, NULL, 1},
{"mtime", FileAttrModifyTimeCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 1},
{"mkdir", TclFileMakeDirsCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 1},
{"nativename", PathNativeNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"normalize", PathNormalizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"owned", FileAttrIsOwnedCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"pathtype", PathTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"readable", FileAttrIsReadableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"readlink", TclFileReadLinkCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"rename", TclFileRenameCmd, NULL, NULL, NULL, 1},
{"rootname", PathRootNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"separator", FilesystemSeparatorCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"size", FileAttrSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"split", PathSplitCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"stat", FileAttrStatCmd, TclCompileBasic2ArgCmd, NULL, NULL, 1},
{"system", PathFilesystemCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"tail", PathTailCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"tempdir", TclFileTempDirCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1},
{"tempfile", TclFileTemporaryCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 1},
{"tildeexpand", TclFileTildeExpandCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"type", FileAttrTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{"volumes", FilesystemVolumesCmd, TclCompileBasic0ArgCmd, NULL, NULL, 1},
{"writable", FileAttrIsWritableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1},
{NULL, NULL, NULL, NULL, NULL, 0}
};
return TclMakeEnsemble(interp, "file", initMap);
}
/*
*----------------------------------------------------------------------
*
* FileAttrAccessTimeCmd --
*
* This function is invoked to process the "file atime" Tcl command. See
* the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* May update the access time on the file, if requested by the user.
*
*----------------------------------------------------------------------
*/
static int
FileAttrAccessTimeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
struct utimbuf tval;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?time?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1238 1239 1240 1241 1242 1243 1244 |
*----------------------------------------------------------------------
*/
static int
FileAttrModifyTimeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 |
*----------------------------------------------------------------------
*/
static int
FileAttrModifyTimeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
struct utimbuf tval;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?time?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1317 1318 1319 1320 1321 1322 1323 |
*----------------------------------------------------------------------
*/
static int
FileAttrLinkStatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 |
*----------------------------------------------------------------------
*/
static int
FileAttrLinkStatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?varName?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 |
*----------------------------------------------------------------------
*/
static int
FileAttrStatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 |
*----------------------------------------------------------------------
*/
static int
FileAttrStatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?varName?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 |
*----------------------------------------------------------------------
*/
static int
FileAttrTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 |
*----------------------------------------------------------------------
*/
static int
FileAttrTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1435 1436 1437 1438 1439 1440 1441 |
*----------------------------------------------------------------------
*/
static int
FileAttrSizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 |
*----------------------------------------------------------------------
*/
static int
FileAttrSizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1472 1473 1474 1475 1476 1477 1478 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsDirectoryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsDirectoryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
int value = 0;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1510 1511 1512 1513 1514 1515 1516 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsExecutableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsExecutableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
return CheckAccess(interp, objv[1], X_OK);
}
|
| ︙ | ︙ | |||
1541 1542 1543 1544 1545 1546 1547 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsExistingCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsExistingCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
return CheckAccess(interp, objv[1], F_OK);
}
|
| ︙ | ︙ | |||
1572 1573 1574 1575 1576 1577 1578 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsFileCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsFileCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_StatBuf buf;
int value = 0;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1610 1611 1612 1613 1614 1615 1616 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsOwnedCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsOwnedCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
#ifdef __CYGWIN__
#define geteuid() (short)(geteuid)()
#endif
#if !defined(_WIN32)
Tcl_StatBuf buf;
#endif
|
| ︙ | ︙ | |||
1672 1673 1674 1675 1676 1677 1678 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsReadableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsReadableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
return CheckAccess(interp, objv[1], R_OK);
}
|
| ︙ | ︙ | |||
1703 1704 1705 1706 1707 1708 1709 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsWritableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 |
*----------------------------------------------------------------------
*/
static int
FileAttrIsWritableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
return CheckAccess(interp, objv[1], W_OK);
}
|
| ︙ | ︙ | |||
1734 1735 1736 1737 1738 1739 1740 |
*----------------------------------------------------------------------
*/
static int
PathDirNameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 |
*----------------------------------------------------------------------
*/
static int
PathDirNameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *dirPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1773 1774 1775 1776 1777 1778 1779 |
*----------------------------------------------------------------------
*/
static int
PathExtensionCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 |
*----------------------------------------------------------------------
*/
static int
PathExtensionCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *dirPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1812 1813 1814 1815 1816 1817 1818 |
*----------------------------------------------------------------------
*/
static int
PathRootNameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 |
*----------------------------------------------------------------------
*/
static int
PathRootNameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *dirPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1851 1852 1853 1854 1855 1856 1857 |
*----------------------------------------------------------------------
*/
static int
PathTailCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 |
*----------------------------------------------------------------------
*/
static int
PathTailCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *dirPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1890 1891 1892 1893 1894 1895 1896 |
*----------------------------------------------------------------------
*/
static int
PathFilesystemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 |
*----------------------------------------------------------------------
*/
static int
PathFilesystemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *fsInfo;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1931 1932 1933 1934 1935 1936 1937 |
*----------------------------------------------------------------------
*/
static int
PathJoinCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 |
*----------------------------------------------------------------------
*/
static int
PathJoinCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?name ...?");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, TclJoinPath(objc - 1, objv + 1, 0));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* PathNativeNameCmd --
|
| ︙ | ︙ | |||
1963 1964 1965 1966 1967 1968 1969 |
*----------------------------------------------------------------------
*/
static int
PathNativeNameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 |
*----------------------------------------------------------------------
*/
static int
PathNativeNameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_DString ds;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2000 2001 2002 2003 2004 2005 2006 |
*----------------------------------------------------------------------
*/
static int
PathNormalizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 |
*----------------------------------------------------------------------
*/
static int
PathNormalizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *fileName;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2038 2039 2040 2041 2042 2043 2044 |
*----------------------------------------------------------------------
*/
static int
PathSplitCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 |
*----------------------------------------------------------------------
*/
static int
PathSplitCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *res;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2081 2082 2083 2084 2085 2086 2087 |
*----------------------------------------------------------------------
*/
static int
PathTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 |
*----------------------------------------------------------------------
*/
static int
PathTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *typeName;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 |
*----------------------------------------------------------------------
*/
static int
FilesystemSeparatorCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 |
*----------------------------------------------------------------------
*/
static int
FilesystemSeparatorCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc < 1 || objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?name?");
return TCL_ERROR;
}
if (objc == 1) {
const char *separator = NULL;
|
| ︙ | ︙ | |||
2183 2184 2185 2186 2187 2188 2189 |
*----------------------------------------------------------------------
*/
static int
FilesystemVolumesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 |
*----------------------------------------------------------------------
*/
static int
FilesystemVolumesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_FSListVolumes());
return TCL_OK;
|
| ︙ | ︙ | |||
2321 2322 2323 2324 2325 2326 2327 |
Tcl_Interp *interp, /* Interpreter for error reports. */
Tcl_Obj *varName, /* Name of associative array variable in which
* to store stat results. */
Tcl_StatBuf *statPtr) /* Pointer to buffer containing stat data to
* store in varName. */
{
Tcl_Obj *field, *value, *result;
| | > | > > | | | | | | | | | | | > | | | < | | | | < | | | | < | | | | | | | | | > | | > | | | 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 |
Tcl_Interp *interp, /* Interpreter for error reports. */
Tcl_Obj *varName, /* Name of associative array variable in which
* to store stat results. */
Tcl_StatBuf *statPtr) /* Pointer to buffer containing stat data to
* store in varName. */
{
Tcl_Obj *field, *value, *result;
unsigned short mode;
if (varName == NULL) {
TclNewObj(result);
Tcl_IncrRefCount(result);
#define DOBJPUT(key, objValue) \
Tcl_DictObjPut(NULL, result, \
Tcl_NewStringObj((key), -1), \
(objValue));
DOBJPUT("dev", Tcl_NewWideIntObj((long)statPtr->st_dev));
DOBJPUT("ino", Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_ino));
DOBJPUT("nlink", Tcl_NewWideIntObj((long)statPtr->st_nlink));
DOBJPUT("uid", Tcl_NewWideIntObj((long)statPtr->st_uid));
DOBJPUT("gid", Tcl_NewWideIntObj((long)statPtr->st_gid));
DOBJPUT("size", Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_size));
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
DOBJPUT("blocks", Tcl_NewWideIntObj((Tcl_WideInt)statPtr->st_blocks));
#endif
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
DOBJPUT("blksize", Tcl_NewWideIntObj((long)statPtr->st_blksize));
#endif
DOBJPUT("atime", Tcl_NewWideIntObj(Tcl_GetAccessTimeFromStat(statPtr)));
DOBJPUT("mtime", Tcl_NewWideIntObj(Tcl_GetModificationTimeFromStat(statPtr)));
DOBJPUT("ctime", Tcl_NewWideIntObj(Tcl_GetChangeTimeFromStat(statPtr)));
mode = (unsigned short) statPtr->st_mode;
DOBJPUT("mode", Tcl_NewWideIntObj(mode));
DOBJPUT("type", Tcl_NewStringObj(GetTypeFromMode(mode), -1));
#undef DOBJPUT
Tcl_SetObjResult(interp, result);
Tcl_DecrRefCount(result);
return TCL_OK;
}
/*
* Might be a better idea to call Tcl_SetVar2Ex() instead, except we want
* to have an object (i.e. possibly cached) array variable name but a
* string element name, so no API exists. Messy.
*/
#define STORE_ARY(fieldName, object) \
TclNewLiteralStringObj(field, fieldName); \
Tcl_IncrRefCount(field); \
value = (object); \
if (Tcl_ObjSetVar2(interp,varName,field,value,TCL_LEAVE_ERR_MSG)==NULL) { \
TclDecrRefCount(field); \
return TCL_ERROR; \
} \
TclDecrRefCount(field);
/*
* Watch out porters; the inode is meant to be an *unsigned* value, so the
* cast might fail when there isn't a real arithmetic 'long long' type...
*/
STORE_ARY("dev", Tcl_NewWideIntObj((long)statPtr->st_dev));
STORE_ARY("ino", Tcl_NewWideIntObj(statPtr->st_ino));
STORE_ARY("nlink", Tcl_NewWideIntObj((long)statPtr->st_nlink));
STORE_ARY("uid", Tcl_NewWideIntObj((long)statPtr->st_uid));
STORE_ARY("gid", Tcl_NewWideIntObj((long)statPtr->st_gid));
STORE_ARY("size", Tcl_NewWideIntObj(statPtr->st_size));
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
STORE_ARY("blocks", Tcl_NewWideIntObj(statPtr->st_blocks));
#endif
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
STORE_ARY("blksize", Tcl_NewWideIntObj((long)statPtr->st_blksize));
#endif
#ifdef HAVE_STRUCT_STAT_ST_RDEV
if (S_ISCHR(statPtr->st_mode) || S_ISBLK(statPtr->st_mode)) {
STORE_ARY("rdev", Tcl_NewWideIntObj((long) statPtr->st_rdev));
}
#endif
STORE_ARY("atime", Tcl_NewWideIntObj(Tcl_GetAccessTimeFromStat(statPtr)));
STORE_ARY("mtime", Tcl_NewWideIntObj(
Tcl_GetModificationTimeFromStat(statPtr)));
STORE_ARY("ctime", Tcl_NewWideIntObj(Tcl_GetChangeTimeFromStat(statPtr)));
mode = (unsigned short) statPtr->st_mode;
STORE_ARY("mode", Tcl_NewWideIntObj(mode));
STORE_ARY("type", Tcl_NewStringObj(GetTypeFromMode(mode), -1));
#undef STORE_ARY
return TCL_OK;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 |
*----------------------------------------------------------------------
*/
int
Tcl_ForObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 |
*----------------------------------------------------------------------
*/
int
Tcl_ForObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRForObjCmd, clientData, objc, objv);
}
int
TclNRForObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
ForIterData *iterPtr;
if (objc != 5) {
Tcl_WrongNumArgs(interp, 1, objv, "start test next command");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2564 2565 2566 2567 2568 2569 2570 | * We need to reset the result before evaluating the expression. * Otherwise, any error message will be appended to the result of the * last evaluation. */ Tcl_ResetResult(interp); TclNewObj(boolObj); | | | | 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 |
* We need to reset the result before evaluating the expression.
* Otherwise, any error message will be appended to the result of the
* last evaluation.
*/
Tcl_ResetResult(interp);
TclNewObj(boolObj);
TclNRAddCallback(interp, ForCondCallback, iterPtr, boolObj, NULL,
NULL);
return Tcl_NRExprObj(interp, iterPtr->cond, boolObj);
case TCL_BREAK:
result = TCL_OK;
Tcl_ResetResult(interp);
break;
case TCL_ERROR:
Tcl_AppendObjToErrorInfo(interp,
|
| ︙ | ︙ | |||
2604 2605 2606 2607 2608 2609 2610 |
return TCL_ERROR;
}
Tcl_DecrRefCount(boolObj);
if (value) {
/* TIP #280. */
if (iterPtr->next) {
| | | | | | | | 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 |
return TCL_ERROR;
}
Tcl_DecrRefCount(boolObj);
if (value) {
/* TIP #280. */
if (iterPtr->next) {
TclNRAddCallback(interp, ForNextCallback, iterPtr, NULL, NULL,
NULL);
} else {
TclNRAddCallback(interp, TclNRForIterCallback, iterPtr, NULL,
NULL, NULL);
}
return TclNREvalObjEx(interp, iterPtr->body, 0, iPtr->cmdFramePtr,
iterPtr->word);
}
TclSmallFreeEx(interp, iterPtr);
return result;
}
static int
ForNextCallback(
void *data[],
Tcl_Interp *interp,
int result)
{
Interp *iPtr = (Interp *) interp;
ForIterData *iterPtr = (ForIterData *)data[0];
Tcl_Obj *next = iterPtr->next;
if ((result == TCL_OK) || (result == TCL_CONTINUE)) {
TclNRAddCallback(interp, ForPostNextCallback, iterPtr, NULL, NULL,
NULL);
/*
* TIP #280. Make invoking context available to next script.
*/
return TclNREvalObjEx(interp, next, 0, iPtr->cmdFramePtr, 3);
}
|
| ︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 |
*----------------------------------------------------------------------
*/
int
Tcl_ForeachObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < | | | | 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 |
*----------------------------------------------------------------------
*/
int
Tcl_ForeachObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRForeachCmd, clientData, objc, objv);
}
int
TclNRForeachCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
return EachloopCmd(interp, TCL_EACH_KEEP_NONE, objc, objv);
}
int
Tcl_LmapObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRLmapCmd, clientData, objc, objv);
}
int
TclNRLmapCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
return EachloopCmd(interp, TCL_EACH_COLLECT, objc, objv);
}
static int
EachloopCmd(
Tcl_Interp *interp, /* Our context for variables and script
* evaluation. */
int collect, /* Select collecting or accumulating mode
* (TCL_EACH_*) */
int objc, /* The arguments being passed in... */
Tcl_Obj *const objv[])
{
int numLists = (objc-2) / 2;
struct ForeachState *statePtr;
int i, result;
Tcl_Size j;
if (objc < 4 || (objc%2 != 0)) {
Tcl_WrongNumArgs(interp, 1, objv,
"varList list ?varList list ...? command");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2784 2785 2786 2787 2788 2789 2790 |
* statePtr->argvList[i].
*
* The setting up of all of these pointers is moderately messy, but allows
* the rest of this code to be simple and for us to use a single memory
* allocation for better performance.
*/
| | | | < < | | | > | | | | | 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 |
* statePtr->argvList[i].
*
* The setting up of all of these pointers is moderately messy, but allows
* the rest of this code to be simple and for us to use a single memory
* allocation for better performance.
*/
statePtr = (struct ForeachState *)TclStackAlloc(interp,
sizeof(struct ForeachState) + 3 * numLists * sizeof(Tcl_Size)
+ 2 * numLists * (sizeof(Tcl_Obj **) + sizeof(Tcl_Obj *)));
memset(statePtr, 0,
sizeof(struct ForeachState) + 3 * numLists * sizeof(Tcl_Size)
+ 2 * numLists * (sizeof(Tcl_Obj **) + sizeof(Tcl_Obj *)));
statePtr->varvList = (Tcl_Obj ***) (statePtr + 1);
statePtr->argvList = statePtr->varvList + numLists;
statePtr->vCopyList = (Tcl_Obj **) (statePtr->argvList + numLists);
statePtr->aCopyList = statePtr->vCopyList + numLists;
statePtr->index = (Tcl_Size *) (statePtr->aCopyList + numLists);
statePtr->varcList = statePtr->index + numLists;
statePtr->argcList = statePtr->varcList + numLists;
statePtr->numLists = numLists;
statePtr->bodyPtr = objv[objc - 1];
statePtr->bodyIdx = objc - 1;
if (collect == TCL_EACH_COLLECT) {
statePtr->resultList = Tcl_NewListObj(0, NULL);
} else {
statePtr->resultList = NULL;
}
/*
* Break up the value lists and variable lists into elements.
*/
for (i=0 ; i<numLists ; i++) {
/* List */
/* Variables */
statePtr->vCopyList[i] = TclListObjCopy(interp, objv[1+i*2]);
if (statePtr->vCopyList[i] == NULL) {
result = TCL_ERROR;
goto done;
}
result = TclListObjLength(interp, statePtr->vCopyList[i],
&statePtr->varcList[i]);
if (result != TCL_OK) {
result = TCL_ERROR;
goto done;
}
if (statePtr->varcList[i] < 1) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s varlist is empty",
(statePtr->resultList != NULL ? "lmap" : "foreach")));
Tcl_SetErrorCode(interp, "TCL", "OPERATION",
(statePtr->resultList != NULL ? "LMAP" : "FOREACH"),
"NEEDVARS", (char *)NULL);
result = TCL_ERROR;
goto done;
}
TclListObjGetElements(NULL, statePtr->vCopyList[i],
&statePtr->varcList[i], &statePtr->varvList[i]);
/* Values */
if (TclObjTypeHasProc(objv[2+i*2],indexProc)) {
/* Special case for AbstractList */
statePtr->aCopyList[i] = Tcl_DuplicateObj(objv[2+i*2]);
if (statePtr->aCopyList[i] == NULL) {
result = TCL_ERROR;
goto done;
}
/* Don't compute values here, wait until the last moment */
statePtr->argcList[i] = TclObjTypeLength(statePtr->aCopyList[i]);
} else {
/* List values */
statePtr->aCopyList[i] = TclListObjCopy(interp, objv[2+i*2]);
if (statePtr->aCopyList[i] == NULL) {
result = TCL_ERROR;
goto done;
}
result = TclListObjGetElements(interp, statePtr->aCopyList[i],
&statePtr->argcList[i], &statePtr->argvList[i]);
if (result != TCL_OK) {
goto done;
}
}
/* account for variable <> value mismatch */
j = statePtr->argcList[i] / statePtr->varcList[i];
if ((statePtr->argcList[i] % statePtr->varcList[i]) != 0) {
|
| ︙ | ︙ | |||
2901 2902 2903 2904 2905 2906 2907 |
result = TCL_OK;
done:
ForeachCleanup(interp, statePtr);
return result;
}
/*
| < < < < | < < | < < < < < < < | < < < | | < < | | | > > | | 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 |
result = TCL_OK;
done:
ForeachCleanup(interp, statePtr);
return result;
}
/*
* Post-body processing handler.
*/
static int
ForeachLoopStep(
void *data[],
Tcl_Interp *interp,
int result)
{
struct ForeachState *statePtr = (struct ForeachState *)data[0];
/*
* Process the result code from this run of the [foreach] body. Note that
* this switch uses fallthroughs in several places. Maintainer aware!
*/
switch (result) {
case TCL_CONTINUE:
result = TCL_OK;
break;
case TCL_OK:
if (statePtr->resultList != NULL) {
result = Tcl_ListObjAppendElement(
interp, statePtr->resultList, Tcl_GetObjResult(interp));
if (result != TCL_OK) {
/* e.g. memory alloc failure on big data tests */
goto done;
}
}
break;
case TCL_BREAK:
result = TCL_OK;
goto finish;
case TCL_ERROR:
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (\"%s\" body line %d)",
(statePtr->resultList != NULL ? "lmap" : "foreach"),
Tcl_GetErrorLine(interp)));
TCL_FALLTHROUGH();
default:
goto done;
}
/*
* Test if there is work still to be done. If so, do the next round of
|
| ︙ | ︙ | |||
2981 2982 2983 2984 2985 2986 2987 |
}
/*
* We're done. Tidy up our work space and finish off.
*/
finish:
| | < < | | < | < < | | < | < < < < < < < < < | < < < < | | | < | < < < | | 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 |
}
/*
* We're done. Tidy up our work space and finish off.
*/
finish:
if (statePtr->resultList == NULL) {
Tcl_ResetResult(interp);
} else {
Tcl_SetObjResult(interp, statePtr->resultList);
statePtr->resultList = NULL; /* Don't clean it up */
}
done:
ForeachCleanup(interp, statePtr);
return result;
}
/*
* Factored out code to do the assignments in [foreach].
*/
static inline int
ForeachAssignments(
Tcl_Interp *interp,
struct ForeachState *statePtr)
{
int i;
Tcl_Size v, k;
Tcl_Obj *valuePtr, *varValuePtr;
for (i=0 ; i<statePtr->numLists ; i++) {
int isAbstractList =
TclObjTypeHasProc(statePtr->aCopyList[i],indexProc) != NULL;
for (v=0 ; v<statePtr->varcList[i] ; v++) {
k = statePtr->index[i]++;
if (k < statePtr->argcList[i]) {
if (isAbstractList) {
if (TclObjTypeIndex(interp, statePtr->aCopyList[i], k, &valuePtr) != TCL_OK) {
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (setting %s loop variable \"%s\")",
(statePtr->resultList != NULL ? "lmap" : "foreach"),
TclGetString(statePtr->varvList[i][v])));
return TCL_ERROR;
}
} else {
valuePtr = statePtr->argvList[i][k];
}
} else {
TclNewObj(valuePtr); /* Empty string */
}
varValuePtr = Tcl_ObjSetVar2(interp, statePtr->varvList[i][v],
NULL, valuePtr, TCL_LEAVE_ERR_MSG);
if (varValuePtr == NULL) {
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (setting %s loop variable \"%s\")",
(statePtr->resultList != NULL ? "lmap" : "foreach"),
TclGetString(statePtr->varvList[i][v])));
return TCL_ERROR;
}
}
}
return TCL_OK;
}
/*
* Factored out code for cleaning up the state of the foreach.
*/
static inline void
ForeachCleanup(
Tcl_Interp *interp,
struct ForeachState *statePtr)
{
int i;
for (i=0 ; i<statePtr->numLists ; i++) {
if (statePtr->vCopyList[i]) {
TclDecrRefCount(statePtr->vCopyList[i]);
}
if (statePtr->aCopyList[i]) {
TclDecrRefCount(statePtr->aCopyList[i]);
}
}
if (statePtr->resultList != NULL) {
TclDecrRefCount(statePtr->resultList);
}
TclStackFree(interp, statePtr);
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
3113 3114 3115 3116 3117 3118 3119 |
*----------------------------------------------------------------------
*/
int
Tcl_FormatObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 |
*----------------------------------------------------------------------
*/
int
Tcl_FormatObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *resultPtr; /* Where result is stored finally. */
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "formatString ?arg ...?");
return TCL_ERROR;
}
|
| ︙ | ︙ |
Changes to generic/tclCmdIL.c.
| ︙ | ︙ | |||
71 72 73 74 75 76 77 |
* that option.
* NULL if no indexes supplied, and points to
* singleIndex field when only one
* supplied. */
Tcl_Size indexc; /* Number of indexes in indexv array. */
int singleIndex; /* Static space for common index case. */
int unique;
| | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
* that option.
* NULL if no indexes supplied, and points to
* singleIndex field when only one
* supplied. */
Tcl_Size indexc; /* Number of indexes in indexv array. */
int singleIndex; /* Static space for common index case. */
int unique;
int numElements;
Tcl_Interp *interp; /* The interpreter in which the sort is being
* done. */
int resultCode; /* Completion code for the lsort command. If
* an error occurs during the sort this is
* changed from TCL_OK to TCL_ERROR. */
} SortInfo;
/*
* The "sortMode" field of the SortInfo structure can take on any of the
* following values.
*/
#define SORTMODE_ASCII 0
#define SORTMODE_INTEGER 1
#define SORTMODE_REAL 2
#define SORTMODE_COMMAND 3
#define SORTMODE_DICTIONARY 4
#define SORTMODE_ASCII_NC 8
/*
* Definitions for [lseq] command
*/
static const char *const seq_operations[] = {
"..", "to", "count", "by", NULL
};
typedef enum {
LSEQ_DOTS, LSEQ_TO, LSEQ_COUNT, LSEQ_BY
} SequenceOperators;
typedef enum {
NoneArg, NumericArg, RangeKeywordArg, ErrArg, LastArg = 8
} SequenceDecoded;
/*
* Forward declarations for procedures defined in this file:
*/
static int DictionaryCompare(const char *left, const char *right);
static Tcl_NRPostProc IfConditionCallback;
static Tcl_ObjCmdProc InfoArgsCmd;
static Tcl_ObjCmdProc InfoBodyCmd;
static Tcl_ObjCmdProc InfoCmdCountCmd;
static Tcl_ObjCmdProc InfoCommandsCmd;
static Tcl_ObjCmdProc InfoCompleteCmd;
static Tcl_ObjCmdProc InfoDefaultCmd;
/* TIP #348 - New 'info' subcommand 'errorstack' */
static Tcl_ObjCmdProc InfoErrorStackCmd;
/* TIP #280 - New 'info' subcommand 'frame' */
static Tcl_ObjCmdProc InfoFrameCmd;
static Tcl_ObjCmdProc InfoFunctionsCmd;
static Tcl_ObjCmdProc InfoHostnameCmd;
static Tcl_ObjCmdProc InfoLevelCmd;
static Tcl_ObjCmdProc InfoLibraryCmd;
static Tcl_ObjCmdProc InfoLoadedCmd;
static Tcl_ObjCmdProc InfoNameOfExecutableCmd;
static Tcl_ObjCmdProc InfoPatchLevelCmd;
static Tcl_ObjCmdProc InfoProcsCmd;
static Tcl_ObjCmdProc InfoScriptCmd;
static Tcl_ObjCmdProc InfoSharedlibCmd;
static Tcl_ObjCmdProc InfoCmdTypeCmd;
static Tcl_ObjCmdProc InfoTclVersionCmd;
static SortElement * MergeLists(SortElement *leftPtr, SortElement *rightPtr,
SortInfo *infoPtr);
static int SortCompare(SortElement *firstPtr, SortElement *second,
SortInfo *infoPtr);
static Tcl_Obj * SelectObjFromSublist(Tcl_Obj *firstPtr,
SortInfo *infoPtr);
/*
* Array of values describing how to implement each standard subcommand of the
* "info" command.
*/
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},
{"constant", TclInfoConstantCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
|
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
*----------------------------------------------------------------------
*/
int
Tcl_IfObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | | < | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
*----------------------------------------------------------------------
*/
int
Tcl_IfObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRIfObjCmd, clientData, objc, objv);
}
int
TclNRIfObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *boolObj;
if (objc <= 1) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"wrong # args: no expression after \"%s\" argument",
TclGetString(objv[0])));
Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", (char *)NULL);
return TCL_ERROR;
}
/*
* At this point, objv[1] refers to the main expression to test. The
* arguments after the expression must be "then" (optional) and a script
* to execute if the expression is true.
*/
TclNewObj(boolObj);
Tcl_NRAddCallback(interp, IfConditionCallback, INT2PTR(objc),
(void *) objv, INT2PTR(1), boolObj);
return Tcl_NRExprObj(interp, objv[1], boolObj);
}
static int
IfConditionCallback(
void *data[],
Tcl_Interp *interp,
int result)
{
Interp *iPtr = (Interp *) interp;
int objc = PTR2INT(data[0]);
Tcl_Obj *const *objv = (Tcl_Obj *const *)data[1];
int i = PTR2INT(data[2]);
Tcl_Obj *boolObj = (Tcl_Obj *)data[3];
int value, thenScriptIndex = 0;
const char *clause;
if (result != TCL_OK) {
TclDecrRefCount(boolObj);
return result;
}
if (Tcl_GetBooleanFromObj(interp, boolObj, &value) != TCL_OK) {
|
| ︙ | ︙ | |||
317 318 319 320 321 322 323 |
"wrong # args: no expression after \"%s\" argument",
clause));
Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", (char *)NULL);
return TCL_ERROR;
}
if (!thenScriptIndex) {
TclNewObj(boolObj);
| | | | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
"wrong # args: no expression after \"%s\" argument",
clause));
Tcl_SetErrorCode(interp, "TCL", "WRONGARGS", (char *)NULL);
return TCL_ERROR;
}
if (!thenScriptIndex) {
TclNewObj(boolObj);
Tcl_NRAddCallback(interp, IfConditionCallback, data[0], data[1],
INT2PTR(i), boolObj);
return Tcl_NRExprObj(interp, objv[i], boolObj);
}
}
/*
* Couldn't find a "then" or "elseif" clause to execute. Check now for an
* "else" clause. We know that there's at least one more argument when we
|
| ︙ | ︙ | |||
385 386 387 388 389 390 391 |
*----------------------------------------------------------------------
*/
int
Tcl_IncrObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
*----------------------------------------------------------------------
*/
int
Tcl_IncrObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *newValuePtr, *incrPtr;
if ((objc != 2) && (objc != 3)) {
Tcl_WrongNumArgs(interp, 1, objv, "varName ?increment?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
Tcl_SetObjResult(interp, newValuePtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* InfoArgsCmd --
*
* Called to implement the "info args" command that returns the argument
* list for a procedure. Handles the following syntax:
*
* info args procName
*
| > > > > > > > > > > > > > > > > > > > > > > > > | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
Tcl_SetObjResult(interp, newValuePtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclInitInfoCmd --
*
* This function is called to create the "info" Tcl command. See the user
* documentation for details on what it does.
*
* Results:
* Handle for the info command, or NULL on failure.
*
* Side effects:
* none
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitInfoCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
return TclMakeEnsemble(interp, "info", defaultInfoMap);
}
/*
*----------------------------------------------------------------------
*
* InfoArgsCmd --
*
* Called to implement the "info args" command that returns the argument
* list for a procedure. Handles the following syntax:
*
* info args procName
*
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 |
*----------------------------------------------------------------------
*/
static int
InfoArgsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
*----------------------------------------------------------------------
*/
static int
InfoArgsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
const char *name;
Proc *procPtr;
CompiledLocal *localPtr;
Tcl_Obj *listObjPtr;
|
| ︙ | ︙ | |||
505 506 507 508 509 510 511 |
*----------------------------------------------------------------------
*/
static int
InfoBodyCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
*----------------------------------------------------------------------
*/
static int
InfoBodyCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
const char *name, *bytes;
Proc *procPtr;
Tcl_Size numBytes;
if (objc != 2) {
|
| ︙ | ︙ | |||
566 567 568 569 570 571 572 |
*----------------------------------------------------------------------
*/
static int
InfoCmdCountCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
*----------------------------------------------------------------------
*/
static int
InfoCmdCountCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
608 609 610 611 612 613 614 |
*----------------------------------------------------------------------
*/
static int
InfoCommandsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 |
*----------------------------------------------------------------------
*/
static int
InfoCommandsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *cmdName, *pattern;
const char *simplePattern;
Tcl_HashEntry *entryPtr;
Tcl_HashSearch search;
Namespace *nsPtr;
Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp);
|
| ︙ | ︙ | |||
791 792 793 794 795 796 797 |
while (entryPtr != NULL) {
cmdName = (const char *)Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr);
if ((simplePattern == NULL)
|| Tcl_StringMatch(cmdName, simplePattern)) {
elemObjPtr = Tcl_NewStringObj(cmdName, -1);
Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
(void) Tcl_CreateHashEntry(&addedCommandsTable,
| | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
while (entryPtr != NULL) {
cmdName = (const char *)Tcl_GetHashKey(&nsPtr->cmdTable, entryPtr);
if ((simplePattern == NULL)
|| Tcl_StringMatch(cmdName, simplePattern)) {
elemObjPtr = Tcl_NewStringObj(cmdName, -1);
Tcl_ListObjAppendElement(interp, listPtr, elemObjPtr);
(void) Tcl_CreateHashEntry(&addedCommandsTable,
elemObjPtr, &isNew);
}
entryPtr = Tcl_NextHashEntry(&search);
}
/*
* Search the path next.
*/
|
| ︙ | ︙ | |||
885 886 887 888 889 890 891 |
*----------------------------------------------------------------------
*/
static int
InfoCompleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 |
*----------------------------------------------------------------------
*/
static int
InfoCompleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "command");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
|
| ︙ | ︙ | |||
922 923 924 925 926 927 928 |
*----------------------------------------------------------------------
*/
static int
InfoDefaultCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 |
*----------------------------------------------------------------------
*/
static int
InfoDefaultCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
const char *procName, *argName;
Proc *procPtr;
CompiledLocal *localPtr;
Tcl_Obj *valueObjPtr;
|
| ︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 |
*----------------------------------------------------------------------
*/
static int
InfoErrorStackCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 |
*----------------------------------------------------------------------
*/
static int
InfoErrorStackCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Interp *target;
Interp *iPtr;
if ((objc != 1) && (objc != 2)) {
Tcl_WrongNumArgs(interp, 1, objv, "?interp?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1054 1055 1056 1057 1058 1059 1060 |
*----------------------------------------------------------------------
*/
int
TclInfoExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 |
*----------------------------------------------------------------------
*/
int
TclInfoExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *varName;
Var *varPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "varName");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1077 1078 1079 1080 1081 1082 1083 |
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* InfoFrameCmd --
| < | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 |
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* InfoFrameCmd --
* TIP #280
*
* Called to implement the "info frame" command that returns the location
* of either the currently executing command, or its caller. Handles the
* following syntax:
*
* info frame ?number?
|
| ︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 |
*----------------------------------------------------------------------
*/
static int
InfoFrameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 |
*----------------------------------------------------------------------
*/
static int
InfoFrameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
int level, code = TCL_OK;
CmdFrame *framePtr, **cmdFramePtrPtr = &iPtr->cmdFramePtr;
CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
int topLevel = 0;
|
| ︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 |
Tcl_Obj *
TclInfoFrame(
Tcl_Interp *interp, /* Current interpreter. */
CmdFrame *framePtr) /* Frame to get info for. */
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *tmpObj;
| | | 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 |
Tcl_Obj *
TclInfoFrame(
Tcl_Interp *interp, /* Current interpreter. */
CmdFrame *framePtr) /* Frame to get info for. */
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *tmpObj;
Tcl_Obj *lv[20] = {NULL}; /* Keep uptodate when more keys are added to
* the dict. */
int lc = 0;
/*
* This array is indexed by the TCL_LOCATION_... values, except
* for _LAST.
*/
static const char *const typeString[TCL_LOCATION_LAST] = {
|
| ︙ | ︙ | |||
1278 1279 1280 1281 1282 1283 1284 |
} else {
ADD_PAIR("line", Tcl_NewWideIntObj(1));
}
ADD_PAIR("cmd", TclGetSourceFromFrame(framePtr, 0, NULL));
break;
case TCL_LOCATION_PREBC:
| | | 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 |
} else {
ADD_PAIR("line", Tcl_NewWideIntObj(1));
}
ADD_PAIR("cmd", TclGetSourceFromFrame(framePtr, 0, NULL));
break;
case TCL_LOCATION_PREBC:
precompiled:
/*
* Precompiled. Result contains the type as signal, nothing else.
*/
ADD_PAIR("type", Tcl_NewStringObj(typeString[TCL_LOCATION_PREBC], -1));
break;
case TCL_LOCATION_BC: {
|
| ︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 |
}
/*
* 'proc'. Common to all frame types. Conditional on having an associated
* Procedure CallFrame.
*/
| | > | | > > > > | | | 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 |
}
/*
* 'proc'. Common to all frame types. Conditional on having an associated
* Procedure CallFrame.
*/
if (procPtr != NULL && procPtr->cmdPtr) {
Command *cmdPtr = procPtr->cmdPtr;
Tcl_HashEntry *namePtr = cmdPtr->hPtr;
if (namePtr) {
Tcl_Obj *procNameObj;
/*
* This is a regular command.
*/
TclNewObj(procNameObj);
Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr,
procNameObj);
ADD_PAIR("proc", procNameObj);
} else if ((procPtr->flags && PROC_CMD_OWNED) && !cmdPtr->objProc &&
cmdPtr->objClientData
) {
ADD_PAIR("lambda", (Tcl_Obj *)cmdPtr->objClientData);
} else if (cmdPtr->clientData) {
ExtraFrameInfo *efiPtr = (ExtraFrameInfo *)cmdPtr->clientData;
Tcl_Size i;
/*
* This is a non-standard command. Luckily, it's told us how to
* render extra information about its frame.
*/
|
| ︙ | ︙ | |||
1404 1405 1406 1407 1408 1409 1410 |
if (framePtr && (framePtr->framePtr != NULL) && (iPtr->varFramePtr != NULL)) {
CallFrame *current = framePtr->framePtr;
CallFrame *top = iPtr->varFramePtr;
CallFrame *idx;
for (idx=top ; idx!=NULL ; idx=idx->callerVarPtr) {
if (idx == current) {
| | | | 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 |
if (framePtr && (framePtr->framePtr != NULL) && (iPtr->varFramePtr != NULL)) {
CallFrame *current = framePtr->framePtr;
CallFrame *top = iPtr->varFramePtr;
CallFrame *idx;
for (idx=top ; idx!=NULL ; idx=idx->callerVarPtr) {
if (idx == current) {
int c = framePtr->framePtr->level;
int t = iPtr->varFramePtr->level;
ADD_PAIR("level", Tcl_NewWideIntObj(t - c));
break;
}
}
}
|
| ︙ | ︙ | |||
1445 1446 1447 1448 1449 1450 1451 |
*----------------------------------------------------------------------
*/
static int
InfoFunctionsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 |
*----------------------------------------------------------------------
*/
static int
InfoFunctionsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *script;
int code;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?pattern?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1510 1511 1512 1513 1514 1515 1516 |
*----------------------------------------------------------------------
*/
static int
InfoHostnameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 |
*----------------------------------------------------------------------
*/
static int
InfoHostnameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *name;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1556 1557 1558 1559 1560 1561 1562 |
*----------------------------------------------------------------------
*/
static int
InfoLevelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 |
*----------------------------------------------------------------------
*/
static int
InfoLevelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
if (objc == 1) { /* Just "info level" */
Tcl_SetObjResult(interp, Tcl_NewWideIntObj((int)iPtr->varFramePtr->level));
return TCL_OK;
}
if (objc == 2) {
int level;
CallFrame *framePtr, *rootFramePtr = iPtr->rootFramePtr;
if (TclGetIntFromObj(interp, objv[1], &level) != TCL_OK) {
return TCL_ERROR;
}
if (level <= 0) {
if (iPtr->varFramePtr == rootFramePtr) {
goto levelError;
}
level += iPtr->varFramePtr->level;
}
for (framePtr=iPtr->varFramePtr ; framePtr!=rootFramePtr;
framePtr=framePtr->callerVarPtr) {
if ((int)framePtr->level == level) {
break;
}
}
if (framePtr == rootFramePtr) {
goto levelError;
}
|
| ︙ | ︙ | |||
1630 1631 1632 1633 1634 1635 1636 |
*----------------------------------------------------------------------
*/
static int
InfoLibraryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 |
*----------------------------------------------------------------------
*/
static int
InfoLibraryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *libDirName;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1677 1678 1679 1680 1681 1682 1683 |
*----------------------------------------------------------------------
*/
static int
InfoLoadedCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 |
*----------------------------------------------------------------------
*/
static int
InfoLoadedCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *interpName, *prefix;
if (objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?interp? ?prefix?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1725 1726 1727 1728 1729 1730 1731 |
*----------------------------------------------------------------------
*/
static int
InfoNameOfExecutableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 |
*----------------------------------------------------------------------
*/
static int
InfoNameOfExecutableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, TclGetObjNameOfExecutable());
return TCL_OK;
|
| ︙ | ︙ | |||
1761 1762 1763 1764 1765 1766 1767 |
*----------------------------------------------------------------------
*/
static int
InfoPatchLevelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 |
*----------------------------------------------------------------------
*/
static int
InfoPatchLevelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *patchlevel;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1808 1809 1810 1811 1812 1813 1814 |
*----------------------------------------------------------------------
*/
static int
InfoProcsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 |
*----------------------------------------------------------------------
*/
static int
InfoProcsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *cmdName, *pattern;
const char *simplePattern;
Namespace *nsPtr;
Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
Tcl_Obj *listPtr, *elemObjPtr;
int specificNsInPattern = 0;/* Init. to avoid compiler warning. */
|
| ︙ | ︙ | |||
1949 1950 1951 1952 1953 1954 1955 |
*----------------------------------------------------------------------
*/
static int
InfoScriptCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 |
*----------------------------------------------------------------------
*/
static int
InfoScriptCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
if ((objc != 1) && (objc != 2)) {
Tcl_WrongNumArgs(interp, 1, objv, "?filename?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1997 1998 1999 2000 2001 2002 2003 |
*----------------------------------------------------------------------
*/
static int
InfoSharedlibCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 |
*----------------------------------------------------------------------
*/
static int
InfoSharedlibCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
#ifdef TCL_SHLIB_EXT
|
| ︙ | ︙ | |||
2035 2036 2037 2038 2039 2040 2041 |
*----------------------------------------------------------------------
*/
static int
InfoTclVersionCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 |
*----------------------------------------------------------------------
*/
static int
InfoTclVersionCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *version;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2078 2079 2080 2081 2082 2083 2084 |
*----------------------------------------------------------------------
*/
static int
InfoCmdTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 |
*----------------------------------------------------------------------
*/
static int
InfoCmdTypeCmd(
TCL_UNUSED(void *),
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, TclGetString(objv[1]), NULL,
TCL_LEAVE_ERR_MSG);
if (command == NULL) {
return TCL_ERROR;
}
/*
* There's one special case: safe child 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", (char *)NULL);
} else {
Tcl_SetObjResult(interp,
Tcl_NewStringObj(TclGetCommandTypeName(command), -1));
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
2129 2130 2131 2132 2133 2134 2135 |
*----------------------------------------------------------------------
*/
int
Tcl_JoinObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | > | < < | | < < < < < < < < < < < | < > | < < < | > | | < < | | | | < | < > | > | < | < < < < > | < | < > < | 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 |
*----------------------------------------------------------------------
*/
int
Tcl_JoinObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_Size length, listLen;
int isAbstractList = 0;
Tcl_Obj *resObjPtr = NULL, *joinObjPtr, **elemPtrs;
if ((objc < 2) || (objc > 3)) {
Tcl_WrongNumArgs(interp, 1, objv, "list ?joinString?");
return TCL_ERROR;
}
/*
* Make sure the list argument is a list object and get its length and a
* pointer to its array of element pointers.
*/
if (TclObjTypeHasProc(objv[1], getElementsProc)) {
listLen = TclObjTypeLength(objv[1]);
isAbstractList = (listLen ? 1 : 0);
if (listLen > 1 && TclObjTypeGetElements(interp, objv[1],
&listLen, &elemPtrs) != TCL_OK) {
return TCL_ERROR;
}
} else if (TclListObjGetElements(interp, objv[1], &listLen,
&elemPtrs) != TCL_OK) {
return TCL_ERROR;
}
if (listLen == 0) {
/* No elements to join; default empty result is correct. */
return TCL_OK;
}
if (listLen == 1) {
/* One element; return it */
if (!isAbstractList) {
Tcl_SetObjResult(interp, elemPtrs[0]);
} else {
Tcl_Obj *elemObj;
if (TclObjTypeIndex(interp, objv[1], 0, &elemObj) != TCL_OK) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, elemObj);
}
return TCL_OK;
}
joinObjPtr = (objc == 2) ? Tcl_NewStringObj(" ", 1) : objv[2];
Tcl_IncrRefCount(joinObjPtr);
(void)TclGetStringFromObj(joinObjPtr, &length);
if (length == 0) {
resObjPtr = TclStringCat(interp, listLen, elemPtrs, 0);
} else {
Tcl_Size i;
TclNewObj(resObjPtr);
for (i = 0; i < listLen; i++) {
if (i > 0) {
/*
* NOTE: This code is relying on Tcl_AppendObjToObj() **NOT**
* to shimmer joinObjPtr. If it did, then the case where
* objv[1] and objv[2] are the same value would not be safe.
* Accessing elemPtrs would crash.
*/
Tcl_AppendObjToObj(resObjPtr, joinObjPtr);
}
Tcl_AppendObjToObj(resObjPtr, elemPtrs[i]);
}
}
Tcl_DecrRefCount(joinObjPtr);
if (resObjPtr) {
Tcl_SetObjResult(interp, resObjPtr);
return TCL_OK;
}
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2253 2254 2255 2256 2257 2258 2259 |
*----------------------------------------------------------------------
*/
int
Tcl_LassignObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 |
*----------------------------------------------------------------------
*/
int
Tcl_LassignObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *listPtr;
Tcl_Size listObjc; /* The length of the list. */
Tcl_Size origListObjc; /* Original length */
int i;
if (objc < 2) {
|
| ︙ | ︙ | |||
2323 2324 2325 2326 2327 2328 2329 |
return TCL_ERROR;
}
}
Tcl_DecrRefCount(emptyObj);
}
if (listObjc > 0) {
| | | | > > | > > > > > | | | > | | | 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 |
return TCL_ERROR;
}
}
Tcl_DecrRefCount(emptyObj);
}
if (listObjc > 0) {
Tcl_Obj *resultObjPtr = NULL;
Tcl_Size fromIdx = origListObjc - listObjc;
Tcl_Size toIdx = origListObjc - 1;
if (TclObjTypeHasProc(listPtr, sliceProc)) {
if (TclObjTypeSlice(
interp, listPtr, fromIdx, toIdx, &resultObjPtr) != TCL_OK) {
return TCL_ERROR;
}
} else {
resultObjPtr = TclListObjRange(
interp, listPtr, origListObjc - listObjc, origListObjc - 1);
if (resultObjPtr == NULL) {
return TCL_ERROR;
}
}
Tcl_SetObjResult(interp, resultObjPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_LindexObjCmd --
*
* This object-based procedure is invoked to process the "lindex" Tcl
* command. See the user documentation for details on what it does.
|
| ︙ | ︙ | |||
2357 2358 2359 2360 2361 2362 2363 |
*----------------------------------------------------------------------
*/
int
Tcl_LindexObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 |
*----------------------------------------------------------------------
*/
int
Tcl_LindexObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *elemPtr; /* Pointer to the element being extracted. */
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "list ?index ...?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2415 2416 2417 2418 2419 2420 2421 |
*----------------------------------------------------------------------
*/
int
Tcl_LinsertObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 |
*----------------------------------------------------------------------
*/
int
Tcl_LinsertObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *listPtr;
Tcl_Size len, index;
int copied = 0, result;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "list index ?element ...?");
|
| ︙ | ︙ | |||
2508 2509 2510 2511 2512 2513 2514 |
*----------------------------------------------------------------------
*/
int
Tcl_ListObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | > | | 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 |
*----------------------------------------------------------------------
*/
int
Tcl_ListObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[])
/* The argument objects. */
{
/*
* If there are no list elements, the result is an empty object.
* Otherwise set the interpreter's result object to be a list object.
*/
if (objc > 1) {
|
| ︙ | ︙ | |||
2543 2544 2545 2546 2547 2548 2549 |
*----------------------------------------------------------------------
*/
int
Tcl_LlengthObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | > | | 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 |
*----------------------------------------------------------------------
*/
int
Tcl_LlengthObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[])
/* Argument objects. */
{
Tcl_Size listLen;
int result;
Tcl_Obj *objPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "list");
|
| ︙ | ︙ | |||
2591 2592 2593 2594 2595 2596 2597 |
*----------------------------------------------------------------------
*/
int
Tcl_LpopObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | > | | 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 |
*----------------------------------------------------------------------
*/
int
Tcl_LpopObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[])
/* Argument objects. */
{
Tcl_Size listLen;
int copied = 0, result;
Tcl_Obj *elemPtr, *stored;
Tcl_Obj *listPtr;
if (objc < 2) {
|
| ︙ | ︙ | |||
2623 2624 2625 2626 2627 2628 2629 |
* TclLindexFlat adds a ref count which is handled.
*/
if (objc == 2) {
if (!listLen) {
/* empty list, throw the same error as with index "end" */
Tcl_SetObjResult(interp, Tcl_NewStringObj(
| | | | 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 |
* TclLindexFlat adds a ref count which is handled.
*/
if (objc == 2) {
if (!listLen) {
/* empty list, throw the same error as with index "end" */
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"index \"end\" out of range", -1));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX", "OUTOFRANGE", (char *)NULL);
return TCL_ERROR;
}
result = Tcl_ListObjIndex(interp, listPtr, (listLen-1), &elemPtr);
if (result != TCL_OK) {
return result;
}
Tcl_IncrRefCount(elemPtr);
} else {
elemPtr = TclLindexFlat(interp, listPtr, objc-2, objv+2);
|
| ︙ | ︙ | |||
2709 2710 2711 2712 2713 2714 2715 |
*----------------------------------------------------------------------
*/
int
Tcl_LrangeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | > | | 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 |
*----------------------------------------------------------------------
*/
int
Tcl_LrangeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[])
/* Argument objects. */
{
int result;
Tcl_Size listLen, first, last;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "list first last");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2736 2737 2738 2739 2740 2741 2742 |
result = TclGetIntForIndexM(interp, objv[3], /*endValue*/ listLen - 1,
&last);
if (result != TCL_OK) {
return result;
}
| > | | | | > > | > > > > > > > | | 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 |
result = TclGetIntForIndexM(interp, objv[3], /*endValue*/ listLen - 1,
&last);
if (result != TCL_OK) {
return result;
}
if (TclObjTypeHasProc(objv[1], sliceProc)) {
Tcl_Obj *resultObj;
int status = TclObjTypeSlice(interp, objv[1], first, last, &resultObj);
if (status == TCL_OK) {
Tcl_SetObjResult(interp, resultObj);
} else {
return TCL_ERROR;
}
} else {
Tcl_Obj *resultObj = TclListObjRange(interp, objv[1], first, last);
if (resultObj == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, resultObj);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_LremoveObjCmd --
*
|
| ︙ | ︙ | |||
2780 2781 2782 2783 2784 2785 2786 |
return (idx1 < idx2) ? 1 : (idx1 > idx2) ? -1 : 0;
}
int
Tcl_LremoveObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 |
return (idx1 < idx2) ? 1 : (idx1 > idx2) ? -1 : 0;
}
int
Tcl_LremoveObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size i, idxc, prevIdx, first, num;
Tcl_Size *idxv, listLen;
Tcl_Obj *listObj;
int copied = 0, status = TCL_OK;
/*
|
| ︙ | ︙ | |||
2911 2912 2913 2914 2915 2916 2917 |
*----------------------------------------------------------------------
*/
int
Tcl_LrepeatObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | > | > | > | > > > > > > | > | > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 |
*----------------------------------------------------------------------
*/
int
Tcl_LrepeatObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[])
/* The argument objects. */
{
Tcl_WideInt elementCount, i;
Tcl_Size totalElems;
Tcl_Obj *listPtr, **dataArray = NULL;
/*
* Check arguments for legality:
* lrepeat count ?value ...?
*/
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "count ?value ...?");
return TCL_ERROR;
}
if (TCL_OK != TclGetWideIntFromObj(interp, objv[1], &elementCount)) {
return TCL_ERROR;
}
if (elementCount < 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad count \"%" TCL_LL_MODIFIER "d\": must be integer >= 0", elementCount));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "LREPEAT", "NEGARG",
(char *)NULL);
return TCL_ERROR;
}
/*
* Skip forward to the interesting arguments now we've finished parsing.
*/
objc -= 2;
objv += 2;
/* Final sanity check. Do not exceed limits on max list length. */
if (elementCount && objc > LIST_MAX/elementCount) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"max length of a Tcl list (%" TCL_SIZE_MODIFIER "d elements) exceeded", LIST_MAX));
Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
return TCL_ERROR;
}
totalElems = objc * elementCount;
/*
* Get an empty list object that is allocated large enough to hold each
* init value elementCount times.
*/
listPtr = Tcl_NewListObj(totalElems, NULL);
if (totalElems) {
ListRep listRep;
ListObjGetRep(listPtr, &listRep);
dataArray = ListRepElementsBase(&listRep);
listRep.storePtr->numUsed = totalElems;
if (listRep.spanPtr) {
/* Future proofing in case Tcl_NewListObj returns a span */
listRep.spanPtr->spanStart = listRep.storePtr->firstUsed;
listRep.spanPtr->spanLength = listRep.storePtr->numUsed;
}
}
/*
* Set the elements. Note that we handle the common degenerate case of a
* single value being repeated separately to permit the compiler as much
* room as possible to optimize a loop that might be run a very large
* number of times.
*/
CLANG_ASSERT(dataArray || totalElems == 0 );
if (objc == 1) {
Tcl_Obj *tmpPtr = objv[0];
tmpPtr->refCount += elementCount;
for (i=0 ; i<elementCount ; i++) {
dataArray[i] = tmpPtr;
}
} else {
Tcl_Size j, k = 0;
for (i=0 ; i<elementCount ; i++) {
for (j=0 ; j<objc ; j++) {
Tcl_IncrRefCount(objv[j]);
dataArray[k++] = objv[j];
}
}
}
Tcl_SetObjResult(interp, listPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_LreplaceObjCmd --
|
| ︙ | ︙ | |||
2957 2958 2959 2960 2961 2962 2963 |
*----------------------------------------------------------------------
*/
int
Tcl_LreplaceObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 |
*----------------------------------------------------------------------
*/
int
Tcl_LreplaceObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *listPtr;
Tcl_Size numToDelete, listLen, first, last;
int result;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 1, objv,
|
| ︙ | ︙ | |||
3059 3060 3061 3062 3063 3064 3065 |
*----------------------------------------------------------------------
*/
int
Tcl_LreverseObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 |
*----------------------------------------------------------------------
*/
int
Tcl_LreverseObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument values. */
{
Tcl_Obj **elemv;
Tcl_Size elemc, i, j;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "list");
return TCL_ERROR;
}
/*
* Handle AbstractList special case - do not shimmer into a list, if it
* supports a private Reverse function, just to reverse it.
*/
if (TclObjTypeHasProc(objv[1], reverseProc)) {
Tcl_Obj *resultObj;
if (TclObjTypeReverse(interp, objv[1], &resultObj) == TCL_OK) {
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
} /* end Abstract List */
if (TclListObjLength(interp, objv[1], &elemc) != TCL_OK) {
return TCL_ERROR;
}
/*
* If the list is empty, just return it. [Bug 1876793]
*/
if (!elemc) {
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
}
if (TclListObjGetElements(interp, objv[1], &elemc, &elemv) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_IsShared(objv[1])
|| ListObjRepIsShared(objv[1])) { /* Bug 1675044 */
Tcl_Obj *resultObj, **dataArray;
ListRep listRep;
resultObj = Tcl_NewListObj(elemc, NULL);
/* Modify the internal rep in-place */
ListObjGetRep(resultObj, &listRep);
listRep.storePtr->numUsed = elemc;
dataArray = ListRepElementsBase(&listRep);
if (listRep.spanPtr) {
/* Future proofing */
listRep.spanPtr->spanStart = listRep.storePtr->firstUsed;
listRep.spanPtr->spanLength = listRep.storePtr->numUsed;
}
for (i=0,j=elemc-1 ; i<elemc ; i++,j--) {
dataArray[j] = elemv[i];
Tcl_IncrRefCount(elemv[i]);
}
Tcl_SetObjResult(interp, resultObj);
} else {
/*
* Not shared, so swap "in place". This relies on Tcl_LOGE above
* returning a pointer to the live array of Tcl_Obj values.
*/
for (i=0,j=elemc-1 ; i<j ; i++,j--) {
Tcl_Obj *tmp = elemv[i];
elemv[i] = elemv[j];
elemv[j] = tmp;
}
TclInvalidateStringRep(objv[1]);
Tcl_SetObjResult(interp, objv[1]);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_LsearchObjCmd --
|
| ︙ | ︙ | |||
3096 3097 3098 3099 3100 3101 3102 |
*----------------------------------------------------------------------
*/
int
Tcl_LsearchObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 |
*----------------------------------------------------------------------
*/
int
Tcl_LsearchObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument values. */
{
const char *bytes, *patternBytes;
int match, result=TCL_OK, bisect;
Tcl_Size i, length = 0, listc, elemLen, start, index;
Tcl_Size groupOffset, lower, upper;
int allocatedIndexVector = 0;
int isIncreasing;
|
| ︙ | ︙ | |||
3348 3349 3350 3351 3352 3353 3354 | "\n (-index option item number %" TCL_Z_MODIFIER "u)", j)); goto done; } sortInfo.indexv[j] = encoded; } break; } | < < | 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 |
"\n (-index option item number %" TCL_Z_MODIFIER "u)", j));
goto done;
}
sortInfo.indexv[j] = encoded;
}
break;
}
}
}
/*
* Subindices only make sense if asked for with -index option set.
*/
|
| ︙ | ︙ | |||
3770 3771 3772 3773 3774 3775 3776 |
Tcl_BounceRefCount(itemPtr);
itemPtr = SelectObjFromSublist(listv[i+groupOffset],
&sortInfo);
Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
} else if (returnSubindices && (sortInfo.indexc == 0) && (groupSize > 1)) {
Tcl_BounceRefCount(itemPtr);
itemPtr = listv[i + groupOffset];
| | | 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 |
Tcl_BounceRefCount(itemPtr);
itemPtr = SelectObjFromSublist(listv[i+groupOffset],
&sortInfo);
Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
} else if (returnSubindices && (sortInfo.indexc == 0) && (groupSize > 1)) {
Tcl_BounceRefCount(itemPtr);
itemPtr = listv[i + groupOffset];
Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
} else if (groupSize > 1) {
Tcl_ListObjReplace(interp, listPtr, LIST_MAX, 0,
groupSize, &listv[i]);
} else {
Tcl_BounceRefCount(itemPtr);
itemPtr = listv[i];
Tcl_ListObjAppendElement(interp, listPtr, itemPtr);
|
| ︙ | ︙ | |||
3818 3819 3820 3821 3822 3823 3824 |
Tcl_Obj *elObj;
size_t elValue = TclIndexDecode(sortInfo.indexv[j], listc);
TclNewIndexObj(elObj, elValue);
Tcl_ListObjAppendElement(interp, itemPtr, elObj);
}
Tcl_SetObjResult(interp, itemPtr);
} else {
| | | | 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 |
Tcl_Obj *elObj;
size_t elValue = TclIndexDecode(sortInfo.indexv[j], listc);
TclNewIndexObj(elObj, elValue);
Tcl_ListObjAppendElement(interp, itemPtr, elObj);
}
Tcl_SetObjResult(interp, itemPtr);
} else {
Tcl_Obj *elObj;
TclNewIndexObj(elObj, index);
Tcl_SetObjResult(interp, elObj);
}
} else if (index < 0) {
/*
* Is this superfluous? The result should be a blank object by
* default...
*/
|
| ︙ | ︙ | |||
3862 3863 3864 3865 3866 3867 3868 |
return result;
}
/*
*----------------------------------------------------------------------
*
* SequenceIdentifyArgument --
| < | | | | | | | | | | | < | | | | | | | | 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 |
return result;
}
/*
*----------------------------------------------------------------------
*
* SequenceIdentifyArgument --
* (for [lseq] command)
*
* Given a Tcl_Obj, identify if it is a keyword or a number
*
* Return Value
* 0 - failure, unexpected value
* 1 - value is a number
* 2 - value is an operand keyword
* 3 - value is a by keyword
*
* The decoded value will be assigned to the appropriate
* pointer, numValuePtr reference count is incremented.
*/
static SequenceDecoded
SequenceIdentifyArgument(
Tcl_Interp *interp, /* for error reporting */
Tcl_Obj *argPtr, /* Argument to decode */
int allowedArgs, /* Flags if keyword or numeric allowed. */
Tcl_Obj **numValuePtr, /* Return numeric value */
int *keywordIndexPtr) /* Return keyword enum */
{
int result = TCL_ERROR;
SequenceOperators opmode;
void *internalPtr;
if (allowedArgs & NumericArg) {
result = Tcl_GetNumberFromObj(NULL, argPtr, &internalPtr, keywordIndexPtr);
if (result == TCL_OK) {
*numValuePtr = argPtr;
Tcl_IncrRefCount(argPtr);
return NumericArg;
}
}
if (allowedArgs & RangeKeywordArg) {
result = Tcl_GetIndexFromObj(NULL, argPtr, seq_operations,
"range operation", 0, &opmode);
}
if (result == TCL_OK) {
if (allowedArgs & LastArg) {
/* keyword found, but no followed number */
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"missing \"%s\" value.", TclGetString(argPtr)));
return ErrArg;
}
*keywordIndexPtr = opmode;
return RangeKeywordArg;
} else {
int keyword;
if (!(allowedArgs & NumericArg)) {
|
| ︙ | ︙ | |||
3964 3965 3966 3967 3968 3969 3970 |
*
*----------------------------------------------------------------------
*/
int
Tcl_LseqObjCmd(
TCL_UNUSED(void *),
| | | | < | | | | | | | | | | | 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 |
*
*----------------------------------------------------------------------
*/
int
Tcl_LseqObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_Obj *elementCount = NULL;
Tcl_Obj *start = NULL, *end = NULL, *step = NULL;
Tcl_WideInt values[5];
Tcl_Obj *numValues[5];
Tcl_Obj *numberObj;
int status = TCL_ERROR, keyword, allowedArgs = NumericArg;
int useDoubles = 0;
int remNums = 3;
Tcl_Obj *arithSeriesPtr;
SequenceOperators opmode;
SequenceDecoded decoded;
int i, arg_key = 0, value_i = 0;
/* Default constants */
#define zero ((Interp *)interp)->execEnvPtr->constants[0];
#define one ((Interp *)interp)->execEnvPtr->constants[1];
/*
* Create a decoding key by looping through the arguments and identify
* what kind of argument each one is. Encode each argument as a decimal
* digit.
*/
if (objc > 6) {
/* Too many arguments */
goto syntax;
}
for (i = 1; i < objc; i++) {
arg_key = (arg_key * 10);
numValues[value_i] = NULL;
decoded = SequenceIdentifyArgument(interp, objv[i],
allowedArgs | (i == objc-1 ? LastArg : 0),
&numberObj, &keyword);
switch (decoded) {
case NoneArg:
/*
* Unrecognizable argument
* Reproduce operation error message
*/
status = Tcl_GetIndexFromObj(interp, objv[i], seq_operations,
"operation", 0, &opmode);
goto done;
case NumericArg:
remNums--;
arg_key += NumericArg;
allowedArgs = RangeKeywordArg;
/* if last number but 2 arguments remain, next is not numeric */
if ((remNums != 1) || ((objc-1-i) != 2)) {
allowedArgs |= NumericArg;
}
numValues[value_i] = numberObj;
values[value_i] = keyword; /* TCL_NUMBER_* */
if ((keyword == TCL_NUMBER_DOUBLE || keyword == TCL_NUMBER_NAN)) {
useDoubles++;
}
value_i++;
break;
case RangeKeywordArg:
arg_key += RangeKeywordArg;
allowedArgs = NumericArg; /* after keyword always numeric only */
values[value_i] = keyword; /* SequenceOperators */
value_i++;
break;
default: /* Error state */
status = TCL_ERROR;
goto done;
}
}
/*
* The key encoding defines a valid set of arguments, or indicates an
|
| ︙ | ︙ | |||
4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 |
start = numValues[0];
elementCount = numValues[2];
step = numValues[3];
break;
case LSEQ_BY:
/* Error case */
goto syntax;
default:
goto syntax;
}
break;
/* lseq n n 'by' n */
case 1121:
start = numValues[0];
end = numValues[1];
opmode = (SequenceOperators)values[2];
switch (opmode) {
case LSEQ_BY:
step = numValues[3];
break;
case LSEQ_DOTS:
case LSEQ_TO:
case LSEQ_COUNT:
default:
goto syntax;
}
break;
/* lseq n 'to' n 'by' n */
/* lseq n 'count' n 'by' n */
case 12121:
start = numValues[0];
opmode = (SequenceOperators)values[3];
switch (opmode) {
case LSEQ_BY:
step = numValues[4];
break;
default:
goto syntax;
}
opmode = (SequenceOperators)values[1];
switch (opmode) {
case LSEQ_DOTS:
case LSEQ_TO:
start = numValues[0];
end = numValues[2];
break;
case LSEQ_COUNT:
start = numValues[0];
elementCount = numValues[2];
break;
default:
goto syntax;
}
break;
/* All other argument errors */
default:
| > > > > > | | | > | 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 |
start = numValues[0];
elementCount = numValues[2];
step = numValues[3];
break;
case LSEQ_BY:
/* Error case */
goto syntax;
break;
default:
goto syntax;
break;
}
break;
/* lseq n n 'by' n */
case 1121:
start = numValues[0];
end = numValues[1];
opmode = (SequenceOperators)values[2];
switch (opmode) {
case LSEQ_BY:
step = numValues[3];
break;
case LSEQ_DOTS:
case LSEQ_TO:
case LSEQ_COUNT:
default:
goto syntax;
break;
}
break;
/* lseq n 'to' n 'by' n */
/* lseq n 'count' n 'by' n */
case 12121:
start = numValues[0];
opmode = (SequenceOperators)values[3];
switch (opmode) {
case LSEQ_BY:
step = numValues[4];
break;
default:
goto syntax;
break;
}
opmode = (SequenceOperators)values[1];
switch (opmode) {
case LSEQ_DOTS:
case LSEQ_TO:
start = numValues[0];
end = numValues[2];
break;
case LSEQ_COUNT:
start = numValues[0];
elementCount = numValues[2];
break;
default:
goto syntax;
break;
}
break;
/* All other argument errors */
default:
syntax:
Tcl_WrongNumArgs(interp, 1, objv, "n ??op? n ??by? n??");
goto done;
break;
}
/* Count needs to be integer, so try to convert if possible */
if (elementCount && TclHasInternalRep(elementCount, &tclDoubleType)) {
double d = elementCount->internalRep.doubleValue;
/* Don't consider Count type to indicate using double values in seqence */
useDoubles -= (useDoubles > 0) ? 1 : 0;
|
| ︙ | ︙ | |||
4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 |
/* Infinity, don't convert, let fail later */
} else {
elementCount = Tcl_NewWideIntObj((Tcl_WideInt)d);
keyword = TCL_NUMBER_INT;
}
}
}
/*
* Success! Now lets create the series object.
*/
arithSeriesPtr = TclNewArithSeriesObj(interp,
| > | | | | | 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 |
/* Infinity, don't convert, let fail later */
} else {
elementCount = Tcl_NewWideIntObj((Tcl_WideInt)d);
keyword = TCL_NUMBER_INT;
}
}
}
/*
* Success! Now lets create the series object.
*/
arithSeriesPtr = TclNewArithSeriesObj(interp,
useDoubles, start, end, step, elementCount);
status = TCL_ERROR;
if (arithSeriesPtr) {
status = TCL_OK;
Tcl_SetObjResult(interp, arithSeriesPtr);
}
done:
// Free number arguments.
while (--value_i>=0) {
if (numValues[value_i]) {
if (elementCount == numValues[value_i]) {
elementCount = NULL;
}
Tcl_DecrRefCount(numValues[value_i]);
}
}
if (elementCount) {
Tcl_DecrRefCount(elementCount);
}
/* Undef constants */
#undef zero
#undef one
return status;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4247 4248 4249 4250 4251 4252 4253 |
*----------------------------------------------------------------------
*/
int
Tcl_LsetObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 |
*----------------------------------------------------------------------
*/
int
Tcl_LsetObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument values. */
{
Tcl_Obj *listPtr; /* Pointer to the list being altered. */
Tcl_Obj *finalValuePtr; /* Value finally assigned to the variable. */
/*
* Check parameter count.
*/
|
| ︙ | ︙ | |||
4282 4283 4284 4285 4286 4287 4288 |
*/
if (objc == 4) {
finalValuePtr = TclLsetList(interp, listPtr, objv[2], objv[3]);
} else {
if (TclObjTypeHasProc(listPtr, setElementProc)) {
finalValuePtr = TclObjTypeSetElement(interp, listPtr,
| | | | 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 |
*/
if (objc == 4) {
finalValuePtr = TclLsetList(interp, listPtr, objv[2], objv[3]);
} else {
if (TclObjTypeHasProc(listPtr, setElementProc)) {
finalValuePtr = TclObjTypeSetElement(interp, listPtr,
objc-3, objv+2, objv[objc-1]);
if (finalValuePtr) {
Tcl_IncrRefCount(finalValuePtr);
}
} else {
finalValuePtr = TclLsetFlat(interp, listPtr, objc-3, objv+2,
objv[objc-1]);
}
}
/*
* If substitution has failed, bail out.
*/
|
| ︙ | ︙ | |||
4340 4341 4342 4343 4344 4345 4346 |
*----------------------------------------------------------------------
*/
int
Tcl_LsortObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 |
*----------------------------------------------------------------------
*/
int
Tcl_LsortObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument values. */
{
int indices, nocase = 0, indexc;
int sortMode = SORTMODE_ASCII;
int group, allocatedIndexVector = 0;
Tcl_Size j, idx, groupOffset, length;
Tcl_WideInt wide, groupSize;
Tcl_Obj *resultPtr, *cmdPtr, **listObjPtrs, *listObj, *indexPtr;
Tcl_Size i, elmArrSize;
SortElement *elementArray = NULL, *elementPtr;
SortInfo sortInfo; /* Information about this sort that needs to
* be passed to the comparison function. */
# define MAXCALLOC 1024000
|
| ︙ | ︙ | |||
4514 4515 4516 4517 4518 4519 4520 | sortInfo.resultCode = TCL_ERROR; goto done; } groupSize = wide; group = 1; i++; break; | < < | 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 |
sortInfo.resultCode = TCL_ERROR;
goto done;
}
groupSize = wide;
group = 1;
i++;
break;
}
}
if (nocase && (sortInfo.sortMode == SORTMODE_ASCII)) {
sortInfo.sortMode = SORTMODE_ASCII_NC;
}
/*
|
| ︙ | ︙ | |||
4590 4591 4592 4593 4594 4595 4596 |
goto done;
}
Tcl_ListObjAppendElement(interp, newCommandPtr, Tcl_NewObj());
sortInfo.compareCmdPtr = newCommandPtr;
}
if (TclObjTypeHasProc(objv[1], getElementsProc)) {
| | | | | 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 |
goto done;
}
Tcl_ListObjAppendElement(interp, newCommandPtr, Tcl_NewObj());
sortInfo.compareCmdPtr = newCommandPtr;
}
if (TclObjTypeHasProc(objv[1], getElementsProc)) {
sortInfo.resultCode =
TclObjTypeGetElements(interp, listObj, &length, &listObjPtrs);
} else {
sortInfo.resultCode = TclListObjGetElements(interp, listObj,
&length, &listObjPtrs);
}
if (sortInfo.resultCode != TCL_OK || length <= 0) {
goto done;
}
/*
* Check for sanity when grouping elements of the overall list together
|
| ︙ | ︙ | |||
4859 4860 4861 4862 4863 4864 4865 |
*----------------------------------------------------------------------
*/
int
Tcl_LeditObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | > > < < | 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 |
*----------------------------------------------------------------------
*/
int
Tcl_LeditObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument values. */
{
Tcl_Obj *listPtr; /* Pointer to the list being altered. */
Tcl_Obj *finalValuePtr; /* Value finally assigned to the variable. */
int createdNewObj;
int result;
Tcl_Size first;
Tcl_Size last;
Tcl_Size listLen;
Tcl_Size numToDelete;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 1, objv,
"listVar first last ?element ...?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
4919 4920 4921 4922 4923 4924 4925 |
numToDelete = (size_t)last - (size_t)first + 1; /* See [3d3124d01d] */
} else {
numToDelete = 0;
}
if (Tcl_IsShared(listPtr)) {
listPtr = TclListObjCopy(NULL, listPtr);
| | | | 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 |
numToDelete = (size_t)last - (size_t)first + 1; /* See [3d3124d01d] */
} else {
numToDelete = 0;
}
if (Tcl_IsShared(listPtr)) {
listPtr = TclListObjCopy(NULL, listPtr);
createdNewObj = 1;
} else {
createdNewObj = 0;
}
result =
Tcl_ListObjReplace(interp, listPtr, first, numToDelete, objc - 4, objv + 4);
if (result != TCL_OK) {
if (createdNewObj) {
Tcl_DecrRefCount(listPtr);
|
| ︙ | ︙ | |||
5188 5189 5190 5191 5192 5193 5194 |
const char *left, const char *right) /* The strings to compare. */
{
int uniLeft = 0, uniRight = 0, uniLeftLower, uniRightLower;
int diff, zeros;
int secondaryDiff = 0;
while (1) {
| | | 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 |
const char *left, const char *right) /* The strings to compare. */
{
int uniLeft = 0, uniRight = 0, uniLeftLower, uniRightLower;
int diff, zeros;
int secondaryDiff = 0;
while (1) {
if (isdigit(UCHAR(*right)) /* INTL: digit */
&& isdigit(UCHAR(*left))) { /* INTL: digit */
/*
* There are decimal numbers embedded in the two strings. Compare
* them as numbers, rather than strings. If one number has more
* leading zeros than the other, the number with more leading
* zeros sorts later, but only as a secondary choice.
*/
|
| ︙ | ︙ | |||
5298 5299 5300 5301 5302 5303 5304 | * SelectObjFromSublist -- * * This procedure is invoked from lsearch and SortCompare. It is used for * implementing the -index option, for the lsort and lsearch commands. * * Results: * Returns NULL if a failure occurs, and sets the result in the infoPtr. | | | 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 | * SelectObjFromSublist -- * * This procedure is invoked from lsearch and SortCompare. It is used for * implementing the -index option, for the lsort and lsearch commands. * * Results: * Returns NULL if a failure occurs, and sets the result in the infoPtr. * Otherwise returns the Tcl_Obj* to the item. * * Side effects: * None. * * Note: * No reference counting is done, as the result is only used internally * and never passed directly to user code. |
| ︙ | ︙ | |||
5333 5334 5335 5336 5337 5338 5339 |
/*
* Iterate over the indices, traversing through the nested sublists as we
* go.
*/
for (i=0 ; i<infoPtr->indexc ; i++) {
Tcl_Size listLen;
| | | | | 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 |
/*
* Iterate over the indices, traversing through the nested sublists as we
* go.
*/
for (i=0 ; i<infoPtr->indexc ; i++) {
Tcl_Size listLen;
int index;
Tcl_Obj *currentObj, *lastObj=NULL;
if (TclListObjLength(infoPtr->interp, objPtr, &listLen) != TCL_OK) {
infoPtr->resultCode = TCL_ERROR;
return NULL;
}
index = TclIndexDecode(infoPtr->indexv[i], listLen - 1);
if (Tcl_ListObjIndex(infoPtr->interp, objPtr, index,
¤tObj) != TCL_OK) {
infoPtr->resultCode = TCL_ERROR;
return NULL;
}
if (currentObj == NULL) {
if (index == TCL_INDEX_NONE) {
index = TCL_INDEX_END - infoPtr->indexv[i];
Tcl_SetObjResult(infoPtr->interp, Tcl_ObjPrintf(
"element end-%d missing from sublist \"%s\"",
index, TclGetString(objPtr)));
} else {
Tcl_SetObjResult(infoPtr->interp, Tcl_ObjPrintf(
"element %d missing from sublist \"%s\"",
index, TclGetString(objPtr)));
}
Tcl_SetErrorCode(infoPtr->interp, "TCL", "OPERATION", "LSORT",
"INDEXFAILED", (char *)NULL);
infoPtr->resultCode = TCL_ERROR;
return NULL;
}
|
| ︙ | ︙ |
Changes to generic/tclCmdMZ.c.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | Tcl_Obj *oldOptions, Tcl_Obj *errorInfo); static Tcl_NRPostProc SwitchPostProc; static Tcl_NRPostProc TryPostBody; static Tcl_NRPostProc TryPostFinal; static Tcl_NRPostProc TryPostHandler; static int UniCharIsAscii(int character); static int UniCharIsHexDigit(int character); | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | Tcl_Obj *oldOptions, Tcl_Obj *errorInfo); static Tcl_NRPostProc SwitchPostProc; static Tcl_NRPostProc TryPostBody; static Tcl_NRPostProc TryPostFinal; static Tcl_NRPostProc TryPostHandler; static int UniCharIsAscii(int character); static int UniCharIsHexDigit(int character); static int StringCmpOpts(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int *nocase, Tcl_Size *reqlength); /* * Default set of characters to trim in [string trim] and friends. This is a * UTF-8 literal string containing all Unicode space characters [TIP #413] */ const char tclDefaultTrimSet[] = |
| ︙ | ︙ | |||
149 150 151 152 153 154 155 |
*----------------------------------------------------------------------
*/
int
Tcl_PwdObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
*----------------------------------------------------------------------
*/
int
Tcl_PwdObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *retVal;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
*----------------------------------------------------------------------
*/
int
Tcl_RegexpObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
*----------------------------------------------------------------------
*/
int
Tcl_RegexpObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size offset, stringLength, matchLength, cflags, eflags;
int i, indices, match, about, all, doinline, numMatchesSaved;
Tcl_RegExp regExpr;
Tcl_Obj *objPtr, *startIndex = NULL, *resultPtr = NULL;
Tcl_RegExpInfo info;
static const char *const options[] = {
"-all", "-about", "-indices", "-inline",
"-expanded", "-line", "-linestop", "-lineanchor",
"-nocase", "-start", "--", NULL
|
| ︙ | ︙ | |||
438 439 440 441 442 443 444 | Tcl_Obj *objs[2]; /* * Only adjust the match area if there was a match for that * area. (Scriptics Bug 4391/SF Bug #219232) */ | | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
Tcl_Obj *objs[2];
/*
* Only adjust the match area if there was a match for that
* area. (Scriptics Bug 4391/SF Bug #219232)
*/
if (i <= (int)info.nsubs && info.matches[i].start >= 0) {
start = offset + info.matches[i].start;
end = offset + info.matches[i].end;
/*
* Adjust index so it refers to the last character in the
* match instead of the first character after the match.
*/
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 |
}
TclNewIndexObj(objs[0], start);
TclNewIndexObj(objs[1], end);
newPtr = Tcl_NewListObj(2, objs);
} else {
| | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
}
TclNewIndexObj(objs[0], start);
TclNewIndexObj(objs[1], end);
newPtr = Tcl_NewListObj(2, objs);
} else {
if ((i <= (int)info.nsubs) && (info.matches[i].end > 0)) {
newPtr = Tcl_GetRange(objPtr,
offset + info.matches[i].start,
offset + info.matches[i].end - 1);
} else {
TclNewObj(newPtr);
}
}
|
| ︙ | ︙ | |||
550 551 552 553 554 555 556 |
*----------------------------------------------------------------------
*/
int
Tcl_RegsubObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
*----------------------------------------------------------------------
*/
int
Tcl_RegsubObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result, cflags, all, match, command;
Tcl_Size idx, wlen, wsublen = 0, offset, numMatches, numParts;
Tcl_Size start, end, subStart, subEnd;
Tcl_RegExp regExpr;
Tcl_RegExpInfo info;
Tcl_Obj *resultPtr, *subPtr, *objPtr, *startIndex = NULL;
|
| ︙ | ︙ | |||
846 847 848 849 850 851 852 |
if (command) {
Tcl_Obj **args = NULL, **parts;
Tcl_Size numArgs;
TclListObjGetElements(interp, subPtr, &numParts, &parts);
numArgs = numParts + info.nsubs + 1;
| | | | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
if (command) {
Tcl_Obj **args = NULL, **parts;
Tcl_Size numArgs;
TclListObjGetElements(interp, subPtr, &numParts, &parts);
numArgs = numParts + info.nsubs + 1;
args = (Tcl_Obj **)Tcl_Alloc(sizeof(Tcl_Obj*) * numArgs);
memcpy(args, parts, sizeof(Tcl_Obj*) * numParts);
for (idx = 0 ; idx <= info.nsubs ; idx++) {
subStart = info.matches[idx].start;
subEnd = info.matches[idx].end;
if ((subStart >= 0) && (subEnd >= 0)) {
args[idx + numParts] = Tcl_NewUnicodeObj(
wstring + offset + subStart, subEnd - subStart);
|
| ︙ | ︙ | |||
1072 1073 1074 1075 1076 1077 1078 |
*----------------------------------------------------------------------
*/
int
Tcl_RenameObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 |
*----------------------------------------------------------------------
*/
int
Tcl_RenameObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *oldName, *newName;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "oldName newName");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1108 1109 1110 1111 1112 1113 1114 |
*----------------------------------------------------------------------
*/
int
Tcl_ReturnObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 |
*----------------------------------------------------------------------
*/
int
Tcl_ReturnObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int code, level;
Tcl_Obj *returnOpts;
/*
* General syntax: [return ?-option value ...? ?result?]
* An even number of words means an explicit result argument is present.
*/
int explicitResult = (0 == (objc % 2));
int numOptionWords = objc - 1 - explicitResult;
if (TCL_ERROR == TclMergeReturnOptions(interp, numOptionWords, objv+1,
&returnOpts, &code, &level)) {
return TCL_ERROR;
}
code = TclProcessReturn(interp, code, level, returnOpts);
|
| ︙ | ︙ | |||
1155 1156 1157 1158 1159 1160 1161 |
*----------------------------------------------------------------------
*/
int
Tcl_SourceObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 |
*----------------------------------------------------------------------
*/
int
Tcl_SourceObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRSourceObjCmd, clientData, objc, objv);
}
int
TclNRSourceObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *encodingName = NULL;
Tcl_Obj *fileName;
int result;
void **pkgFiles = NULL;
void *names = NULL;
|
| ︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 |
*----------------------------------------------------------------------
*/
int
Tcl_SplitObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 |
*----------------------------------------------------------------------
*/
int
Tcl_SplitObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int ch = 0;
int len;
const char *splitChars;
const char *stringPtr;
const char *end;
Tcl_Size splitCharLen, stringLen;
Tcl_Obj *listPtr, *objPtr;
if (objc == 2) {
|
| ︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 |
*----------------------------------------------------------------------
*/
static int
StringFirstCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 |
*----------------------------------------------------------------------
*/
static int
StringFirstCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size start = TCL_INDEX_START;
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv,
"needleString haystackString ?startIndex?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 |
*----------------------------------------------------------------------
*/
static int
StringLastCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 |
*----------------------------------------------------------------------
*/
static int
StringLastCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size last = TCL_SIZE_MAX;
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv,
"needleString haystackString ?lastIndex?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1460 1461 1462 1463 1464 1465 1466 |
*----------------------------------------------------------------------
*/
static int
StringIndexCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 |
*----------------------------------------------------------------------
*/
static int
StringIndexCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size index, end;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "string charIndex");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1527 1528 1529 1530 1531 1532 1533 |
*----------------------------------------------------------------------
*/
static int
StringInsertCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter */
| | | | 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 |
*----------------------------------------------------------------------
*/
static int
StringInsertCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter */
int objc, /* Number of arguments */
Tcl_Obj *const objv[]) /* Argument objects */
{
Tcl_Size length; /* String length */
Tcl_Size index; /* Insert index */
Tcl_Obj *outObj; /* Output object */
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "string index insertString");
|
| ︙ | ︙ | |||
1584 1585 1586 1587 1588 1589 1590 |
*----------------------------------------------------------------------
*/
static int
StringIsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 |
*----------------------------------------------------------------------
*/
static int
StringIsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *string1, *end, *stop;
int (*chcomp)(int) = NULL; /* The UniChar comparison function. */
int i, result = 1, strict = 0;
Tcl_Size failat = 0, length1, length2, length3;
Tcl_Obj *objPtr, *failVarObj = NULL;
Tcl_WideInt w;
static const char *const isClasses[] = {
"alnum", "alpha", "ascii", "control",
"boolean", "dict", "digit", "double",
"entier", "false", "graph", "integer",
|
| ︙ | ︙ | |||
1973 1974 1975 1976 1977 1978 1979 |
}
/*
* Only set the failVarObj when we will return 0 and we have indicated a
* valid fail index (>= 0).
*/
| | | 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 |
}
/*
* Only set the failVarObj when we will return 0 and we have indicated a
* valid fail index (>= 0).
*/
str_is_done:
if ((result == 0) && (failVarObj != NULL)) {
TclNewIndexObj(objPtr, failat);
if (Tcl_ObjSetVar2(interp, failVarObj, NULL, objPtr, TCL_LEAVE_ERR_MSG) == NULL) {
return TCL_ERROR;
}
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
|
| ︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 |
*----------------------------------------------------------------------
*/
static int
StringMapCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 |
*----------------------------------------------------------------------
*/
static int
StringMapCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size length1, length2, mapElemc, index;
int nocase = 0, mapWithDict = 0, copySource = 0;
Tcl_Obj **mapElemv, *sourceObj, *resultPtr;
Tcl_UniChar *ustring1, *ustring2, *p, *end;
int (*strCmpFn)(const Tcl_UniChar*, const Tcl_UniChar*, size_t);
|
| ︙ | ︙ | |||
2109 2110 2111 2112 2113 2114 2115 |
Tcl_SetObjResult(interp, objv[objc-1]);
return TCL_OK;
} else if (mapElemc & 1) {
/*
* The charMap must be an even number of key/value items.
*/
| | | | 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 |
Tcl_SetObjResult(interp, objv[objc-1]);
return TCL_OK;
} else if (mapElemc & 1) {
/*
* The charMap must be an even number of key/value items.
*/
Tcl_SetObjResult(interp,
Tcl_NewStringObj("char map list unbalanced", -1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "MAP",
"UNBALANCED", (char *)NULL);
return TCL_ERROR;
}
}
/*
|
| ︙ | ︙ | |||
2296 2297 2298 2299 2300 2301 2302 |
*----------------------------------------------------------------------
*/
static int
StringMatchCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 |
*----------------------------------------------------------------------
*/
static int
StringMatchCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int nocase = 0;
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "?-nocase? pattern string");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2321 2322 2323 2324 2325 2326 2327 |
"bad option \"%s\": must be -nocase", string));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option",
string, (char *)NULL);
return TCL_ERROR;
}
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
| | | 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 |
"bad option \"%s\": must be -nocase", string));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "option",
string, (char *)NULL);
return TCL_ERROR;
}
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
TclStringMatchObj(objv[objc-1], objv[objc-2], nocase)));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* StringRangeCmd --
|
| ︙ | ︙ | |||
2347 2348 2349 2350 2351 2352 2353 |
*----------------------------------------------------------------------
*/
static int
StringRangeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 |
*----------------------------------------------------------------------
*/
static int
StringRangeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size first, last, end;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "string first last");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2397 2398 2399 2400 2401 2402 2403 |
*----------------------------------------------------------------------
*/
static int
StringReptCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 |
*----------------------------------------------------------------------
*/
static int
StringReptCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_WideInt count;
Tcl_Obj *resultPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "string count");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2453 2454 2455 2456 2457 2458 2459 |
*----------------------------------------------------------------------
*/
static int
StringRplcCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 |
*----------------------------------------------------------------------
*/
static int
StringRplcCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size first, last, end;
if (objc < 4 || objc > 5) {
Tcl_WrongNumArgs(interp, 1, objv, "string first last ?string?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2476 2477 2478 2479 2480 2481 2482 |
/*
* The following test screens out most empty substrings as candidates for
* replacement. When they are detected, no replacement is done, and the
* result is the original string.
*/
| | | 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 |
/*
* The following test screens out most empty substrings as candidates for
* replacement. When they are detected, no replacement is done, and the
* result is the original string.
*/
if ((last < 0) || /* Range ends before start of string */
(first > end) || /* Range begins after end of string */
(last < first)) { /* Range begins after it starts */
/*
* BUT!!! when (end < 0) -- an empty original string -- we can
* have (first <= end < 0 <= last) and an empty string is permitted
* to be replaced.
*/
|
| ︙ | ︙ | |||
2530 2531 2532 2533 2534 2535 2536 |
*----------------------------------------------------------------------
*/
static int
StringRevCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 |
*----------------------------------------------------------------------
*/
static int
StringRevCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "string");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, TclStringReverse(objv[1], TCL_STRING_IN_PLACE));
|
| ︙ | ︙ | |||
2563 2564 2565 2566 2567 2568 2569 |
*----------------------------------------------------------------------
*/
static int
StringStartCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 |
*----------------------------------------------------------------------
*/
static int
StringStartCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int ch;
const Tcl_UniChar *p, *string;
Tcl_Size cur, index, length;
Tcl_Obj *obj;
if (objc != 3) {
|
| ︙ | ︙ | |||
2634 2635 2636 2637 2638 2639 2640 |
*----------------------------------------------------------------------
*/
static int
StringEndCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 |
*----------------------------------------------------------------------
*/
static int
StringEndCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int ch;
const Tcl_UniChar *p, *end, *string;
Tcl_Size cur, index, length;
Tcl_Obj *obj;
if (objc != 3) {
|
| ︙ | ︙ | |||
2696 2697 2698 2699 2700 2701 2702 |
*----------------------------------------------------------------------
*/
static int
StringEqualCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 |
*----------------------------------------------------------------------
*/
static int
StringEqualCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
/*
* Remember to keep code here in some sync with the byte-compiled versions
* in tclExecute.c (INST_STR_EQ, INST_STR_NEQ and INST_STR_CMP as well as
* the expr string comparison in INST_EQ/INST_NEQ/INST_LT/...).
*/
const char *string2;
int i, match, nocase = 0;
Tcl_Size length;
Tcl_WideInt reqlength = -1;
if (objc < 3 || objc > 6) {
str_cmp_args:
Tcl_WrongNumArgs(interp, 1, objv,
"?-nocase? ?-length int? string1 string2");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2776 2777 2778 2779 2780 2781 2782 |
*----------------------------------------------------------------------
*/
static int
StringCmpCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 |
*----------------------------------------------------------------------
*/
static int
StringCmpCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
/*
* Remember to keep code here in some sync with the byte-compiled versions
* in tclExecute.c (INST_STR_EQ, INST_STR_NEQ and INST_STR_CMP as well as
* the expr string comparison in INST_EQ/INST_NEQ/INST_LT/...).
*/
|
| ︙ | ︙ | |||
2802 2803 2804 2805 2806 2807 2808 |
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(match));
return TCL_OK;
}
int
StringCmpOpts(
Tcl_Interp *interp, /* Current interpreter. */
| | | > | | 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 |
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(match));
return TCL_OK;
}
int
StringCmpOpts(
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[], /* Argument objects. */
int *nocase,
Tcl_Size *reqlength)
{
int i;
Tcl_Size length;
const char *string;
Tcl_WideInt wreqlength = -1;
*nocase = 0;
if (objc < 3 || objc > 6) {
str_cmp_args:
Tcl_WrongNumArgs(interp, 1, objv,
|
| ︙ | ︙ | |||
2870 2871 2872 2873 2874 2875 2876 |
*----------------------------------------------------------------------
*/
static int
StringCatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 |
*----------------------------------------------------------------------
*/
static int
StringCatCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *objResultPtr;
if (objc < 2) {
/*
* If there are no args, the result is an empty object.
* Just leave the preset empty interp result.
|
| ︙ | ︙ | |||
2915 2916 2917 2918 2919 2920 2921 |
*----------------------------------------------------------------------
*/
static int
StringLenCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 |
*----------------------------------------------------------------------
*/
static int
StringLenCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "string");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(Tcl_GetCharLength(objv[1])));
|
| ︙ | ︙ | |||
2949 2950 2951 2952 2953 2954 2955 |
*----------------------------------------------------------------------
*/
static int
StringLowerCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 |
*----------------------------------------------------------------------
*/
static int
StringLowerCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size length1, length2;
const char *string1;
char *string2;
if (objc < 2 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "string ?first? ?last?");
|
| ︙ | ︙ | |||
3034 3035 3036 3037 3038 3039 3040 |
*----------------------------------------------------------------------
*/
static int
StringUpperCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 |
*----------------------------------------------------------------------
*/
static int
StringUpperCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size length1, length2;
const char *string1;
char *string2;
if (objc < 2 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "string ?first? ?last?");
|
| ︙ | ︙ | |||
3119 3120 3121 3122 3123 3124 3125 |
*----------------------------------------------------------------------
*/
static int
StringTitleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 |
*----------------------------------------------------------------------
*/
static int
StringTitleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size length1, length2;
const char *string1;
char *string2;
if (objc < 2 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "string ?first? ?last?");
|
| ︙ | ︙ | |||
3204 3205 3206 3207 3208 3209 3210 |
*----------------------------------------------------------------------
*/
static int
StringTrimCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 |
*----------------------------------------------------------------------
*/
static int
StringTrimCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *string1, *string2;
Tcl_Size triml, trimr, length1, length2;
if (objc == 3) {
string2 = TclGetStringFromObj(objv[2], &length2);
} else if (objc == 2) {
|
| ︙ | ︙ | |||
3251 3252 3253 3254 3255 3256 3257 |
*----------------------------------------------------------------------
*/
static int
StringTrimLCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 |
*----------------------------------------------------------------------
*/
static int
StringTrimLCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *string1, *string2;
int trim;
Tcl_Size length1, length2;
if (objc == 3) {
string2 = TclGetStringFromObj(objv[2], &length2);
} else if (objc == 2) {
string2 = tclDefaultTrimSet;
length2 = strlen(tclDefaultTrimSet);
|
| ︙ | ︙ | |||
3298 3299 3300 3301 3302 3303 3304 |
*----------------------------------------------------------------------
*/
static int
StringTrimRCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 |
*----------------------------------------------------------------------
*/
static int
StringTrimRCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *string1, *string2;
int trim;
Tcl_Size length1, length2;
if (objc == 3) {
string2 = TclGetStringFromObj(objv[2], &length2);
} else if (objc == 2) {
string2 = tclDefaultTrimSet;
length2 = strlen(tclDefaultTrimSet);
} else {
Tcl_WrongNumArgs(interp, 1, objv, "string ?chars?");
return TCL_ERROR;
}
string1 = TclGetStringFromObj(objv[1], &length1);
trim = TclTrimRight(string1, length1, string2, length2);
Tcl_SetObjResult(interp, Tcl_NewStringObj(string1, length1-trim));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclInitStringCmd --
*
* This procedure creates the "string" Tcl command. See the user
* documentation for details on what it does. Note that this command only
* functions correctly on properly formed Tcl UTF strings.
*
* Also note that the primary methods here (equal, compare, match, ...)
* have bytecode equivalents. You will find the code for those in
* tclExecute.c. The code here will only be used in the non-bc case (like
* in an 'eval').
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitStringCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap stringImplMap[] = {
{"cat", StringCatCmd, TclCompileStringCatCmd, NULL, NULL, 0},
{"compare", StringCmpCmd, TclCompileStringCmpCmd, NULL, NULL, 0},
{"equal", StringEqualCmd, TclCompileStringEqualCmd, NULL, NULL, 0},
{"first", StringFirstCmd, TclCompileStringFirstCmd, NULL, NULL, 0},
{"index", StringIndexCmd, TclCompileStringIndexCmd, NULL, NULL, 0},
{"insert", StringInsertCmd, TclCompileStringInsertCmd, NULL, NULL, 0},
{"is", StringIsCmd, TclCompileStringIsCmd, NULL, NULL, 0},
{"last", StringLastCmd, TclCompileStringLastCmd, NULL, NULL, 0},
{"length", StringLenCmd, TclCompileStringLenCmd, NULL, NULL, 0},
{"map", StringMapCmd, TclCompileStringMapCmd, NULL, NULL, 0},
{"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, NULL, 0},
{"range", StringRangeCmd, TclCompileStringRangeCmd, NULL, NULL, 0},
{"repeat", StringReptCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"replace", StringRplcCmd, TclCompileStringReplaceCmd, NULL, NULL, 0},
{"reverse", StringRevCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"tolower", StringLowerCmd, TclCompileStringToLowerCmd, NULL, NULL, 0},
{"toupper", StringUpperCmd, TclCompileStringToUpperCmd, NULL, NULL, 0},
{"totitle", StringTitleCmd, TclCompileStringToTitleCmd, NULL, NULL, 0},
{"trim", StringTrimCmd, TclCompileStringTrimCmd, NULL, NULL, 0},
{"trimleft", StringTrimLCmd, TclCompileStringTrimLCmd, NULL, NULL, 0},
{"trimright", StringTrimRCmd, TclCompileStringTrimRCmd, NULL, NULL, 0},
{"wordend", StringEndCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"wordstart", StringStartCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
return TclMakeEnsemble(interp, "string", stringImplMap);
}
/*
*----------------------------------------------------------------------
*
* Tcl_SubstObjCmd --
*
* This procedure is invoked to process the "subst" Tcl command. See the
|
| ︙ | ︙ | |||
3348 3349 3350 3351 3352 3353 3354 |
TclSubstOptions(
Tcl_Interp *interp,
Tcl_Size numOpts,
Tcl_Obj *const opts[],
int *flagPtr)
{
static const char *const substOptions[] = {
| < | < < < < < | | < < < < < < < < < < < | | | | | < | 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 |
TclSubstOptions(
Tcl_Interp *interp,
Tcl_Size numOpts,
Tcl_Obj *const opts[],
int *flagPtr)
{
static const char *const substOptions[] = {
"-nobackslashes", "-nocommands", "-novariables", NULL
};
static const int optionFlags[] = {
TCL_SUBST_BACKSLASHES, TCL_SUBST_COMMANDS, TCL_SUBST_VARIABLES
};
int flags = TCL_SUBST_ALL;
for (Tcl_Size i = 0; i < numOpts; i++) {
int optionIndex;
if (Tcl_GetIndexFromObj(interp, opts[i], substOptions, "option", 0,
&optionIndex) != TCL_OK) {
return TCL_ERROR;
}
flags &= ~optionFlags[optionIndex];
}
*flagPtr = flags;
return TCL_OK;
}
int
Tcl_SubstObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRSubstObjCmd, clientData, objc, objv);
}
int
TclNRSubstObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int flags;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-nobackslashes? ?-nocommands? ?-novariables? string");
return TCL_ERROR;
}
if (TclSubstOptions(interp, objc-2, objv+1, &flags) != TCL_OK) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3438 3439 3440 3441 3442 3443 3444 |
*----------------------------------------------------------------------
*/
int
Tcl_SwitchObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | < | | | | | | 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 |
*----------------------------------------------------------------------
*/
int
Tcl_SwitchObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRSwitchObjCmd, clientData, objc, objv);
}
int
TclNRSwitchObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int i, mode, foundmode, splitObjs, numMatchesSaved;
int noCase;
Tcl_Size patternLength, j;
const char *pattern;
Tcl_Obj *stringObj, *indexVarObj, *matchVarObj;
Tcl_Obj *const *savedObjv = objv;
Tcl_RegExp regExpr = NULL;
Interp *iPtr = (Interp *) interp;
int pc = 0;
int bidx = 0; /* Index of body argument. */
Tcl_Obj *blist = NULL; /* List obj which is the body */
CmdFrame *ctxPtr; /* Copy of the topmost cmdframe, to allow us
* to mess with the line information */
/*
* If you add options that make -e and -g not unique prefixes of -exact or
* -glob, you *must* fix TclCompileSwitchCmd's option parser as well.
*/
static const char *const options[] = {
"-exact", "-glob", "-indexvar", "-matchvar", "-nocase", "-regexp",
"--", NULL
};
enum switchOptionsEnum {
OPT_EXACT, OPT_GLOB, OPT_INDEXV, OPT_MATCHV, OPT_NOCASE, OPT_REGEXP,
OPT_LAST
} index;
typedef int (*strCmpFn_t)(const char *, const char *);
strCmpFn_t strCmpFn = TclUtfCmp;
mode = OPT_EXACT;
foundmode = 0;
indexVarObj = NULL;
|
| ︙ | ︙ | |||
3536 3537 3538 3539 3540 3541 3542 | /* * Check for TIP#75 options specifying the variables to write * regexp information into. */ case OPT_INDEXV: i++; | | | | < < < < < < | < | | 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 |
/*
* Check for TIP#75 options specifying the variables to write
* regexp information into.
*/
case OPT_INDEXV:
i++;
if (i >= objc-2) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"missing variable name argument to %s option",
"-indexvar"));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH",
"NOVAR", (char *)NULL);
return TCL_ERROR;
}
indexVarObj = objv[i];
numMatchesSaved = -1;
break;
case OPT_MATCHV:
i++;
if (i >= objc-2) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"missing variable name argument to %s option",
"-matchvar"));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH",
"NOVAR", (char *)NULL);
return TCL_ERROR;
}
matchVarObj = objv[i];
numMatchesSaved = -1;
break;
}
}
finishedOptions:
if (objc - i < 2) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-option ...? string ?pattern body ...? ?default body?");
return TCL_ERROR;
}
if (indexVarObj != NULL && mode != OPT_REGEXP) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s option requires -regexp option", "-indexvar"));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH",
"MODERESTRICTION", (char *)NULL);
return TCL_ERROR;
}
if (matchVarObj != NULL && mode != OPT_REGEXP) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s option requires -regexp option", "-matchvar"));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH",
"MODERESTRICTION", (char *)NULL);
return TCL_ERROR;
}
stringObj = objv[i];
objc -= i + 1;
objv += i + 1;
bidx = i + 1; /* First after the match string. */
/*
* If all of the pattern/command pairs are lumped into a single argument,
* split them out again.
|
| ︙ | ︙ | |||
3619 3620 3621 3622 3623 3624 3625 | return TCL_ERROR; } /* * Ensure that the list is non-empty. */ | | | 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 |
return TCL_ERROR;
}
/*
* Ensure that the list is non-empty.
*/
if (listc < 1 || listc > INT_MAX) {
Tcl_WrongNumArgs(interp, 1, savedObjv,
"?-option ...? string {?pattern body ...? ?default body?}");
return TCL_ERROR;
}
if (TclListObjGetElements(interp, objv[0], &listc, &listv) != TCL_OK) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3683 3684 3685 3686 3687 3688 3689 |
"no body specified for pattern \"%s\"",
TclGetString(objv[objc-2])));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "BADARM",
"FALLTHROUGH", (char *)NULL);
return TCL_ERROR;
}
| < < < < < < | | 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 |
"no body specified for pattern \"%s\"",
TclGetString(objv[objc-2])));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "SWITCH", "BADARM",
"FALLTHROUGH", (char *)NULL);
return TCL_ERROR;
}
for (i = 0; i < objc; i += 2) {
/*
* See if the pattern matches the string.
*/
pattern = TclGetStringFromObj(objv[i], &patternLength);
if ((i == objc - 2) && (*pattern == 'd')
&& (strcmp(pattern, "default") == 0)) {
Tcl_Obj *emptyObj = NULL;
/*
* If either indexVarObj or matchVarObj are non-NULL, we're in
* REGEXP mode but have reached the default clause anyway. TIP#75
* specifies that we set the variables to empty lists (== empty
|
| ︙ | ︙ | |||
3728 3729 3730 3731 3732 3733 3734 |
}
}
goto matchFound;
}
switch (mode) {
case OPT_EXACT:
| | | | < < < < < < < | 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 |
}
}
goto matchFound;
}
switch (mode) {
case OPT_EXACT:
if (strCmpFn(TclGetString(stringObj), pattern) == 0) {
goto matchFound;
}
break;
case OPT_GLOB:
if (Tcl_StringCaseMatch(TclGetString(stringObj),pattern,noCase)) {
goto matchFound;
}
break;
case OPT_REGEXP:
regExpr = Tcl_GetRegExpFromObj(interp, objv[i],
TCL_REG_ADVANCED | (noCase ? TCL_REG_NOCASE : 0));
if (regExpr == NULL) {
return TCL_ERROR;
} else {
int matched = Tcl_RegExpExecObj(interp, regExpr, stringObj, 0,
numMatchesSaved, 0);
if (matched < 0) {
return TCL_ERROR;
} else if (matched) {
goto matchFoundRegexp;
}
}
break;
}
}
return TCL_OK;
matchFoundRegexp:
/*
|
| ︙ | ︙ | |||
3809 3810 3811 3812 3813 3814 3815 |
Tcl_NewListObj(2, rangeObjAry));
}
if (matchVarObj != NULL) {
Tcl_Obj *substringObj;
if (info.matches[j].end > 0) {
| | | 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 |
Tcl_NewListObj(2, rangeObjAry));
}
if (matchVarObj != NULL) {
Tcl_Obj *substringObj;
if (info.matches[j].end > 0) {
substringObj = Tcl_GetRange(stringObj,
info.matches[j].start, info.matches[j].end-1);
} else {
TclNewObj(substringObj);
}
/*
* Never fails; the object is always clean at this point.
|
| ︙ | ︙ | |||
3888 3889 3890 3891 3892 3893 3894 |
/*
* The line information in the cmdFrame is now a copy we do not
* own.
*/
}
if (ctxPtr->type == TCL_LOCATION_SOURCE && ctxPtr->line[bidx] >= 0) {
| | | | | 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 |
/*
* The line information in the cmdFrame is now a copy we do not
* own.
*/
}
if (ctxPtr->type == TCL_LOCATION_SOURCE && ctxPtr->line[bidx] >= 0) {
int bline = ctxPtr->line[bidx];
ctxPtr->line = (Tcl_Size *)Tcl_Alloc(objc * sizeof(Tcl_Size));
ctxPtr->nline = objc;
TclListLines(blist, bline, objc, ctxPtr->line, objv);
} else {
/*
* This is either a dynamic code word, when all elements are
* relative to themselves, or something else less expected and
* where we have no information. The result is the same in both
* cases; tell the code to come that it doesn't know where it is,
* which triggers reversion to the old behavior.
*/
int k;
ctxPtr->line = (Tcl_Size *)Tcl_Alloc(objc * sizeof(Tcl_Size));
ctxPtr->nline = objc;
for (k=0; k < objc; k++) {
ctxPtr->line[k] = -1;
}
}
}
|
| ︙ | ︙ | |||
3930 3931 3932 3933 3934 3935 3936 |
}
}
/*
* TIP #280: Make invoking context available to switch branch.
*/
| | | | | | | 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 |
}
}
/*
* TIP #280: Make invoking context available to switch branch.
*/
Tcl_NRAddCallback(interp, SwitchPostProc, INT2PTR(splitObjs), ctxPtr,
INT2PTR(pc), (void *)pattern);
return TclNREvalObjEx(interp, objv[j], 0, ctxPtr, splitObjs ? j : bidx+j);
}
static int
SwitchPostProc(
void *data[], /* Data passed from Tcl_NRAddCallback above */
Tcl_Interp *interp, /* Tcl interpreter */
int result) /* Result to return*/
{
/* Unpack the preserved data */
int splitObjs = PTR2INT(data[0]);
CmdFrame *ctxPtr = (CmdFrame *)data[1];
int pc = PTR2INT(data[2]);
const char *pattern = (const char *)data[3];
Tcl_Size patternLength = strlen(pattern);
/*
* Clean up TIP 280 context information
*/
|
| ︙ | ︙ | |||
4002 4003 4004 4005 4006 4007 4008 |
*----------------------------------------------------------------------
*/
int
Tcl_ThrowObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 |
*----------------------------------------------------------------------
*/
int
Tcl_ThrowObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *options;
Tcl_Size len;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "type message");
return TCL_ERROR;
|
| ︙ | ︙ | |||
4064 4065 4066 4067 4068 4069 4070 |
*----------------------------------------------------------------------
*/
int
Tcl_TimeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | > | > > > | | | | > | 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 |
*----------------------------------------------------------------------
*/
int
Tcl_TimeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *objPtr;
Tcl_Obj *objs[4];
int i, result;
int count;
double totalMicroSec;
#ifndef TCL_WIDE_CLICKS
Tcl_Time start, stop;
#else
Tcl_WideInt start, stop;
#endif
if (objc == 2) {
count = 1;
} else if (objc == 3) {
result = TclGetIntFromObj(interp, objv[2], &count);
if (result != TCL_OK) {
return result;
}
} else {
Tcl_WrongNumArgs(interp, 1, objv, "command ?count?");
return TCL_ERROR;
}
objPtr = objv[1];
i = count;
#ifndef TCL_WIDE_CLICKS
Tcl_GetTime(&start);
#else
start = TclpGetWideClicks();
#endif
while (i-- > 0) {
result = TclEvalObjEx(interp, objPtr, 0, NULL, 0);
if (result != TCL_OK) {
return result;
}
}
#ifndef TCL_WIDE_CLICKS
Tcl_GetTime(&stop);
totalMicroSec = ((double) (stop.sec - start.sec)) * 1.0e6
+ (stop.usec - start.usec);
#else
stop = TclpGetWideClicks();
totalMicroSec = ((double) TclpWideClicksToNanoseconds(stop - start))/1.0e3;
#endif
if (count <= 1) {
/*
|
| ︙ | ︙ | |||
4157 4158 4159 4160 4161 4162 4163 |
*----------------------------------------------------------------------
*/
int
Tcl_TimeRateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | < | 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 |
*----------------------------------------------------------------------
*/
int
Tcl_TimeRateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static double measureOverhead = 0;
/* global measure-overhead */
double overhead = -1; /* given measure-overhead */
Tcl_Obj *objPtr;
int result, i;
Tcl_Obj *calibrate = NULL, *direct = NULL;
Tcl_WideUInt count = 0; /* Holds repetition count */
Tcl_WideUInt lastCount = 0; /* Repetition count since last calculation. */
Tcl_WideInt maxms = WIDE_MIN;
/* Maximal running time (in milliseconds) */
Tcl_WideUInt maxcnt = UWIDE_MAX;
/* Maximal count of iterations. */
|
| ︙ | ︙ | |||
4191 4192 4193 4194 4195 4196 4197 |
#define TR_MIN_FACTOR 2 /* Min allowed factor calculating threshold. */
#define TR_MAX_FACTOR 50 /* Max allowed factor calculating threshold. */
#define TR_FACT_SINGLE_ITER 25 /* This or larger factor value will force the
* threshold 1, to avoid drastic growth of
* execution time by quadratic O() complexity. */
unsigned short factor = 16; /* Factor (2..50) limiting threshold to avoid
* growth of execution time. */
| | > > > | | | | | | 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 |
#define TR_MIN_FACTOR 2 /* Min allowed factor calculating threshold. */
#define TR_MAX_FACTOR 50 /* Max allowed factor calculating threshold. */
#define TR_FACT_SINGLE_ITER 25 /* This or larger factor value will force the
* threshold 1, to avoid drastic growth of
* execution time by quadratic O() complexity. */
unsigned short factor = 16; /* Factor (2..50) limiting threshold to avoid
* growth of execution time. */
Tcl_WideInt start, last, middle, stop;
#ifndef TCL_WIDE_CLICKS
Tcl_Time now;
#endif /* !TCL_WIDE_CLICKS */
static const char *const options[] = {
"-direct", "-overhead", "-calibrate", "--", NULL
};
enum timeRateOptionsEnum {
TMRT_EV_DIRECT, TMRT_OVERHEAD, TMRT_CALIBRATE, TMRT_LAST
};
NRE_callback *rootPtr;
ByteCode *codePtr = NULL;
for (i = 1; i < objc - 1; i++) {
enum timeRateOptionsEnum index;
if (Tcl_GetIndexFromObj(NULL, objv[i], options, "option", TCL_EXACT,
&index) != TCL_OK) {
break;
}
if (index == TMRT_LAST) {
i++;
break;
}
switch (index) {
case TMRT_EV_DIRECT:
direct = objv[i];
break;
case TMRT_OVERHEAD:
if (++i >= objc - 1) {
goto usage;
}
if (Tcl_GetDoubleFromObj(interp, objv[i], &overhead) != TCL_OK) {
return TCL_ERROR;
}
break;
case TMRT_CALIBRATE:
calibrate = objv[i];
break;
case TMRT_LAST:
break;
default:
TCL_UNREACHABLE();
}
}
if (i >= objc || i < objc - 3) {
usage:
Tcl_WrongNumArgs(interp, 1, objv,
"?-direct? ?-calibrate? ?-overhead double? "
"command ?time ?max-count??");
return TCL_ERROR;
}
objPtr = objv[i++];
if (i < objc) { /* max-time */
result = TclGetWideIntFromObj(interp, objv[i], &maxms);
i++; // Keep this separate from TclGetWideIntFromObj macro above!
if (result != TCL_OK) {
return result;
}
if (i < objc) { /* max-count*/
Tcl_WideInt v;
result = TclGetWideIntFromObj(interp, objv[i], &v);
if (result != TCL_OK) {
return result;
}
maxcnt = (v > 0) ? v : 0;
|
| ︙ | ︙ | |||
4270 4271 4272 4273 4274 4275 4276 |
if (calibrate) {
/*
* If no time specified for the calibration.
*/
if (maxms == WIDE_MIN) {
Tcl_Obj *clobjv[6];
| | | 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 |
if (calibrate) {
/*
* If no time specified for the calibration.
*/
if (maxms == WIDE_MIN) {
Tcl_Obj *clobjv[6];
Tcl_WideInt maxCalTime = 5000;
double lastMeasureOverhead = measureOverhead;
clobjv[0] = objv[0];
i = 1;
if (direct) {
clobjv[i++] = direct;
}
|
| ︙ | ︙ | |||
4316 4317 4318 4319 4320 4321 4322 |
/*
* Run the calibration cycle until it is more precise.
*/
maxms = -1000;
do {
lastMeasureOverhead = measureOverhead;
| | | 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 |
/*
* Run the calibration cycle until it is more precise.
*/
maxms = -1000;
do {
lastMeasureOverhead = measureOverhead;
TclNewIntObj(clobjv[i], (int) maxms);
Tcl_IncrRefCount(clobjv[i]);
result = Tcl_TimeRateObjCmd(NULL, interp, i + 1, clobjv);
Tcl_DecrRefCount(clobjv[i]);
if (result != TCL_OK) {
return result;
}
maxCalTime += maxms;
|
| ︙ | ︙ | |||
4402 4403 4404 4405 4406 4407 4408 |
#ifdef TCL_WIDE_CLICKS
start = last = middle = TclpGetWideClicks();
/*
* Time to stop execution (in wide clicks).
*/
| | > > > > | | 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 |
#ifdef TCL_WIDE_CLICKS
start = last = middle = TclpGetWideClicks();
/*
* Time to stop execution (in wide clicks).
*/
stop = start + (maxms * 1000 / TclpWideClickInMicrosec());
#else
Tcl_GetTime(&now);
start = now.sec;
start *= 1000000;
start += now.usec;
last = middle = start;
/*
* Time to stop execution (in microsecs).
*/
stop = start + maxms * 1000;
#endif /* TCL_WIDE_CLICKS */
|
| ︙ | ︙ | |||
4474 4475 4476 4477 4478 4479 4480 | /* * Check stop time reached, estimate new threshold. */ #ifdef TCL_WIDE_CLICKS middle = TclpGetWideClicks(); #else | > | > > | 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 |
/*
* Check stop time reached, estimate new threshold.
*/
#ifdef TCL_WIDE_CLICKS
middle = TclpGetWideClicks();
#else
Tcl_GetTime(&now);
middle = now.sec;
middle *= 1000000;
middle += now.usec;
#endif /* TCL_WIDE_CLICKS */
if (middle >= stop || count >= maxcnt) {
break;
}
/*
|
| ︙ | ︙ | |||
4546 4547 4548 4549 4550 4551 4552 | /* * Calculate next threshold to check. * Firstly check iteration time is not larger than remaining time, * considering last known iteration growth factor. */ threshold = (Tcl_WideUInt)(stop - middle) * TR_SCALE; | | | | | | | 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 |
/*
* Calculate next threshold to check.
* Firstly check iteration time is not larger than remaining time,
* considering last known iteration growth factor.
*/
threshold = (Tcl_WideUInt)(stop - middle) * TR_SCALE;
/*
* Estimated count of iteration til the end of execution.
* Thereby 2.5% longer execution time would be OK.
*/
if (threshold / estIterTm < 0.975) {
/* estimated time for next iteration is too large */
break;
}
threshold /= estIterTm;
/*
* Don't use threshold by few iterations, because sometimes
* first iteration(s) can be too fast or slow (cached, delayed
* clean up, etc). Also avoid unexpected execution time growth,
* so if iterations continuously grow, stay by single iteration.
*/
if (count < 10 || factor >= TR_FACT_SINGLE_ITER) {
|
| ︙ | ︙ | |||
4599 4600 4601 4602 4603 4604 4605 | usec = (Tcl_WideUInt)(middle - start); #ifdef TCL_WIDE_CLICKS /* * convert execution time (in wide clicks) to microsecs. */ | | | 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 |
usec = (Tcl_WideUInt)(middle - start);
#ifdef TCL_WIDE_CLICKS
/*
* convert execution time (in wide clicks) to microsecs.
*/
usec *= TclpWideClickInMicrosec();
#endif /* TCL_WIDE_CLICKS */
if (!count) { /* no iterations - avoid divide by zero */
TclNewIntObj(objs[4], 0);
objs[0] = objs[2] = objs[4];
goto retRes;
}
|
| ︙ | ︙ | |||
4622 4623 4624 4625 4626 4627 4628 |
*/
if (overhead > 0) {
/*
* Estimate the time of overhead (microsecs).
*/
| | | 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 |
*/
if (overhead > 0) {
/*
* Estimate the time of overhead (microsecs).
*/
Tcl_WideUInt curOverhead = overhead * count;
if (usec > curOverhead) {
usec -= curOverhead;
} else {
usec = 0;
}
}
|
| ︙ | ︙ | |||
4746 4747 4748 4749 4750 4751 4752 |
*----------------------------------------------------------------------
*/
int
Tcl_TryObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 |
*----------------------------------------------------------------------
*/
int
Tcl_TryObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRTryObjCmd, clientData, objc, objv);
}
int
TclNRTryObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *bodyObj, *handlersObj, *finallyObj = NULL;
int i, bodyShared, haveHandlers, code;
Tcl_Size dummy;
static const char *const handlerNames[] = {
"finally", "on", "trap", NULL
};
enum Handlers {
TryFinally, TryOn, TryTrap
};
|
| ︙ | ︙ | |||
4795 4796 4797 4798 4799 4800 4801 |
if (Tcl_GetIndexFromObj(interp, objv[i], handlerNames, "handler type",
0, &type) != TCL_OK) {
Tcl_DecrRefCount(handlersObj);
return TCL_ERROR;
}
switch (type) {
case TryFinally: /* finally script */
| | | | | | 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 |
if (Tcl_GetIndexFromObj(interp, objv[i], handlerNames, "handler type",
0, &type) != TCL_OK) {
Tcl_DecrRefCount(handlersObj);
return TCL_ERROR;
}
switch (type) {
case TryFinally: /* finally script */
if (i < objc-2) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"finally clause must be last", -1));
Tcl_DecrRefCount(handlersObj);
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "FINALLY",
"NONTERMINAL", (char *)NULL);
return TCL_ERROR;
} else if (i == objc-1) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"wrong # args to finally clause: must be"
" \"... finally script\"", -1));
Tcl_DecrRefCount(handlersObj);
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "FINALLY",
"ARGUMENT", (char *)NULL);
return TCL_ERROR;
}
finallyObj = objv[++i];
break;
case TryOn: /* on code variableList script */
if (i > objc-4) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"wrong # args to on clause: must be \"... on code"
" variableList script\"", -1));
Tcl_DecrRefCount(handlersObj);
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "ON",
"ARGUMENT", (char *)NULL);
return TCL_ERROR;
}
if (TclGetCompletionCodeFromObj(interp, objv[i+1],
&code) != TCL_OK) {
Tcl_DecrRefCount(handlersObj);
return TCL_ERROR;
}
info[2] = NULL;
goto commonHandler;
case TryTrap: /* trap pattern variableList script */
if (i > objc-4) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"wrong # args to trap clause: "
"must be \"... trap pattern variableList script\"",
-1));
Tcl_DecrRefCount(handlersObj);
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "TRY", "TRAP",
"ARGUMENT", (char *)NULL);
|
| ︙ | ︙ | |||
4896 4897 4898 4899 4900 4901 4902 |
handlersObj = NULL;
}
/*
* Execute the body.
*/
| | | | 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 |
handlersObj = NULL;
}
/*
* Execute the body.
*/
Tcl_NRAddCallback(interp, TryPostBody, handlersObj, finallyObj,
(void *)objv, INT2PTR(objc));
return TclNREvalObjEx(interp, bodyObj, 0,
((Interp *) interp)->cmdFramePtr, 1);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4957 4958 4959 4960 4961 4962 4963 |
static int
TryPostBody(
void *data[],
Tcl_Interp *interp,
int result)
{
Tcl_Obj *resultObj, *options, *handlersObj, *finallyObj, *cmdObj, **objv;
| | | | 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 |
static int
TryPostBody(
void *data[],
Tcl_Interp *interp,
int result)
{
Tcl_Obj *resultObj, *options, *handlersObj, *finallyObj, *cmdObj, **objv;
int code, objc;
Tcl_Size i, numHandlers = 0;
handlersObj = (Tcl_Obj *)data[0];
finallyObj = (Tcl_Obj *)data[1];
objv = (Tcl_Obj **)data[2];
objc = PTR2INT(data[3]);
cmdObj = objv[0];
|
| ︙ | ︙ | |||
5107 5108 5109 5110 5111 5112 5113 | * now because the info[] array is about to become invalid. There * is very little refcount handling here however, since we know * that the objects that we still want to refer to now were input * arguments to [try] and so are still on the Tcl value stack. */ handlerBodyObj = info[4]; | | | 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 | * now because the info[] array is about to become invalid. There * is very little refcount handling here however, since we know * that the objects that we still want to refer to now were input * arguments to [try] and so are still on the Tcl value stack. */ handlerBodyObj = info[4]; Tcl_NRAddCallback(interp, TryPostHandler, objv, options, info[0], INT2PTR((finallyObj == NULL) ? 0 : objc - 1)); Tcl_DecrRefCount(handlersObj); return TclNREvalObjEx(interp, handlerBodyObj, 0, ((Interp *) interp)->cmdFramePtr, 4*i + 5); handlerFailed: resultObj = Tcl_GetObjResult(interp); |
| ︙ | ︙ | |||
5135 5136 5137 5138 5139 5140 5141 |
}
/*
* Process the finally clause.
*/
if (finallyObj != NULL) {
| | | 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 |
}
/*
* Process the finally clause.
*/
if (finallyObj != NULL) {
Tcl_NRAddCallback(interp, TryPostFinal, resultObj, options, cmdObj,
NULL);
return TclNREvalObjEx(interp, finallyObj, 0,
((Interp *) interp)->cmdFramePtr, objc - 1);
}
/*
* Install the correct result/options into the interpreter and clean up
|
| ︙ | ︙ | |||
5172 5173 5174 5175 5176 5177 5178 |
TryPostHandler(
void *data[],
Tcl_Interp *interp,
int result)
{
Tcl_Obj *resultObj, *cmdObj, *options, *handlerKindObj, **objv;
Tcl_Obj *finallyObj;
| | | 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 |
TryPostHandler(
void *data[],
Tcl_Interp *interp,
int result)
{
Tcl_Obj *resultObj, *cmdObj, *options, *handlerKindObj, **objv;
Tcl_Obj *finallyObj;
int finallyIndex;
objv = (Tcl_Obj **)data[0];
options = (Tcl_Obj *)data[1];
handlerKindObj = (Tcl_Obj *)data[2];
finallyIndex = PTR2INT(data[3]);
cmdObj = objv[0];
|
| ︙ | ︙ | |||
5219 5220 5221 5222 5223 5224 5225 |
/*
* Process the finally clause if it is present.
*/
if (finallyObj != NULL) {
Interp *iPtr = (Interp *) interp;
| | | 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 |
/*
* Process the finally clause if it is present.
*/
if (finallyObj != NULL) {
Interp *iPtr = (Interp *) interp;
Tcl_NRAddCallback(interp, TryPostFinal, resultObj, options, cmdObj,
NULL);
/* The 'finally' script is always the last argument word. */
return TclNREvalObjEx(interp, finallyObj, 0, iPtr->cmdFramePtr,
finallyIndex);
}
|
| ︙ | ︙ | |||
5321 5322 5323 5324 5325 5326 5327 |
*----------------------------------------------------------------------
*/
int
Tcl_WhileObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 |
*----------------------------------------------------------------------
*/
int
Tcl_WhileObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRWhileObjCmd, clientData, objc, objv);
}
int
TclNRWhileObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
ForIterData *iterPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "test command");
return TCL_ERROR;
}
/*
* We reuse [for]'s callback, passing a NULL for the 'next' script.
*/
TclSmallAllocEx(interp, sizeof(ForIterData), iterPtr);
iterPtr->cond = objv[1];
iterPtr->body = objv[2];
iterPtr->next = NULL;
iterPtr->msg = "\n (\"while\" body line %d)";
iterPtr->word = 2;
TclNRAddCallback(interp, TclNRForIterCallback, iterPtr, NULL,
NULL, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclListLines --
|
| ︙ | ︙ | |||
5378 5379 5380 5381 5382 5383 5384 |
*/
void
TclListLines(
Tcl_Obj *listObj, /* Pointer to obj holding a string with list
* structure. Assumed to be valid. Assumed to
* contain n elements. */
| | | | | 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 |
*/
void
TclListLines(
Tcl_Obj *listObj, /* Pointer to obj holding a string with list
* structure. Assumed to be valid. Assumed to
* contain n elements. */
Tcl_Size line, /* Line the list as a whole starts on. */
Tcl_Size n, /* #elements in lines */
Tcl_Size *lines, /* Array of line numbers, to fill. */
Tcl_Obj *const *elems) /* The list elems as Tcl_Obj*, in need of
* derived continuation data */
{
const char *listStr = TclGetString(listObj);
const char *listHead = listStr;
Tcl_Size i, length = strlen(listStr);
const char *element = NULL, *next = NULL;
ContLineLoc *clLocPtr = TclContinuationsGet(listObj);
|
| ︙ | ︙ | |||
5412 5413 5414 5415 5416 5417 5418 |
if (*element == 0) {
/* ASSERT i == n */
break;
}
}
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 |
if (*element == 0) {
/* ASSERT i == n */
break;
}
}
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclCompCmds.c.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 | static AuxDataDupProc DupForeachInfo; static AuxDataFreeProc FreeForeachInfo; static AuxDataPrintProc PrintForeachInfo; static AuxDataPrintProc DisassembleForeachInfo; static AuxDataPrintProc PrintNewForeachInfo; static AuxDataPrintProc DisassembleNewForeachInfo; static int CompileEachloopCmd(Tcl_Interp *interp, | | | | < < < < < < | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
static AuxDataDupProc DupForeachInfo;
static AuxDataFreeProc FreeForeachInfo;
static AuxDataPrintProc PrintForeachInfo;
static AuxDataPrintProc DisassembleForeachInfo;
static AuxDataPrintProc PrintNewForeachInfo;
static AuxDataPrintProc DisassembleNewForeachInfo;
static int CompileEachloopCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
CompileEnv *envPtr, int collect);
static int CompileDictEachCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr, int collect);
/*
* The structures below define the AuxData types defined in this file.
*/
static const AuxDataType foreachInfoType = {
"ForeachInfo", /* name */
|
| ︙ | ︙ | |||
96 97 98 99 100 101 102 |
return &foreachInfoType;
} else if (!strcmp(typeName, newForeachInfoType.name)) {
return &newForeachInfoType;
} else if (!strcmp(typeName, dictUpdateInfoType.name)) {
return &dictUpdateInfoType;
} else if (!strcmp(typeName, tclJumptableInfoType.name)) {
return &tclJumptableInfoType;
| < < | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
return &foreachInfoType;
} else if (!strcmp(typeName, newForeachInfoType.name)) {
return &newForeachInfoType;
} else if (!strcmp(typeName, dictUpdateInfoType.name)) {
return &dictUpdateInfoType;
} else if (!strcmp(typeName, tclJumptableInfoType.name)) {
return &tclJumptableInfoType;
}
return NULL;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
131 132 133 134 135 136 137 |
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
| | < < > | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
int isScalar, localIndex, numWords, i;
/* TODO: Consider support for compiling expanded args. */
numWords = parsePtr->numWords;
if (numWords == 1) {
return TCL_ERROR;
} else if (numWords == 2) {
/*
* append varName == set varName
*/
return TclCompileSetCmd(interp, parsePtr, cmdPtr, envPtr);
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
* to emit code to compute and push the name at runtime. We use a frame
* slot (entry in the array of local vars) if we are compiling a procedure
* body and if the name is simple text that does not include namespace
* qualifiers.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
| < < < | > > | | | | | | | | | | | | | | | | | | | | | | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
* to emit code to compute and push the name at runtime. We use a frame
* slot (entry in the array of local vars) if we are compiling a procedure
* body and if the name is simple text that does not include namespace
* qualifiers.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, varTokenPtr, envPtr, 0,
&localIndex, &isScalar, 1);
/*
* We are doing an assignment, otherwise TclCompileSetCmd was called, so
* push the new value. This will need to be extended to push a value for
* each argument.
*/
valueTokenPtr = TokenAfter(varTokenPtr);
CompileWord(envPtr, valueTokenPtr, interp, 2);
/*
* Emit instructions to set/get the variable.
*/
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode(INST_APPEND_STK, envPtr);
} else {
Emit14Inst(INST_APPEND_SCALAR, localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode(INST_APPEND_ARRAY_STK, envPtr);
} else {
Emit14Inst(INST_APPEND_ARRAY, localIndex, envPtr);
}
}
return TCL_OK;
appendMultiple:
/*
* Can only handle the case where we are appending to a local scalar when
* there are multiple values to append. Fortunately, this is common.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
localIndex = LocalScalarFromToken(varTokenPtr, envPtr);
if (localIndex < 0) {
return TCL_ERROR;
}
/*
* Definitely appending to a local scalar; generate the words and append
* them.
*/
valueTokenPtr = TokenAfter(varTokenPtr);
for (i = 2 ; i < numWords ; i++) {
CompileWord(envPtr, valueTokenPtr, interp, i);
valueTokenPtr = TokenAfter(valueTokenPtr);
}
TclEmitInstInt4( INST_REVERSE, numWords-2, envPtr);
for (i = 2 ; i < numWords ;) {
Emit14Inst( INST_APPEND_SCALAR, localIndex, envPtr);
if (++i < numWords) {
TclEmitOpcode(INST_POP, envPtr);
}
}
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
258 259 260 261 262 263 264 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
| | < > | | | | > | | < > < | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int isScalar, localIndex;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT,
&localIndex, &isScalar, 1);
if (!isScalar) {
return TCL_ERROR;
}
if (localIndex >= 0) {
TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
} else {
TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
}
return TCL_OK;
}
int
TclCompileArraySetCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *dataTokenPtr;
int isScalar, localIndex, code = TCL_OK;
int isDataLiteral, isDataValid, isDataEven;
Tcl_Size len;
int keyVar, valVar, infoIndex;
int fwd, offsetBack, offsetFwd;
Tcl_Obj *literalObj;
ForeachInfo *infoPtr;
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
dataTokenPtr = TokenAfter(varTokenPtr);
|
| ︙ | ︙ | |||
324 325 326 327 328 329 330 | goto done; /* * We used to compile to the bytecode that would throw the error, * but that was wrong because it would not invoke the array trace * on the variable. * | | | | > | > | | < | | | < < | | | | < | < < > | < | | | | | | < < < | < | < | < | | | < | < | | | | > | | | | > | < > > | | | | | | | | | | | | < < > | | | | | > | | | | < | | < | < | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
goto done;
/*
* We used to compile to the bytecode that would throw the error,
* but that was wrong because it would not invoke the array trace
* on the variable.
*
PushStringLiteral(envPtr, "list must have an even number of elements");
PushStringLiteral(envPtr, "-errorcode {TCL ARGUMENT FORMAT}");
TclEmitInstInt4(INST_RETURN_IMM, TCL_ERROR, envPtr);
TclEmitInt4( 0, envPtr);
goto done;
*
*/
}
/*
* Except for the special "ensure array" case below, when we're not in
* a proc, we cannot do a better compile than generic.
*/
if ((varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) ||
(envPtr->procPtr == NULL && !(isDataEven && len == 0))) {
code = TclCompileBasic2ArgCmd(interp, parsePtr, cmdPtr, envPtr);
goto done;
}
PushVarNameWord(interp, varTokenPtr, envPtr, TCL_NO_ELEMENT,
&localIndex, &isScalar, 1);
if (!isScalar) {
code = TCL_ERROR;
goto done;
}
/*
* Special case: literal empty value argument is just an "ensure array"
* operation.
*/
if (isDataEven && len == 0) {
if (localIndex >= 0) {
TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
} else {
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
TclEmitInstInt1(INST_JUMP_TRUE1, 5, envPtr);
TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr);
TclEmitInstInt1(INST_JUMP1, 3, envPtr);
/* Each branch decrements stack depth, but we only take one. */
TclAdjustStackDepth(1, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
PushStringLiteral(envPtr, "");
goto done;
}
if (localIndex < 0) {
/*
* a non-local variable: upvar from a local one! This consumes the
* variable name that was left at stacktop.
*/
localIndex = TclFindCompiledLocal(varTokenPtr->start,
varTokenPtr->size, 1, envPtr);
PushStringLiteral(envPtr, "0");
TclEmitInstInt4(INST_REVERSE, 2, envPtr);
TclEmitInstInt4(INST_UPVAR, localIndex, envPtr);
TclEmitOpcode(INST_POP, envPtr);
}
/*
* Prepare for the internal foreach.
*/
keyVar = AnonymousLocal(envPtr);
valVar = AnonymousLocal(envPtr);
infoPtr = (ForeachInfo *)Tcl_Alloc(offsetof(ForeachInfo, varLists) + sizeof(ForeachVarList *));
infoPtr->numLists = 1;
infoPtr->varLists[0] = (ForeachVarList *)Tcl_Alloc(offsetof(ForeachVarList, varIndexes) + 2 * sizeof(Tcl_Size));
infoPtr->varLists[0]->numVars = 2;
infoPtr->varLists[0]->varIndexes[0] = keyVar;
infoPtr->varLists[0]->varIndexes[1] = valVar;
infoIndex = TclCreateAuxData(infoPtr, &newForeachInfoType, envPtr);
/*
* Start issuing instructions to write to the array.
*/
TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
TclEmitInstInt1(INST_JUMP_TRUE1, 7, envPtr);
TclEmitInstInt4(INST_ARRAY_MAKE_IMM, localIndex, envPtr);
CompileWord(envPtr, dataTokenPtr, interp, 2);
if (!isDataLiteral || !isDataValid) {
/*
* Only need this safety check if we're handling a non-literal or list
* containing an invalid literal; with valid list literals, we've
* already checked (worth it because literals are a very common
* use-case with [array set]).
*/
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
PushStringLiteral(envPtr, "1");
TclEmitOpcode( INST_BITAND, envPtr);
offsetFwd = CurrentOffset(envPtr);
TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
PushStringLiteral(envPtr, "list must have an even number of elements");
PushStringLiteral(envPtr, "-errorcode {TCL ARGUMENT FORMAT}");
TclEmitInstInt4(INST_RETURN_IMM, TCL_ERROR, envPtr);
TclEmitInt4( 0, envPtr);
TclAdjustStackDepth(-1, envPtr);
fwd = CurrentOffset(envPtr) - offsetFwd;
TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1);
}
TclEmitInstInt4(INST_FOREACH_START, infoIndex, envPtr);
offsetBack = CurrentOffset(envPtr);
Emit14Inst( INST_LOAD_SCALAR, keyVar, envPtr);
Emit14Inst( INST_LOAD_SCALAR, valVar, envPtr);
Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
infoPtr->loopCtTemp = offsetBack - CurrentOffset(envPtr); /*misuse */
TclEmitOpcode( INST_FOREACH_STEP, envPtr);
TclEmitOpcode( INST_FOREACH_END, envPtr);
TclAdjustStackDepth(-3, envPtr);
PushStringLiteral(envPtr, "");
done:
Tcl_DecrRefCount(literalObj);
return code;
}
int
TclCompileArrayUnsetCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
int isScalar, localIndex;
if (parsePtr->numWords != 2) {
return TclCompileBasic2ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
PushVarNameWord(interp, tokenPtr, envPtr, TCL_NO_ELEMENT,
&localIndex, &isScalar, 1);
if (!isScalar) {
return TCL_ERROR;
}
if (localIndex >= 0) {
TclEmitInstInt4(INST_ARRAY_EXISTS_IMM, localIndex, envPtr);
TclEmitInstInt1(INST_JUMP_FALSE1, 8, envPtr);
TclEmitInstInt1(INST_UNSET_SCALAR, 1, envPtr);
TclEmitInt4( localIndex, envPtr);
} else {
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_ARRAY_EXISTS_STK, envPtr);
TclEmitInstInt1(INST_JUMP_FALSE1, 6, envPtr);
TclEmitInstInt1(INST_UNSET_STK, 1, envPtr);
TclEmitInstInt1(INST_JUMP1, 3, envPtr);
/* Each branch decrements stack depth, but we only take one. */
TclAdjustStackDepth(1, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileBreakCmd --
|
| ︙ | ︙ | |||
557 558 559 560 561 562 563 |
TclCleanupStackForBreakContinue(envPtr, auxPtr);
TclAddLoopBreakFixup(envPtr, auxPtr);
} else {
/*
* Emit a real break.
*/
| | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 |
TclCleanupStackForBreakContinue(envPtr, auxPtr);
TclAddLoopBreakFixup(envPtr, auxPtr);
} else {
/*
* Emit a real break.
*/
TclEmitOpcode(INST_BREAK, envPtr);
}
TclAdjustStackDepth(1, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
591 592 593 594 595 596 597 598 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr;
| > < | < < | | | | | | | | | | | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
JumpFixup jumpFixup;
Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr;
int resultIndex, optsIndex, range, dropScript = 0;
int depth = TclGetStackDepth(envPtr);
/*
* If syntax does not match what we expect for [catch], do not compile.
* Let runtime checks determine if syntax has changed.
*/
if (((int)parsePtr->numWords < 2) || ((int)parsePtr->numWords > 4)) {
return TCL_ERROR;
}
/*
* If variables were specified and the catch command is at global level
* (not in a procedure), don't compile it inline: the payoff is too small.
*/
if (((int)parsePtr->numWords >= 3) && !EnvHasLVT(envPtr)) {
return TCL_ERROR;
}
/*
* Make sure the variable names, if any, have no substitutions and just
* refer to local scalars.
*/
resultIndex = optsIndex = -1;
cmdTokenPtr = TokenAfter(parsePtr->tokenPtr);
if ((int)parsePtr->numWords >= 3) {
resultNameTokenPtr = TokenAfter(cmdTokenPtr);
/* DGP */
resultIndex = LocalScalarFromToken(resultNameTokenPtr, envPtr);
if (resultIndex < 0) {
return TCL_ERROR;
}
/* DKF */
if (parsePtr->numWords == 4) {
optsNameTokenPtr = TokenAfter(resultNameTokenPtr);
optsIndex = LocalScalarFromToken(optsNameTokenPtr, envPtr);
if (optsIndex < 0) {
return TCL_ERROR;
}
}
}
/*
* We will compile the catch command. Declare the exception range that it
|
| ︙ | ︙ | |||
657 658 659 660 661 662 663 |
* Care has to be taken to make sure that substitution happens outside the
* catch range so that errors in the substitution are not caught.
* [Bug 219184]
* The reason for duplicating the script is that EVAL_STK would otherwise
* begin by underflowing the stack below the mark set by BEGIN_CATCH4.
*/
| | | | | < > | | < | > | < < > | > | | < | | > | < | | > > > | | | | | > > | > > > > > | > | | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 |
* Care has to be taken to make sure that substitution happens outside the
* catch range so that errors in the substitution are not caught.
* [Bug 219184]
* The reason for duplicating the script is that EVAL_STK would otherwise
* begin by underflowing the stack below the mark set by BEGIN_CATCH4.
*/
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
BODY(cmdTokenPtr, 1);
} else {
SetLineInformation(1);
CompileTokens(envPtr, cmdTokenPtr, interp);
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
TclEmitOpcode( INST_DUP, envPtr);
TclEmitInvoke(envPtr, INST_EVAL_STK);
/* drop the script */
dropScript = 1;
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
ExceptionRangeEnds(envPtr, range);
/*
* Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch result,
* and jump around the "error case" code.
*/
TclCheckStackDepth(depth+1, envPtr);
PushStringLiteral(envPtr, "0");
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
/*
* Emit the "error case" epilogue. Push the interpreter result and the
* return code.
*/
ExceptionRangeTarget(envPtr, range, catchOffset);
TclSetStackDepth(depth + dropScript, envPtr);
if (dropScript) {
TclEmitOpcode( INST_POP, envPtr);
}
/* Stack at this point is empty */
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr);
/* Stack at this point on both branches: result returnCode */
if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
Tcl_Panic("TclCompileCatchCmd: bad jump distance %" TCL_Z_MODIFIER "d",
(CurrentOffset(envPtr) - jumpFixup.codeOffset));
}
/*
* Push the return options if the caller wants them. This needs to happen
* before INST_END_CATCH
*/
if (optsIndex != -1) {
TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
}
/*
* End the catch
*/
TclEmitOpcode( INST_END_CATCH, envPtr);
/*
* Save the result and return options if the caller wants them. This needs
* to happen after INST_END_CATCH (compile-3.6/7).
*/
if (optsIndex != -1) {
Emit14Inst( INST_STORE_SCALAR, optsIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
/*
* At this point, the top of the stack is inconveniently ordered:
* result returnCode
* Reverse the stack to store the result.
*/
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
if (resultIndex != -1) {
Emit14Inst( INST_STORE_SCALAR, resultIndex, envPtr);
}
TclEmitOpcode( INST_POP, envPtr);
TclCheckStackDepth(depth+1, envPtr);
return TCL_OK;
}
/*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
771 772 773 774 775 776 777 |
Tcl_Token* tokenPtr;
switch (parsePtr->numWords) {
case 1:
/*
* No args
*/
| | > > > > | > | > | > | > < | 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 |
Tcl_Token* tokenPtr;
switch (parsePtr->numWords) {
case 1:
/*
* No args
*/
TclEmitInstInt1(INST_CLOCK_READ, 0, envPtr);
break;
case 2:
/*
* -milliseconds or -microseconds
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD
|| tokenPtr[1].size < 4
|| tokenPtr[1].size > 13) {
return TCL_ERROR;
} else if (!strncmp(tokenPtr[1].start, "-microseconds",
tokenPtr[1].size)) {
TclEmitInstInt1(INST_CLOCK_READ, 1, envPtr);
break;
} else if (!strncmp(tokenPtr[1].start, "-milliseconds",
tokenPtr[1].size)) {
TclEmitInstInt1(INST_CLOCK_READ, 2, envPtr);
break;
} else {
return TCL_ERROR;
}
default:
return TCL_ERROR;
}
return TCL_OK;
}
/*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
824 825 826 827 828 829 830 |
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
if (parsePtr->numWords != 1) {
return TCL_ERROR;
}
| | > | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 |
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
if (parsePtr->numWords != 1) {
return TCL_ERROR;
}
TclEmitInstInt1(INST_CLOCK_READ, PTR2INT(cmdPtr->objClientData), envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileConcatCmd --
|
| ︙ | ︙ | |||
855 856 857 858 859 860 861 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
| | < > | | < < | | | | | > > > > > | | | > > > | | > | < | | > | > | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Obj *objPtr, *listObj;
Tcl_Token *tokenPtr;
int i;
/* TODO: Consider compiling expansion case. */
if (parsePtr->numWords == 1) {
/*
* [concat] without arguments just pushes an empty object.
*/
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
* Test if all arguments are compile-time known. If they are, we can
* implement with a simple push.
*/
TclNewObj(listObj);
for (i = 1, tokenPtr = parsePtr->tokenPtr; i < (int)parsePtr->numWords; i++) {
tokenPtr = TokenAfter(tokenPtr);
TclNewObj(objPtr);
if (!TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
Tcl_DecrRefCount(objPtr);
Tcl_DecrRefCount(listObj);
listObj = NULL;
break;
}
(void) Tcl_ListObjAppendElement(NULL, listObj, objPtr);
}
if (listObj != NULL) {
Tcl_Obj **objs;
const char *bytes;
Tcl_Size len, slen;
TclListObjGetElements(NULL, listObj, &len, &objs);
objPtr = Tcl_ConcatObj(len, objs);
Tcl_DecrRefCount(listObj);
bytes = TclGetStringFromObj(objPtr, &slen);
PushLiteral(envPtr, bytes, slen);
Tcl_DecrRefCount(objPtr);
return TCL_OK;
}
/*
* General case: runtime concat.
*/
for (i = 1, tokenPtr = parsePtr->tokenPtr; i < (int)parsePtr->numWords; i++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
TclEmitInstInt4( INST_CONCAT_STK, i-1, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileConstCmd --
|
| ︙ | ︙ | |||
934 935 936 937 938 939 940 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
| | < > | | | | | | | 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
int isScalar, localIndex;
/*
* Need exactly two arguments.
*/
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
/*
* Decide if we can use a frame slot for the var/array name or if we need
* to emit code to compute and push the name at runtime. We use a frame
* slot (entry in the array of local vars) if we are compiling a procedure
* body and if the name is simple text that does not include namespace
* qualifiers.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, varTokenPtr, envPtr, 0,
&localIndex, &isScalar, 1);
/*
* If the user specified an array element, we don't bother handling
* that.
*/
if (!isScalar) {
return TCL_ERROR;
}
/*
* We are doing an assignment to set the value of the constant. This will
* need to be extended to push a value for each argument.
*/
valueTokenPtr = TokenAfter(varTokenPtr);
CompileWord(envPtr, valueTokenPtr, interp, 2);
if (localIndex < 0) {
TclEmitOpcode(INST_CONST_STK, envPtr);
} else {
TclEmitInstInt4(INST_CONST_IMM, localIndex, envPtr);
}
/*
* The const command's result is an empty string.
*/
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileContinueCmd --
|
| ︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 |
TclCleanupStackForBreakContinue(envPtr, auxPtr);
TclAddLoopContinueFixup(envPtr, auxPtr);
} else {
/*
* Emit a real continue.
*/
| | | | 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
TclCleanupStackForBreakContinue(envPtr, auxPtr);
TclAddLoopContinueFixup(envPtr, auxPtr);
} else {
/*
* Emit a real continue.
*/
TclEmitOpcode(INST_CONTINUE, envPtr);
}
TclAdjustStackDepth(1, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
| < | < | | | | | > | > | < | > > > | < < | < > > > > > > | | | | | > | | | | | > | | | | | > | | | | < < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | > | | > > | > > | < | | > | > | | | | > | | | | | | > | > | | > > > > > | > > > | | > | < | < | > > > > > > > < < | < | | | | | | | > | | | > > | | | | < | | | | | | | | > | | > | | | < | | | > | < > | > > | < > > | | | < < < < < < | < < < < < < < < < < < < < | < < < < < < | < < < < | < < < | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i, dictVarIndex;
Tcl_Token *varTokenPtr;
/*
* There must be at least one argument after the command.
*/
if ((int)parsePtr->numWords < 4) {
return TCL_ERROR;
}
/*
* The dictionary variable must be a local scalar that is knowable at
* compile time; anything else exceeds the complexity of the opcode. So
* discover what the index is.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
dictVarIndex = LocalScalarFromToken(varTokenPtr, envPtr);
if (dictVarIndex < 0) {
return TCL_ERROR;
}
/*
* Remaining words (key path and value to set) can be handled normally.
*/
tokenPtr = TokenAfter(varTokenPtr);
for (i=2 ; i< (int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
/*
* Now emit the instruction to do the dict manipulation.
*/
TclEmitInstInt4( INST_DICT_SET, (int)parsePtr->numWords-3, envPtr);
TclEmitInt4( dictVarIndex, envPtr);
TclAdjustStackDepth(-1, envPtr);
return TCL_OK;
}
int
TclCompileDictIncrCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *keyTokenPtr;
int dictVarIndex, incrAmount;
/*
* There must be at least two arguments after the command.
*/
if ((int)parsePtr->numWords < 3 || (int)parsePtr->numWords > 4) {
return TCL_ERROR;
}
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
keyTokenPtr = TokenAfter(varTokenPtr);
/*
* Parse the increment amount, if present.
*/
if (parsePtr->numWords == 4) {
const char *word;
Tcl_Size numBytes;
int code;
Tcl_Token *incrTokenPtr;
Tcl_Obj *intObj;
incrTokenPtr = TokenAfter(keyTokenPtr);
if (incrTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TclCompileBasic2Or3ArgCmd(interp, parsePtr,cmdPtr, envPtr);
}
word = incrTokenPtr[1].start;
numBytes = incrTokenPtr[1].size;
intObj = Tcl_NewStringObj(word, numBytes);
Tcl_IncrRefCount(intObj);
code = TclGetIntFromObj(NULL, intObj, &incrAmount);
TclDecrRefCount(intObj);
if (code != TCL_OK) {
return TclCompileBasic2Or3ArgCmd(interp, parsePtr,cmdPtr, envPtr);
}
} else {
incrAmount = 1;
}
/*
* The dictionary variable must be a local scalar that is knowable at
* compile time; anything else exceeds the complexity of the opcode. So
* discover what the index is.
*/
dictVarIndex = LocalScalarFromToken(varTokenPtr, envPtr);
if (dictVarIndex < 0) {
return TclCompileBasic2Or3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Emit the key and the code to actually do the increment.
*/
CompileWord(envPtr, keyTokenPtr, interp, 2);
TclEmitInstInt4( INST_DICT_INCR_IMM, incrAmount, envPtr);
TclEmitInt4( dictVarIndex, envPtr);
return TCL_OK;
}
int
TclCompileDictGetCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i;
/*
* There must be at least two arguments after the command (the single-arg
* case is legal, but too special and magic for us to deal with here).
*/
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords < 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
/*
* Only compile this because we need INST_DICT_GET anyway.
*/
for (i=1 ; i<(int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4(INST_DICT_GET, (int)parsePtr->numWords-2, envPtr);
TclAdjustStackDepth(-1, envPtr);
return TCL_OK;
}
int
TclCompileDictGetWithDefaultCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i;
/*
* There must be at least three arguments after the command.
*/
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords < 4) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
for (i=1 ; i<(int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4(INST_DICT_GET_DEF, (int)parsePtr->numWords-3, envPtr);
TclAdjustStackDepth(-2, envPtr);
return TCL_OK;
}
int
TclCompileDictExistsCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i;
/*
* There must be at least two arguments after the command (the single-arg
* case is legal, but too special and magic for us to deal with here).
*/
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords < 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
/*
* Now we do the code generation.
*/
for (i=1 ; i<(int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4(INST_DICT_EXISTS, (int)parsePtr->numWords-2, envPtr);
TclAdjustStackDepth(-1, envPtr);
return TCL_OK;
}
int
TclCompileDictUnsetCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i, dictVarIndex;
/*
* There must be at least one argument after the variable name for us to
* compile to bytecode.
*/
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords < 3) {
return TCL_ERROR;
}
/*
* The dictionary variable must be a local scalar that is knowable at
* compile time; anything else exceeds the complexity of the opcode. So
* discover what the index is.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
dictVarIndex = LocalScalarFromToken(tokenPtr, envPtr);
if (dictVarIndex < 0) {
return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Remaining words (the key path) can be handled normally.
*/
for (i=2 ; i<(int)parsePtr->numWords ; i++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
/*
* Now emit the instruction to do the dict manipulation.
*/
TclEmitInstInt4( INST_DICT_UNSET, (int)parsePtr->numWords-2, envPtr);
TclEmitInt4( dictVarIndex, envPtr);
return TCL_OK;
}
int
TclCompileDictCreateCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
int worker; /* Temp var for building the value in. */
Tcl_Token *tokenPtr;
Tcl_Obj *keyObj, *valueObj, *dictObj;
const char *bytes;
int i;
Tcl_Size len;
if ((parsePtr->numWords & 1) == 0) {
return TCL_ERROR;
}
/*
* See if we can build the value at compile time...
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
TclNewObj(dictObj);
Tcl_IncrRefCount(dictObj);
for (i=1 ; i<(int)parsePtr->numWords ; i+=2) {
TclNewObj(keyObj);
Tcl_IncrRefCount(keyObj);
if (!TclWordKnownAtCompileTime(tokenPtr, keyObj)) {
Tcl_DecrRefCount(keyObj);
Tcl_DecrRefCount(dictObj);
goto nonConstant;
}
tokenPtr = TokenAfter(tokenPtr);
TclNewObj(valueObj);
Tcl_IncrRefCount(valueObj);
if (!TclWordKnownAtCompileTime(tokenPtr, valueObj)) {
Tcl_DecrRefCount(keyObj);
Tcl_DecrRefCount(valueObj);
Tcl_DecrRefCount(dictObj);
goto nonConstant;
}
tokenPtr = TokenAfter(tokenPtr);
Tcl_DictObjPut(NULL, dictObj, keyObj, valueObj);
Tcl_DecrRefCount(keyObj);
Tcl_DecrRefCount(valueObj);
}
/*
* We did! Excellent. The "verifyDict" is to do type forcing.
*/
bytes = TclGetStringFromObj(dictObj, &len);
PushLiteral(envPtr, bytes, len);
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_DICT_VERIFY, envPtr);
Tcl_DecrRefCount(dictObj);
return TCL_OK;
/*
* Otherwise, we've got to issue runtime code to do the building, which we
* do by [dict set]ting into an unnamed local variable. This requires that
* we are in a context with an LVT.
*/
nonConstant:
worker = AnonymousLocal(envPtr);
if (worker < 0) {
return TclCompileBasicMin0ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
PushStringLiteral(envPtr, "");
Emit14Inst( INST_STORE_SCALAR, worker, envPtr);
TclEmitOpcode( INST_POP, envPtr);
tokenPtr = TokenAfter(parsePtr->tokenPtr);
for (i=1 ; i<(int)parsePtr->numWords ; i+=2) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i+1);
tokenPtr = TokenAfter(tokenPtr);
TclEmitInstInt4( INST_DICT_SET, 1, envPtr);
TclEmitInt4( worker, envPtr);
TclAdjustStackDepth(-1, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
Emit14Inst( INST_LOAD_SCALAR, worker, envPtr);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( worker, envPtr);
return TCL_OK;
}
int
TclCompileDictMergeCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i, workerIndex, infoIndex, outLoop;
/*
* Deal with some special edge cases. Note that in the case with one
* argument, the only thing to do is to verify the dict-ness.
*/
/* TODO: Consider support for compiling expanded args. (less likely) */
if ((int)parsePtr->numWords < 2) {
PushStringLiteral(envPtr, "");
return TCL_OK;
} else if (parsePtr->numWords == 2) {
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_DICT_VERIFY, envPtr);
return TCL_OK;
}
/*
* There's real merging work to do.
*
* Allocate some working space. This means we'll only ever compile this
* command when there's an LVT present.
*/
workerIndex = AnonymousLocal(envPtr);
if (workerIndex < 0) {
return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
infoIndex = AnonymousLocal(envPtr);
/*
* Get the first dictionary and verify that it is so.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_DICT_VERIFY, envPtr);
Emit14Inst( INST_STORE_SCALAR, workerIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
/*
* For each of the remaining dictionaries...
*/
outLoop = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, outLoop, envPtr);
ExceptionRangeStarts(envPtr, outLoop);
for (i=2 ; i<(int)parsePtr->numWords ; i++) {
/*
* Get the dictionary, and merge its pairs into the first dict (using
* a small loop).
*/
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
TclEmitInstInt4( INST_DICT_FIRST, infoIndex, envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, 24, envPtr);
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitInstInt4( INST_DICT_SET, 1, envPtr);
TclEmitInt4( workerIndex, envPtr);
TclAdjustStackDepth(-1, envPtr);
TclEmitOpcode( INST_POP, envPtr);
TclEmitInstInt4( INST_DICT_NEXT, infoIndex, envPtr);
TclEmitInstInt1( INST_JUMP_FALSE1, -20, envPtr);
TclEmitOpcode( INST_POP, envPtr);
TclEmitOpcode( INST_POP, envPtr);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( infoIndex, envPtr);
}
ExceptionRangeEnds(envPtr, outLoop);
TclEmitOpcode( INST_END_CATCH, envPtr);
/*
* Clean up any state left over.
*/
Emit14Inst( INST_LOAD_SCALAR, workerIndex, envPtr);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( workerIndex, envPtr);
TclEmitInstInt1( INST_JUMP1, 18, envPtr);
/*
* If an exception happens when starting to iterate over the second (and
* subsequent) dicts. This is strictly not necessary, but it is nice.
*/
TclAdjustStackDepth(-1, envPtr);
ExceptionRangeTarget(envPtr, outLoop, catchOffset);
TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( workerIndex, envPtr);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( infoIndex, envPtr);
TclEmitOpcode( INST_RETURN_STK, envPtr);
return TCL_OK;
}
int
TclCompileDictForCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
|
| ︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 |
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
return CompileDictEachCmd(interp, parsePtr, cmdPtr, envPtr,
TCL_EACH_COLLECT);
}
| | | | | < | > > < < < | | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 |
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
return CompileDictEachCmd(interp, parsePtr, cmdPtr, envPtr,
TCL_EACH_COLLECT);
}
int
CompileDictEachCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr, /* Holds resulting instructions. */
int collect) /* Flag == TCL_EACH_COLLECT to collect and
* construct a new dictionary with the loop
* body result. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varsTokenPtr, *dictTokenPtr, *bodyTokenPtr;
int keyVarIndex, valueVarIndex, nameChars, loopRange, catchRange;
int infoIndex, jumpDisplacement, bodyTargetOffset, emptyTargetOffset;
Tcl_Size numVars;
int endTargetOffset;
int collectVar = -1; /* Index of temp var holding the result
* dict. */
const char **argv;
Tcl_DString buffer;
/*
* There must be three arguments after the command.
*/
if (parsePtr->numWords != 4) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
varsTokenPtr = TokenAfter(parsePtr->tokenPtr);
dictTokenPtr = TokenAfter(varsTokenPtr);
bodyTokenPtr = TokenAfter(dictTokenPtr);
if (varsTokenPtr->type != TCL_TOKEN_SIMPLE_WORD ||
bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Create temporary variable to capture return values from loop body when
* we're collecting results.
*/
if (collect == TCL_EACH_COLLECT) {
collectVar = AnonymousLocal(envPtr);
if (collectVar < 0) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
}
/*
* Check we've got a pair of variables and that they are local variables.
* Then extract their indices in the LVT.
|
| ︙ | ︙ | |||
1800 1801 1802 1803 1804 1805 1806 |
Tcl_DStringFree(&buffer);
if (numVars != 2) {
Tcl_Free((void *)argv);
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
nameChars = strlen(argv[0]);
| | | | | | | | | | > | | | | > | | | | | | | | | | | | > | | | < | | | | | > > > | | | > > > | > > | | | > | < > > | | | | | > | > | > > | > > | | | | | | | > | | > | < < < < < < < < < < < < | < < > | | | | | | < | < | | | | | > | | < < | > > > | | | > | | | | | | | > | | > > > | | > > > > > > > > > > > > > | < > > > | | > > > > | > > > | > > > > > | > > > | < > > > > > > > > | < > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > > | | | > | | | | | < | < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < | < < < < | | | | | | | | > | | | | | > | < < < < < | | | | | | < < | < > > > > | | > | | | | | | > | < < < < < < | < < > > | | | | | | > | | | | | | > | < < < < < < | | < > > > > | 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 |
Tcl_DStringFree(&buffer);
if (numVars != 2) {
Tcl_Free((void *)argv);
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
nameChars = strlen(argv[0]);
keyVarIndex = LocalScalar(argv[0], nameChars, envPtr);
nameChars = strlen(argv[1]);
valueVarIndex = LocalScalar(argv[1], nameChars, envPtr);
Tcl_Free((void *)argv);
if ((keyVarIndex < 0) || (valueVarIndex < 0)) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Allocate a temporary variable to store the iterator reference. The
* variable will contain a Tcl_DictSearch reference which will be
* allocated by INST_DICT_FIRST and disposed when the variable is unset
* (at which point it should also have been finished with).
*/
infoIndex = AnonymousLocal(envPtr);
if (infoIndex < 0) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Preparation complete; issue instructions. Note that this code issues
* fixed-sized jumps. That simplifies things a lot!
*
* First up, initialize the accumulator dictionary if needed.
*/
if (collect == TCL_EACH_COLLECT) {
PushStringLiteral(envPtr, "");
Emit14Inst( INST_STORE_SCALAR, collectVar, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
/*
* Get the dictionary and start the iteration. No catching of errors at
* this point.
*/
CompileWord(envPtr, dictTokenPtr, interp, 2);
/*
* Now we catch errors from here on so that we can finalize the search
* started by Tcl_DictObjFirst above.
*/
catchRange = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, catchRange, envPtr);
ExceptionRangeStarts(envPtr, catchRange);
TclEmitInstInt4( INST_DICT_FIRST, infoIndex, envPtr);
emptyTargetOffset = CurrentOffset(envPtr);
TclEmitInstInt4( INST_JUMP_TRUE4, 0, envPtr);
/*
* Inside the iteration, write the loop variables.
*/
bodyTargetOffset = CurrentOffset(envPtr);
Emit14Inst( INST_STORE_SCALAR, keyVarIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
Emit14Inst( INST_STORE_SCALAR, valueVarIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
/*
* Set up the loop exception targets.
*/
loopRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
ExceptionRangeStarts(envPtr, loopRange);
/*
* Compile the loop body itself. It should be stack-neutral.
*/
BODY(bodyTokenPtr, 3);
if (collect == TCL_EACH_COLLECT) {
Emit14Inst( INST_LOAD_SCALAR, keyVarIndex, envPtr);
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitInstInt4(INST_DICT_SET, 1, envPtr);
TclEmitInt4( collectVar, envPtr);
TclAdjustStackDepth(-1, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
TclEmitOpcode( INST_POP, envPtr);
/*
* Both exception target ranges (error and loop) end here.
*/
ExceptionRangeEnds(envPtr, loopRange);
ExceptionRangeEnds(envPtr, catchRange);
/*
* Continue (or just normally process) by getting the next pair of items
* from the dictionary and jumping back to the code to write them into
* variables if there is another pair.
*/
ExceptionRangeTarget(envPtr, loopRange, continueOffset);
TclEmitInstInt4( INST_DICT_NEXT, infoIndex, envPtr);
jumpDisplacement = bodyTargetOffset - CurrentOffset(envPtr);
TclEmitInstInt4( INST_JUMP_FALSE4, jumpDisplacement, envPtr);
endTargetOffset = CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP1, 0, envPtr);
/*
* Error handler "finally" clause, which force-terminates the iteration
* and re-throws the error.
*/
TclAdjustStackDepth(-1, envPtr);
ExceptionRangeTarget(envPtr, catchRange, catchOffset);
TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( infoIndex, envPtr);
if (collect == TCL_EACH_COLLECT) {
TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( collectVar, envPtr);
}
TclEmitOpcode( INST_RETURN_STK, envPtr);
/*
* Otherwise we're done (the jump after the DICT_FIRST points here) and we
* need to pop the bogus key/value pair (pushed to keep stack calculations
* easy!) Note that we skip the END_CATCH. [Bug 1382528]
*/
jumpDisplacement = CurrentOffset(envPtr) - emptyTargetOffset;
TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDisplacement,
envPtr->codeStart + emptyTargetOffset);
jumpDisplacement = CurrentOffset(envPtr) - endTargetOffset;
TclUpdateInstInt1AtPc(INST_JUMP1, jumpDisplacement,
envPtr->codeStart + endTargetOffset);
TclEmitOpcode( INST_POP, envPtr);
TclEmitOpcode( INST_POP, envPtr);
ExceptionRangeTarget(envPtr, loopRange, breakOffset);
TclFinalizeLoopExceptionRange(envPtr, loopRange);
TclEmitOpcode( INST_END_CATCH, envPtr);
/*
* Final stage of the command (normal case) is that we push an empty
* object (or push the accumulator as the result object). This is done
* last to promote peephole optimization when it's dropped immediately.
*/
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( infoIndex, envPtr);
if (collect == TCL_EACH_COLLECT) {
Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr);
TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( collectVar, envPtr);
} else {
PushStringLiteral(envPtr, "");
}
return TCL_OK;
}
int
TclCompileDictUpdateCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
int i, dictIndex, numVars, range, infoIndex;
Tcl_Token **keyTokenPtrs, *dictVarTokenPtr, *bodyTokenPtr, *tokenPtr;
DictUpdateInfo *duiPtr;
JumpFixup jumpFixup;
/*
* There must be at least one argument after the command.
*/
if ((int)parsePtr->numWords < 5) {
return TCL_ERROR;
}
/*
* Parse the command. Expect the following:
* dict update <lit(eral)> <any> <lit> ?<any> <lit> ...? <lit>
*/
if (((int)parsePtr->numWords - 1) & 1) {
return TCL_ERROR;
}
numVars = (parsePtr->numWords - 3) / 2;
/*
* The dictionary variable must be a local scalar that is knowable at
* compile time; anything else exceeds the complexity of the opcode. So
* discover what the index is.
*/
dictVarTokenPtr = TokenAfter(parsePtr->tokenPtr);
dictIndex = LocalScalarFromToken(dictVarTokenPtr, envPtr);
if (dictIndex < 0) {
goto issueFallback;
}
/*
* Assemble the instruction metadata. This is complex enough that it is
* represented as auxData; it holds an ordered list of variable indices
* that are to be used.
*/
duiPtr = (DictUpdateInfo *)Tcl_Alloc(offsetof(DictUpdateInfo, varIndices) + sizeof(size_t) * numVars);
duiPtr->length = numVars;
keyTokenPtrs = (Tcl_Token **)TclStackAlloc(interp, sizeof(Tcl_Token *) * numVars);
tokenPtr = TokenAfter(dictVarTokenPtr);
for (i=0 ; i<numVars ; i++) {
/*
* Put keys to one side for later compilation to bytecode.
*/
keyTokenPtrs[i] = tokenPtr;
tokenPtr = TokenAfter(tokenPtr);
/*
* Stash the index in the auxiliary data (if it is indeed a local
* scalar that is resolvable at compile-time).
*/
duiPtr->varIndices[i] = LocalScalarFromToken(tokenPtr, envPtr);
if (duiPtr->varIndices[i] == TCL_INDEX_NONE) {
goto failedUpdateInfoAssembly;
}
tokenPtr = TokenAfter(tokenPtr);
}
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
goto failedUpdateInfoAssembly;
}
bodyTokenPtr = tokenPtr;
/*
* The list of variables to bind is stored in auxiliary data so that it
* can't be snagged by literal sharing and forced to shimmer dangerously.
*/
infoIndex = TclCreateAuxData(duiPtr, &dictUpdateInfoType, envPtr);
for (i=0 ; i<numVars ; i++) {
CompileWord(envPtr, keyTokenPtrs[i], interp, 2*i+2);
}
TclEmitInstInt4( INST_LIST, numVars, envPtr);
TclEmitInstInt4( INST_DICT_UPDATE_START, dictIndex, envPtr);
TclEmitInt4( infoIndex, envPtr);
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
BODY(bodyTokenPtr, parsePtr->numWords - 1);
ExceptionRangeEnds(envPtr, range);
/*
* Normal termination code: the stack has the key list below the result of
* the body evaluation: swap them and finish the update code.
*/
TclEmitOpcode( INST_END_CATCH, envPtr);
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitInstInt4( INST_DICT_UPDATE_END, dictIndex, envPtr);
TclEmitInt4( infoIndex, envPtr);
/*
* Jump around the exceptional termination code.
*/
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
/*
* Termination code for non-ok returns: stash the result and return
* options in the stack, bring up the key list, finish the update code,
* and finally return with the caught return data
*/
ExceptionRangeTarget(envPtr, range, catchOffset);
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
TclEmitInstInt4( INST_DICT_UPDATE_END, dictIndex, envPtr);
TclEmitInt4( infoIndex, envPtr);
TclEmitInvoke(envPtr,INST_RETURN_STK);
if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
Tcl_Panic("TclCompileDictCmd(update): bad jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - jumpFixup.codeOffset);
}
TclStackFree(interp, keyTokenPtrs);
return TCL_OK;
/*
* Clean up after a failure to create the DictUpdateInfo structure.
*/
failedUpdateInfoAssembly:
Tcl_Free(duiPtr);
TclStackFree(interp, keyTokenPtrs);
issueFallback:
return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
int
TclCompileDictAppendCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i, dictVarIndex;
/*
* There must be at least two argument after the command. And we impose an
* (arbitrary) safe limit; anyone exceeding it should stop worrying about
* speed quite so much. ;-)
*/
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords<4 || (int)parsePtr->numWords>100) {
return TCL_ERROR;
}
/*
* Get the index of the local variable that we will be working with.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
dictVarIndex = LocalScalarFromToken(tokenPtr, envPtr);
if (dictVarIndex < 0) {
return TclCompileBasicMin2ArgCmd(interp, parsePtr,cmdPtr, envPtr);
}
/*
* Produce the string to concatenate onto the dictionary entry.
*/
tokenPtr = TokenAfter(tokenPtr);
for (i=2 ; i<(int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
if ((int)parsePtr->numWords > 4) {
TclEmitInstInt1(INST_STR_CONCAT1, (int)parsePtr->numWords-3, envPtr);
}
/*
* Do the concatenation.
*/
TclEmitInstInt4(INST_DICT_APPEND, dictVarIndex, envPtr);
return TCL_OK;
}
int
TclCompileDictLappendCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *keyTokenPtr, *valueTokenPtr;
int dictVarIndex;
/*
* There must be three arguments after the command.
*/
/* TODO: Consider support for compiling expanded args. */
/* Probably not. Why is INST_DICT_LAPPEND limited to one value? */
if (parsePtr->numWords != 4) {
return TCL_ERROR;
}
/*
* Parse the arguments.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
keyTokenPtr = TokenAfter(varTokenPtr);
valueTokenPtr = TokenAfter(keyTokenPtr);
dictVarIndex = LocalScalarFromToken(varTokenPtr, envPtr);
if (dictVarIndex < 0) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Issue the implementation.
*/
CompileWord(envPtr, keyTokenPtr, interp, 2);
CompileWord(envPtr, valueTokenPtr, interp, 3);
TclEmitInstInt4( INST_DICT_LAPPEND, dictVarIndex, envPtr);
return TCL_OK;
}
int
TclCompileDictWithCmd(
Tcl_Interp *interp, /* Used for looking up stuff. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
int i, range, varNameTmp = -1, pathTmp = -1, keysTmp, gotPath;
int dictVar, bodyIsEmpty = 1;
Tcl_Token *varTokenPtr, *tokenPtr;
JumpFixup jumpFixup;
const char *ptr, *end;
/*
* There must be at least one argument after the command.
*/
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords < 3) {
return TCL_ERROR;
}
/*
* Parse the command (trivially). Expect the following:
* dict with <any (varName)> ?<any> ...? <literal>
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
tokenPtr = TokenAfter(varTokenPtr);
for (i=3 ; i<(int)parsePtr->numWords ; i++) {
tokenPtr = TokenAfter(tokenPtr);
}
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Test if the last word is an empty script; if so, we can compile it in
* all cases, but if it is non-empty we need local variable table entries
* to hold the temporary variables (used to keep stack usage simple).
*/
for (ptr=tokenPtr[1].start,end=ptr+tokenPtr[1].size ; ptr!=end ; ptr++) {
if (*ptr!=' ' && *ptr!='\t' && *ptr!='\n' && *ptr!='\r') {
if (envPtr->procPtr == NULL) {
return TclCompileBasicMin2ArgCmd(interp, parsePtr, cmdPtr,
envPtr);
}
bodyIsEmpty = 0;
break;
}
}
/*
* Determine if we're manipulating a dict in a simple local variable.
*/
gotPath = ((int)parsePtr->numWords > 3);
dictVar = LocalScalarFromToken(varTokenPtr, envPtr);
/*
* Special case: an empty body means we definitely have no need to issue
* try-finally style code or to allocate local variable table entries for
* storing temporaries. Still need to do both INST_DICT_EXPAND and
* INST_DICT_RECOMBINE_* though, because we can't determine if we're free
* of traces.
*/
if (bodyIsEmpty) {
if (dictVar >= 0) {
if (gotPath) {
/*
* Case: Path into dict in LVT with empty body.
*/
tokenPtr = TokenAfter(varTokenPtr);
for (i=2 ; i<(int)parsePtr->numWords-1 ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4(INST_LIST, (int)parsePtr->numWords-3,envPtr);
Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr);
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitOpcode( INST_DICT_EXPAND, envPtr);
TclEmitInstInt4(INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
} else {
/*
* Case: Direct dict in LVT with empty body.
*/
PushStringLiteral(envPtr, "");
Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr);
PushStringLiteral(envPtr, "");
TclEmitOpcode( INST_DICT_EXPAND, envPtr);
TclEmitInstInt4(INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
}
} else {
if (gotPath) {
/*
* Case: Path into dict in non-simple var with empty body.
*/
tokenPtr = varTokenPtr;
for (i=1 ; i<(int)parsePtr->numWords-1 ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4(INST_LIST, (int)parsePtr->numWords-3,envPtr);
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitOpcode( INST_LOAD_STK, envPtr);
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitOpcode( INST_DICT_EXPAND, envPtr);
TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
} else {
/*
* Case: Direct dict in non-simple var with empty body.
*/
CompileWord(envPtr, varTokenPtr, interp, 1);
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LOAD_STK, envPtr);
PushStringLiteral(envPtr, "");
TclEmitOpcode( INST_DICT_EXPAND, envPtr);
PushStringLiteral(envPtr, "");
TclEmitInstInt4(INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
}
}
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
* OK, we have a non-trivial body. This means that the focus is on
* generating a try-finally structure where the INST_DICT_RECOMBINE_* goes
* in the 'finally' clause.
*
* Start by allocating local (unnamed, untraced) working variables.
*/
if (dictVar == -1) {
varNameTmp = AnonymousLocal(envPtr);
}
if (gotPath) {
pathTmp = AnonymousLocal(envPtr);
}
keysTmp = AnonymousLocal(envPtr);
/*
* Issue instructions. First, the part to expand the dictionary.
*/
if (dictVar == -1) {
CompileWord(envPtr, varTokenPtr, interp, 1);
Emit14Inst( INST_STORE_SCALAR, varNameTmp, envPtr);
}
tokenPtr = TokenAfter(varTokenPtr);
if (gotPath) {
for (i=2 ; i<(int)parsePtr->numWords-1 ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4( INST_LIST, (int)parsePtr->numWords-3,envPtr);
Emit14Inst( INST_STORE_SCALAR, pathTmp, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
if (dictVar == -1) {
TclEmitOpcode( INST_LOAD_STK, envPtr);
} else {
Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr);
}
if (gotPath) {
Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr);
} else {
PushStringLiteral(envPtr, "");
}
TclEmitOpcode( INST_DICT_EXPAND, envPtr);
Emit14Inst( INST_STORE_SCALAR, keysTmp, envPtr);
TclEmitOpcode( INST_POP, envPtr);
/*
* Now the body of the [dict with].
*/
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
BODY(tokenPtr, parsePtr->numWords - 1);
ExceptionRangeEnds(envPtr, range);
/*
* Now fold the results back into the dictionary in the OK case.
*/
TclEmitOpcode( INST_END_CATCH, envPtr);
if (dictVar == -1) {
Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr);
}
if (gotPath) {
Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr);
} else {
PushStringLiteral(envPtr, "");
}
Emit14Inst( INST_LOAD_SCALAR, keysTmp, envPtr);
if (dictVar == -1) {
TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
} else {
TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
}
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
/*
* Now fold the results back into the dictionary in the exception case.
*/
TclAdjustStackDepth(-1, envPtr);
ExceptionRangeTarget(envPtr, range, catchOffset);
TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr);
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
if (dictVar == -1) {
Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr);
}
if ((int)parsePtr->numWords > 3) {
Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr);
} else {
PushStringLiteral(envPtr, "");
}
Emit14Inst( INST_LOAD_SCALAR, keysTmp, envPtr);
if (dictVar == -1) {
TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr);
} else {
TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr);
}
TclEmitInvoke(envPtr, INST_RETURN_STK);
/*
* Prepare for the start of the next command.
*/
if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
Tcl_Panic("TclCompileDictCmd(update): bad jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - jumpFixup.codeOffset);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* DupDictUpdateInfo, FreeDictUpdateInfo --
|
| ︙ | ︙ | |||
2482 2483 2484 2485 2486 2487 2488 |
DupDictUpdateInfo(
void *clientData)
{
DictUpdateInfo *dui1Ptr, *dui2Ptr;
size_t len;
dui1Ptr = (DictUpdateInfo *)clientData;
| | < | 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 |
DupDictUpdateInfo(
void *clientData)
{
DictUpdateInfo *dui1Ptr, *dui2Ptr;
size_t len;
dui1Ptr = (DictUpdateInfo *)clientData;
len = offsetof(DictUpdateInfo, varIndices) + sizeof(size_t) * dui1Ptr->length;
dui2Ptr = (DictUpdateInfo *)Tcl_Alloc(len);
memcpy(dui2Ptr, dui1Ptr, len);
return dui2Ptr;
}
static void
FreeDictUpdateInfo(
|
| ︙ | ︙ | |||
2507 2508 2509 2510 2511 2512 2513 |
TCL_UNUSED(ByteCode *),
TCL_UNUSED(size_t))
{
DictUpdateInfo *duiPtr = (DictUpdateInfo *)clientData;
Tcl_Size i;
for (i=0 ; i<duiPtr->length ; i++) {
| > | < > | | 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 |
TCL_UNUSED(ByteCode *),
TCL_UNUSED(size_t))
{
DictUpdateInfo *duiPtr = (DictUpdateInfo *)clientData;
Tcl_Size i;
for (i=0 ; i<duiPtr->length ; i++) {
if (i) {
Tcl_AppendToObj(appendObj, ", ", -1);
}
Tcl_AppendPrintfToObj(appendObj, "%%v%" TCL_Z_MODIFIER "u", duiPtr->varIndices[i]);
}
}
static void
DisassembleDictUpdateInfo(
void *clientData,
Tcl_Obj *dictObj,
|
| ︙ | ︙ | |||
2560 2561 2562 2563 2564 2565 2566 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
| < | | < | > > > < | < | > > > < | < > | > | 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
/*
* General syntax: [error message ?errorInfo? ?errorCode?]
*/
if ((int)parsePtr->numWords < 2 || (int)parsePtr->numWords > 4) {
return TCL_ERROR;
}
/*
* Handle the message.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
/*
* Construct the options. Note that -code and -level are not here.
*/
if (parsePtr->numWords == 2) {
PushStringLiteral(envPtr, "");
} else {
PushStringLiteral(envPtr, "-errorinfo");
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
if (parsePtr->numWords == 3) {
TclEmitInstInt4( INST_LIST, 2, envPtr);
} else {
PushStringLiteral(envPtr, "-errorcode");
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
TclEmitInstInt4( INST_LIST, 4, envPtr);
}
}
/*
* Issue the error via 'returnImm error 0'.
*/
TclEmitInstInt4( INST_RETURN_IMM, TCL_ERROR, envPtr);
TclEmitInt4( 0, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileExprCmd --
|
| ︙ | ︙ | |||
2631 2632 2633 2634 2635 2636 2637 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Token *firstWordPtr;
| | | | | 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Token *firstWordPtr;
if (parsePtr->numWords == 1) {
return TCL_ERROR;
}
/*
* TIP #280: Use the per-word line information of the current command.
*/
envPtr->line = envPtr->extCmdMapPtr->loc[
envPtr->extCmdMapPtr->nuloc-1].line[1];
firstWordPtr = TokenAfter(parsePtr->tokenPtr);
TclCompileExprWords(interp, firstWordPtr, (int)parsePtr->numWords-1, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileForCmd --
|
| ︙ | ︙ | |||
2675 2676 2677 2678 2679 2680 2681 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *startTokenPtr, *testTokenPtr, *nextTokenPtr, *bodyTokenPtr;
| > > | < | 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *startTokenPtr, *testTokenPtr, *nextTokenPtr, *bodyTokenPtr;
JumpFixup jumpEvalCondFixup;
int bodyCodeOffset, nextCodeOffset, jumpDist;
int bodyRange, nextRange;
if (parsePtr->numWords != 5) {
return TCL_ERROR;
}
/*
* If the test expression requires substitutions, don't compile the for
|
| ︙ | ︙ | |||
2710 2711 2712 2713 2714 2715 2716 |
return TCL_ERROR;
}
/*
* Inline compile the initial command.
*/
| | | | | < | | < > | < < | | | | < > | < > > > > | > | | > > > > > > | | | | < | > > > > > | | 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 |
return TCL_ERROR;
}
/*
* Inline compile the initial command.
*/
BODY(startTokenPtr, 1);
TclEmitOpcode(INST_POP, envPtr);
/*
* Jump to the evaluation of the condition. This code uses the "loop
* rotation" optimisation (which eliminates one branch from the loop).
* "for start cond next body" produces then:
* start
* goto A
* B: body : bodyCodeOffset
* next : nextCodeOffset, continueOffset
* A: cond -> result : testCodeOffset
* if (result) goto B
*/
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
/*
* Compile the loop body.
*/
bodyRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
bodyCodeOffset = ExceptionRangeStarts(envPtr, bodyRange);
BODY(bodyTokenPtr, 4);
ExceptionRangeEnds(envPtr, bodyRange);
TclEmitOpcode(INST_POP, envPtr);
/*
* Compile the "next" subcommand. Note that this exception range will not
* have a continueOffset (other than -1) connected to it; it won't trap
* TCL_CONTINUE but rather just TCL_BREAK.
*/
nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
envPtr->exceptAuxArrayPtr[nextRange].supportsContinue = 0;
nextCodeOffset = ExceptionRangeStarts(envPtr, nextRange);
BODY(nextTokenPtr, 3);
ExceptionRangeEnds(envPtr, nextRange);
TclEmitOpcode(INST_POP, envPtr);
/*
* Compile the test expression then emit the conditional jump that
* terminates the for.
*/
if (TclFixupForwardJumpToHere(envPtr, &jumpEvalCondFixup, 127)) {
bodyCodeOffset += 3;
nextCodeOffset += 3;
}
SetLineInformation(2);
TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
if (jumpDist > 127) {
TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
} else {
TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
}
/*
* Fix the starting points of the exception ranges (may have moved due to
* jump type modification) and set where the exceptions target.
*/
envPtr->exceptArrayPtr[bodyRange].codeOffset = bodyCodeOffset;
envPtr->exceptArrayPtr[bodyRange].continueOffset = nextCodeOffset;
envPtr->exceptArrayPtr[nextRange].codeOffset = nextCodeOffset;
ExceptionRangeTarget(envPtr, bodyRange, breakOffset);
ExceptionRangeTarget(envPtr, nextRange, breakOffset);
TclFinalizeLoopExceptionRange(envPtr, bodyRange);
TclFinalizeLoopExceptionRange(envPtr, nextRange);
/*
* The for command's result is an empty string.
*/
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileForeachCmd --
|
| ︙ | ︙ | |||
2806 2807 2808 2809 2810 2811 2812 |
*/
int
TclCompileForeachCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
| | > | > | 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 |
*/
int
TclCompileForeachCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
return CompileEachloopCmd(interp, parsePtr, cmdPtr, envPtr,
TCL_EACH_KEEP_NONE);
}
/*
*----------------------------------------------------------------------
*
* TclCompileLmapCmd --
*
|
| ︙ | ︙ | |||
2835 2836 2837 2838 2839 2840 2841 |
*/
int
TclCompileLmapCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
| | > | > | 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 |
*/
int
TclCompileLmapCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to the definition of the command
* being compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
return CompileEachloopCmd(interp, parsePtr, cmdPtr, envPtr,
TCL_EACH_COLLECT);
}
/*
*----------------------------------------------------------------------
*
* CompileEachloopCmd --
*
|
| ︙ | ︙ | |||
2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 |
*/
static int
CompileEachloopCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
CompileEnv *envPtr, /* Holds resulting instructions. */
int collect) /* Select collecting or accumulating mode
* (TCL_EACH_*) */
{
DefineLineInformation; /* TIP #280 */
ForeachInfo *infoPtr=NULL; /* Points to the structure describing this
* foreach command. Stored in a AuxData
* record in the ByteCode. */
Tcl_Token *tokenPtr, *bodyTokenPtr;
| > > | < < | > | | | | 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 |
*/
static int
CompileEachloopCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr, /* Holds resulting instructions. */
int collect) /* Select collecting or accumulating mode
* (TCL_EACH_*) */
{
DefineLineInformation; /* TIP #280 */
Proc *procPtr = envPtr->procPtr;
ForeachInfo *infoPtr=NULL; /* Points to the structure describing this
* foreach command. Stored in a AuxData
* record in the ByteCode. */
Tcl_Token *tokenPtr, *bodyTokenPtr;
int jumpBackOffset, infoIndex, range;
int numWords, numLists, i, code = TCL_OK;
Tcl_Size j;
Tcl_Obj *varListObj = NULL;
/*
* If the foreach command isn't in a procedure, don't compile it inline:
* the payoff is too small.
*/
if (procPtr == NULL) {
return TCL_ERROR;
}
numWords = (int)parsePtr->numWords;
if ((numWords < 4) || (numWords%2 != 0)) {
return TCL_ERROR;
}
/*
* Bail out if the body requires substitutions in order to ensure correct
* behaviour. [Bug 219166]
*/
|
| ︙ | ︙ | |||
2951 2952 2953 2954 2955 2956 2957 | code = TCL_ERROR; goto done; } varListPtr = (ForeachVarList *)Tcl_Alloc(offsetof(ForeachVarList, varIndexes) + numVars * sizeof(varListPtr->varIndexes[0])); varListPtr->numVars = numVars; | | | | | | | | | | | > | < | | | | | | | | < < | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 |
code = TCL_ERROR;
goto done;
}
varListPtr = (ForeachVarList *)Tcl_Alloc(offsetof(ForeachVarList, varIndexes)
+ numVars * sizeof(varListPtr->varIndexes[0]));
varListPtr->numVars = numVars;
infoPtr->varLists[i/2] = varListPtr;
infoPtr->numLists++;
for (j = 0; j < numVars; j++) {
Tcl_Obj *varNameObj;
const char *bytes;
int varIndex;
Tcl_Size length;
Tcl_ListObjIndex(NULL, varListObj, j, &varNameObj);
bytes = TclGetStringFromObj(varNameObj, &length);
varIndex = LocalScalar(bytes, length, envPtr);
if (varIndex < 0) {
code = TCL_ERROR;
goto done;
}
varListPtr->varIndexes[j] = varIndex;
}
Tcl_SetObjLength(varListObj, 0);
}
/*
* We will compile the foreach command.
*/
infoIndex = TclCreateAuxData(infoPtr, &newForeachInfoType, envPtr);
/*
* Create the collecting object, unshared.
*/
if (collect == TCL_EACH_COLLECT) {
TclEmitInstInt4(INST_LIST, 0, envPtr);
}
/*
* Evaluate each value list and leave it on stack.
*/
for (i = 0, tokenPtr = parsePtr->tokenPtr;
i < numWords-1;
i++, tokenPtr = TokenAfter(tokenPtr)) {
if ((i%2 == 0) && (i > 0)) {
CompileWord(envPtr, tokenPtr, interp, i);
}
}
TclEmitInstInt4(INST_FOREACH_START, infoIndex, envPtr);
/*
* Inline compile the loop body.
*/
range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
ExceptionRangeStarts(envPtr, range);
BODY(bodyTokenPtr, numWords - 1);
ExceptionRangeEnds(envPtr, range);
if (collect == TCL_EACH_COLLECT) {
TclEmitOpcode(INST_LMAP_COLLECT, envPtr);
} else {
TclEmitOpcode( INST_POP, envPtr);
}
/*
* Bottom of loop code: assign each loop variable and check whether
* to terminate the loop. Set the loop's break target.
*/
ExceptionRangeTarget(envPtr, range, continueOffset);
TclEmitOpcode(INST_FOREACH_STEP, envPtr);
ExceptionRangeTarget(envPtr, range, breakOffset);
TclFinalizeLoopExceptionRange(envPtr, range);
TclEmitOpcode(INST_FOREACH_END, envPtr);
TclAdjustStackDepth(-(numLists+2), envPtr);
/*
* Set the jumpback distance from INST_FOREACH_STEP to the start of the
* body's code. Misuse loopCtTemp for storing the jump size.
*/
jumpBackOffset = envPtr->exceptArrayPtr[range].continueOffset -
envPtr->exceptArrayPtr[range].codeOffset;
infoPtr->loopCtTemp = -jumpBackOffset;
/*
* The command's result is an empty string if not collecting. If
* collecting, it is automatically left on stack after FOREACH_END.
*/
if (collect != TCL_EACH_COLLECT) {
PushStringLiteral(envPtr, "");
}
done:
if (code == TCL_ERROR) {
FreeForeachInfo(infoPtr);
}
Tcl_DecrRefCount(varListObj);
return code;
}
|
| ︙ | ︙ | |||
3289 3290 3291 3292 3293 3294 3295 | * the new ForeachInfo record. * *---------------------------------------------------------------------- */ static void * DupForeachInfo( | | | | 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 |
* the new ForeachInfo record.
*
*----------------------------------------------------------------------
*/
static void *
DupForeachInfo(
void *clientData) /* The foreach command's compilation auxiliary
* data to duplicate. */
{
ForeachInfo *srcPtr = (ForeachInfo *)clientData;
ForeachInfo *dupPtr;
ForeachVarList *srcListPtr, *dupListPtr;
int numVars, i, j, numLists = srcPtr->numLists;
dupPtr = (ForeachInfo *)Tcl_Alloc(offsetof(ForeachInfo, varLists)
+ numLists * sizeof(ForeachVarList *));
dupPtr->numLists = numLists;
dupPtr->firstValueTemp = srcPtr->firstValueTemp;
dupPtr->loopCtTemp = srcPtr->loopCtTemp;
|
| ︙ | ︙ | |||
3338 3339 3340 3341 3342 3343 3344 | * ForeachInfo structure. * *---------------------------------------------------------------------- */ static void FreeForeachInfo( | | | | 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 |
* ForeachInfo structure.
*
*----------------------------------------------------------------------
*/
static void
FreeForeachInfo(
void *clientData) /* The foreach command's compilation auxiliary
* data to free. */
{
ForeachInfo *infoPtr = (ForeachInfo *)clientData;
ForeachVarList *listPtr;
size_t i, numLists = infoPtr->numLists;
for (i = 0; i < numLists; i++) {
listPtr = infoPtr->varLists[i];
Tcl_Free(listPtr);
}
Tcl_Free(infoPtr);
}
|
| ︙ | ︙ | |||
3380 3381 3382 3383 3384 3385 3386 |
TCL_UNUSED(ByteCode *),
TCL_UNUSED(size_t))
{
ForeachInfo *infoPtr = (ForeachInfo *)clientData;
ForeachVarList *varsPtr;
Tcl_Size i, j;
| | | | | | | | | | | 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 |
TCL_UNUSED(ByteCode *),
TCL_UNUSED(size_t))
{
ForeachInfo *infoPtr = (ForeachInfo *)clientData;
ForeachVarList *varsPtr;
Tcl_Size i, j;
Tcl_AppendToObj(appendObj, "data=[", -1);
for (i=0 ; i<infoPtr->numLists ; i++) {
if (i) {
Tcl_AppendToObj(appendObj, ", ", -1);
}
Tcl_AppendPrintfToObj(appendObj, "%%v%" TCL_Z_MODIFIER "u",
(infoPtr->firstValueTemp + i));
}
Tcl_AppendPrintfToObj(appendObj, "], loop=%%v%" TCL_Z_MODIFIER "u",
infoPtr->loopCtTemp);
for (i=0 ; i<infoPtr->numLists ; i++) {
if (i) {
Tcl_AppendToObj(appendObj, ",", -1);
}
Tcl_AppendPrintfToObj(appendObj, "\n\t\t it%%v%" TCL_Z_MODIFIER "u\t[",
(infoPtr->firstValueTemp + i));
varsPtr = infoPtr->varLists[i];
for (j=0 ; j<varsPtr->numVars ; j++) {
if (j) {
Tcl_AppendToObj(appendObj, ", ", -1);
}
Tcl_AppendPrintfToObj(appendObj, "%%v%" TCL_Z_MODIFIER "u",
varsPtr->varIndexes[j]);
}
Tcl_AppendToObj(appendObj, "]", -1);
}
}
static void
PrintNewForeachInfo(
void *clientData,
Tcl_Obj *appendObj,
TCL_UNUSED(ByteCode *),
TCL_UNUSED(size_t))
{
ForeachInfo *infoPtr = (ForeachInfo *)clientData;
ForeachVarList *varsPtr;
Tcl_Size i, j;
Tcl_AppendPrintfToObj(appendObj, "jumpOffset=%+" TCL_Z_MODIFIER "d, vars=",
infoPtr->loopCtTemp);
for (i=0 ; i<infoPtr->numLists ; i++) {
if (i) {
Tcl_AppendToObj(appendObj, ",", -1);
}
Tcl_AppendToObj(appendObj, "[", -1);
varsPtr = infoPtr->varLists[i];
for (j=0 ; j<varsPtr->numVars ; j++) {
if (j) {
Tcl_AppendToObj(appendObj, ",", -1);
}
Tcl_AppendPrintfToObj(appendObj, "%%v%" TCL_Z_MODIFIER "u",
varsPtr->varIndexes[j]);
}
Tcl_AppendToObj(appendObj, "]", -1);
}
}
static void
DisassembleForeachInfo(
void *clientData,
Tcl_Obj *dictObj,
|
| ︙ | ︙ | |||
3552 3553 3554 3555 3556 3557 3558 |
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Obj **objv, *formatObj, *tmpObj;
const char *bytes, *start;
| > | < < | | < | | > | | > > | | | 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 |
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Obj **objv, *formatObj, *tmpObj;
const char *bytes, *start;
int i, j;
Tcl_Size len;
/*
* Don't handle any guaranteed-error cases.
*/
if ((int)parsePtr->numWords < 2) {
return TCL_ERROR;
}
/*
* Check if the argument words are all compile-time-known literals; that's
* a case we can handle by compiling to a constant.
*/
TclNewObj(formatObj);
Tcl_IncrRefCount(formatObj);
tokenPtr = TokenAfter(tokenPtr);
if (!TclWordKnownAtCompileTime(tokenPtr, formatObj)) {
Tcl_DecrRefCount(formatObj);
return TCL_ERROR;
}
objv = (Tcl_Obj **)Tcl_Alloc(((int)parsePtr->numWords-2) * sizeof(Tcl_Obj *));
for (i=0 ; i+2 < (int)parsePtr->numWords ; i++) {
tokenPtr = TokenAfter(tokenPtr);
TclNewObj(objv[i]);
Tcl_IncrRefCount(objv[i]);
if (!TclWordKnownAtCompileTime(tokenPtr, objv[i])) {
goto checkForStringConcatCase;
}
}
/*
* Everything is a literal, so the result is constant too (or an error if
* the format is broken). Do the format now.
*/
tmpObj = Tcl_Format(interp, TclGetString(formatObj),
(int)parsePtr->numWords-2, objv);
for (; --i>=0 ;) {
Tcl_DecrRefCount(objv[i]);
}
Tcl_Free(objv);
Tcl_DecrRefCount(formatObj);
if (tmpObj == NULL) {
TclCompileSyntaxError(interp, envPtr);
return TCL_OK;
}
/*
* Not an error, always a constant result, so just push the result as a
* literal. Job done.
*/
bytes = TclGetStringFromObj(tmpObj, &len);
PushLiteral(envPtr, bytes, len);
Tcl_DecrRefCount(tmpObj);
return TCL_OK;
checkForStringConcatCase:
/*
* See if we can generate a sequence of things to concatenate. This
* requires that all the % sequences be %s or %%, as everything else is
* sufficiently complex that we don't bother.
*
* First, get the state of the system relatively sensible (cleaning up
* after our attempt to spot a literal).
*/
for (; i>=0 ; i--) {
Tcl_DecrRefCount(objv[i]);
}
Tcl_Free(objv);
tokenPtr = TokenAfter(parsePtr->tokenPtr);
tokenPtr = TokenAfter(tokenPtr);
i = 0;
/*
* Now scan through and check for non-%s and non-%% substitutions.
*/
|
| ︙ | ︙ | |||
3652 3653 3654 3655 3656 3657 3658 |
}
}
/*
* Check if the number of things to concatenate will fit in a byte.
*/
| | | > > | > | | | | > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 |
}
}
/*
* Check if the number of things to concatenate will fit in a byte.
*/
if (i+2 != (int)parsePtr->numWords || i > 125) {
Tcl_DecrRefCount(formatObj);
return TCL_ERROR;
}
/*
* Generate the pushes of the things to concatenate, a sequence of
* literals and compiled tokens (of which at least one is non-literal or
* we'd have the case in the first half of this function) which we will
* concatenate.
*/
i = 0; /* The count of things to concat. */
j = 2; /* The index into the argument tokens, for
* TIP#280 handling. */
start = TclGetString(formatObj);
/* The start of the currently-scanned literal
* in the format string. */
TclNewObj(tmpObj); /* The buffer used to accumulate the literal
* being built. */
for (bytes = start ; *bytes ; bytes++) {
if (*bytes == '%') {
Tcl_AppendToObj(tmpObj, start, bytes - start);
if (*++bytes == '%') {
Tcl_AppendToObj(tmpObj, "%", 1);
} else {
const char *b = TclGetStringFromObj(tmpObj, &len);
/*
* If there is a non-empty literal from the format string,
* push it and reset.
*/
if (len > 0) {
PushLiteral(envPtr, b, len);
Tcl_DecrRefCount(tmpObj);
TclNewObj(tmpObj);
i++;
}
/*
* Push the code to produce the string that would be
* substituted with %s, except we'll be concatenating
* directly.
*/
CompileWord(envPtr, tokenPtr, interp, j);
tokenPtr = TokenAfter(tokenPtr);
j++;
i++;
}
start = bytes + 1;
}
}
/*
* Handle the case of a trailing literal.
*/
Tcl_AppendToObj(tmpObj, start, bytes - start);
bytes = TclGetStringFromObj(tmpObj, &len);
if (len > 0) {
PushLiteral(envPtr, bytes, len);
i++;
}
Tcl_DecrRefCount(tmpObj);
Tcl_DecrRefCount(formatObj);
if (i > 1) {
/*
* Do the concatenation, which produces the result.
*/
TclEmitInstInt1(INST_STR_CONCAT1, i, envPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclLocalScalarFromToken --
*
* Get the index into the table of compiled locals that corresponds
* to a local scalar variable name.
*
* Results:
* Returns the non-negative integer index value into the table of
* compiled locals corresponding to a local scalar variable name.
* If the arguments passed in do not identify a local scalar variable
* then return TCL_INDEX_NONE.
*
* Side effects:
* May add an entry into the table of compiled locals.
*
*----------------------------------------------------------------------
*/
size_t
TclLocalScalarFromToken(
Tcl_Token *tokenPtr,
CompileEnv *envPtr)
{
int isScalar, index;
TclPushVarName(NULL, tokenPtr, envPtr, TCL_NO_ELEMENT, &index, &isScalar);
if (!isScalar) {
index = -1;
}
return index;
}
size_t
TclLocalScalar(
const char *bytes,
size_t numBytes,
CompileEnv *envPtr)
{
Tcl_Token token[2] = {
{TCL_TOKEN_SIMPLE_WORD, NULL, 0, 1},
{TCL_TOKEN_TEXT, NULL, 0, 0}
};
token[1].start = bytes;
token[1].size = numBytes;
return TclLocalScalarFromToken(token, envPtr);
}
/*
*----------------------------------------------------------------------
*
* TclPushVarName --
*
* Procedure used in the compiling where pushing a variable name is
* necessary (append, lappend, set).
*
* Results:
* The values written to *localIndexPtr and *isScalarPtr signal to
* the caller what the instructions emitted by this routine will do:
*
* *isScalarPtr (*localIndexPtr < 0)
* 1 1 Push the varname on the stack. (Stack +1)
* 1 0 *localIndexPtr is the index of the compiled
* local for this varname. No instructions
* emitted. (Stack +0)
* 0 1 Push part1 and part2 names of array element
* on the stack. (Stack +2)
* 0 0 *localIndexPtr is the index of the compiled
* local for this array. Element name is pushed
* on the stack. (Stack +1)
*
* Side effects:
* Instructions are added to envPtr.
*
*----------------------------------------------------------------------
*/
void
TclPushVarName(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Token *varTokenPtr, /* Points to a variable token. */
CompileEnv *envPtr, /* Holds resulting instructions. */
int flags, /* TCL_NO_LARGE_INDEX | TCL_NO_ELEMENT. */
int *localIndexPtr, /* Must not be NULL. */
int *isScalarPtr) /* Must not be NULL. */
{
const char *p;
const char *last, *name, *elName;
Tcl_Size n;
Tcl_Token *elemTokenPtr = NULL;
size_t nameLen, elNameLen;
int simpleVarName, localIndex;
Tcl_Size elemTokenCount = 0, removedParen = 0;
int allocedTokens = 0;
/*
* Decide if we can use a frame slot for the var/array name or if we need
* to emit code to compute and push the name at runtime. We use a frame
* slot (entry in the array of local vars) if we are compiling a procedure
* body and if the name is simple text that does not include namespace
* qualifiers.
*/
simpleVarName = 0;
name = elName = NULL;
nameLen = elNameLen = 0;
localIndex = -1;
if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
/*
* A simple variable name. Divide it up into "name" and "elName"
* strings. If it is not a local variable, look it up at runtime.
*/
simpleVarName = 1;
name = varTokenPtr[1].start;
nameLen = varTokenPtr[1].size;
if (nameLen > 0 && name[nameLen-1] == ')') {
/*
* last char is ')' => potential array reference.
*/
last = &name[nameLen-1];
if (*last == ')') {
for (p = name; p < last; p++) {
if (*p == '(') {
elName = p + 1;
elNameLen = last - elName;
nameLen = p - name;
break;
}
}
}
if (!(flags & TCL_NO_ELEMENT) && elNameLen) {
/*
* An array element, the element name is a simple string:
* assemble the corresponding token.
*/
elemTokenPtr = (Tcl_Token *)TclStackAlloc(interp, sizeof(Tcl_Token));
allocedTokens = 1;
elemTokenPtr->type = TCL_TOKEN_TEXT;
elemTokenPtr->start = elName;
elemTokenPtr->size = elNameLen;
elemTokenPtr->numComponents = 0;
elemTokenCount = 1;
}
}
} else if (interp && ((n = varTokenPtr->numComponents) > 1)
&& (varTokenPtr[1].type == TCL_TOKEN_TEXT)
&& (varTokenPtr[n].type == TCL_TOKEN_TEXT)
&& (*(varTokenPtr[n].start + varTokenPtr[n].size - 1) == ')')) {
/*
* Check for parentheses inside first token.
*/
simpleVarName = 0;
for (p = varTokenPtr[1].start, last = p + varTokenPtr[1].size;
p < last; p++) {
if (*p == '(') {
simpleVarName = 1;
break;
}
}
if (simpleVarName) {
size_t remainingLen;
/*
* Check the last token: if it is just ')', do not count it.
* Otherwise, remove the ')' and flag so that it is restored at
* the end.
*/
if (varTokenPtr[n].size == 1) {
n--;
} else {
varTokenPtr[n].size--;
removedParen = n;
}
name = varTokenPtr[1].start;
nameLen = p - varTokenPtr[1].start;
elName = p + 1;
remainingLen = (varTokenPtr[2].start - p) - 1;
elNameLen = (varTokenPtr[n].start-p) + varTokenPtr[n].size - 1;
if (!(flags & TCL_NO_ELEMENT)) {
if (remainingLen) {
/*
* Make a first token with the extra characters in the first
* token.
*/
elemTokenPtr = (Tcl_Token *)TclStackAlloc(interp, n * sizeof(Tcl_Token));
allocedTokens = 1;
elemTokenPtr->type = TCL_TOKEN_TEXT;
elemTokenPtr->start = elName;
elemTokenPtr->size = remainingLen;
elemTokenPtr->numComponents = 0;
elemTokenCount = n;
/*
* Copy the remaining tokens.
*/
memcpy(elemTokenPtr+1, varTokenPtr+2,
(n-1) * sizeof(Tcl_Token));
} else {
/*
* Use the already available tokens.
*/
elemTokenPtr = &varTokenPtr[2];
elemTokenCount = n - 1;
}
}
}
}
if (simpleVarName) {
/*
* See whether name has any namespace separators (::'s).
*/
int hasNsQualifiers = 0;
for (p = name, last = p + nameLen-1; p < last; p++) {
if ((p[0] == ':') && (p[1] == ':')) {
hasNsQualifiers = 1;
break;
}
}
/*
* Look up the var name's index in the array of local vars in the proc
* frame. If retrieving the var's value and it doesn't already exist,
* push its name and look it up at runtime.
*/
if (!hasNsQualifiers) {
localIndex = TclFindCompiledLocal(name, nameLen, 1, envPtr);
if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
/*
* We'll push the name.
*/
localIndex = -1;
}
}
if (interp && localIndex < 0) {
PushLiteral(envPtr, name, nameLen);
}
/*
* Compile the element script, if any, and only if not inhibited. [Bug
* 3600328]
*/
if (elName != NULL && !(flags & TCL_NO_ELEMENT)) {
if (elNameLen) {
TclCompileTokens(interp, elemTokenPtr, elemTokenCount,
envPtr);
} else {
PushStringLiteral(envPtr, "");
}
}
} else if (interp) {
/*
* The var name isn't simple: compile and push it.
*/
CompileTokens(envPtr, varTokenPtr, interp);
}
if (removedParen) {
varTokenPtr[removedParen].size++;
}
if (allocedTokens) {
TclStackFree(interp, elemTokenPtr);
}
*localIndexPtr = localIndex;
*isScalarPtr = (elName == NULL);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclCompCmdsGR.c.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" | < | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" /* * Prototypes for procedures defined later in this file: */ static void CompileReturnInternal(CompileEnv *envPtr, unsigned char op, int code, int level, Tcl_Obj *returnOpts); static int IndexTailVarIfKnown(Tcl_Interp *interp, Tcl_Token *varTokenPtr, CompileEnv *envPtr); /* *---------------------------------------------------------------------- * * TclGetIndexFromToken -- * |
| ︙ | ︙ | |||
54 55 56 57 58 59 60 |
int *indexPtr)
{
Tcl_Obj *tmpObj;
int result = TCL_ERROR;
TclNewObj(tmpObj);
if (TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
| | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
int *indexPtr)
{
Tcl_Obj *tmpObj;
int result = TCL_ERROR;
TclNewObj(tmpObj);
if (TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
result = TclIndexEncode(NULL, tmpObj, before, after, indexPtr);
}
Tcl_DecrRefCount(tmpObj);
return result;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr;
| | < > > | | | | | | | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr;
int localIndex, numWords, i;
/* TODO: Consider support for compiling expanded args. */
numWords = parsePtr->numWords;
if (numWords < 2) {
return TCL_ERROR;
}
/*
* 'global' has no effect outside of proc bodies; handle that at runtime
*/
if (envPtr->procPtr == NULL) {
return TCL_ERROR;
}
/*
* Push the namespace
*/
PushStringLiteral(envPtr, "::");
/*
* Loop over the variables.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
for (i=1; i<numWords; varTokenPtr = TokenAfter(varTokenPtr),i++) {
localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);
if (localIndex < 0) {
return TCL_ERROR;
}
/*
* 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);
}
/*
* Pop the namespace, and set the result to empty
*/
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileIfCmd --
|
| ︙ | ︙ | |||
175 176 177 178 179 180 181 |
/* Used to fix the ifFalse jump after each
* test when its target PC is determined. */
JumpFixupArray jumpEndFixupArray;
/* Used to fix the jump after each "then" body
* to the end of the "if" when that PC is
* determined. */
Tcl_Token *tokenPtr, *testTokenPtr;
| | > | | | | | | > < < < | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
/* Used to fix the ifFalse jump after each
* test when its target PC is determined. */
JumpFixupArray jumpEndFixupArray;
/* Used to fix the jump after each "then" body
* to the end of the "if" when that PC is
* determined. */
Tcl_Token *tokenPtr, *testTokenPtr;
int jumpIndex = 0; /* Avoid compiler warning. */
size_t numBytes, j;
int jumpFalseDist, numWords, wordIdx, code;
const char *word;
int realCond = 1; /* Set to 0 for static conditions:
* "if 0 {..}" */
int boolVal; /* Value of static condition. */
int compileScripts = 1;
/*
* Only compile the "if" command if all arguments are simple words, in
* order to insure correct substitution [Bug 219166]
*/
tokenPtr = parsePtr->tokenPtr;
wordIdx = 0;
numWords = parsePtr->numWords;
for (wordIdx = 0; wordIdx < numWords; wordIdx++) {
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(tokenPtr);
}
|
| ︙ | ︙ | |||
217 218 219 220 221 222 223 224 |
tokenPtr = parsePtr->tokenPtr;
wordIdx = 0;
while (wordIdx < numWords) {
/*
* Stop looping if the token isn't "if" or "elseif".
*/
if ((tokenPtr == parsePtr->tokenPtr)
| > > | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
tokenPtr = parsePtr->tokenPtr;
wordIdx = 0;
while (wordIdx < numWords) {
/*
* Stop looping if the token isn't "if" or "elseif".
*/
word = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
if ((tokenPtr == parsePtr->tokenPtr)
|| ((numBytes == 6) && (strncmp(word, "elseif", 6) == 0))) {
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
} else {
break;
}
if (wordIdx >= numWords) {
code = TCL_ERROR;
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 |
testTokenPtr = tokenPtr;
if (realCond) {
/*
* Find out if the condition is a constant.
*/
| | > > > | | | > | | > > | > > | | | | | > | | > > > > | | | > > > > > > > | | | | > > | | | | > > > > > > > > > > > > > > > > > > > > > | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
testTokenPtr = tokenPtr;
if (realCond) {
/*
* Find out if the condition is a constant.
*/
Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start,
testTokenPtr[1].size);
Tcl_IncrRefCount(boolObj);
code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
TclDecrRefCount(boolObj);
if (code == TCL_OK) {
/*
* A static condition.
*/
realCond = 0;
if (!boolVal) {
compileScripts = 0;
}
} else {
SetLineInformation(wordIdx);
Tcl_ResetResult(interp);
TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) {
TclExpandJumpFixupArray(&jumpFalseFixupArray);
}
jumpIndex = jumpFalseFixupArray.next;
jumpFalseFixupArray.next++;
TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
jumpFalseFixupArray.fixup + jumpIndex);
}
code = TCL_OK;
}
/*
* Skip over the optional "then" before the then clause.
*/
tokenPtr = TokenAfter(testTokenPtr);
wordIdx++;
if (wordIdx >= numWords) {
code = TCL_ERROR;
goto done;
}
if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
word = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
if ((numBytes == 4) && (strncmp(word, "then", 4) == 0)) {
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
if (wordIdx >= numWords) {
code = TCL_ERROR;
goto done;
}
}
}
/*
* Compile the "then" command body.
*/
if (compileScripts) {
BODY(tokenPtr, wordIdx);
}
if (realCond) {
/*
* Jump to the end of the "if" command. Both jumpFalseFixupArray
* and jumpEndFixupArray are indexed by "jumpIndex".
*/
if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
TclExpandJumpFixupArray(&jumpEndFixupArray);
}
jumpEndFixupArray.next++;
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
jumpEndFixupArray.fixup + jumpIndex);
/*
* Fix the target of the jumpFalse after the test. Generate a 4
* byte jump if the distance is > 120 bytes. This is conservative,
* and ensures that we won't have to replace this jump if we later
* also need to replace the proceeding jump to the end of the "if"
* with a 4 byte jump.
*/
TclAdjustStackDepth(-1, envPtr);
if (TclFixupForwardJumpToHere(envPtr,
jumpFalseFixupArray.fixup + jumpIndex, 120)) {
/*
* Adjust the code offset for the proceeding jump to the end
* of the "if" command.
*/
jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
}
} else if (boolVal) {
/*
* We were processing an "if 1 {...}"; stop compiling scripts.
*/
compileScripts = 0;
} else {
/*
* We were processing an "if 0 {...}"; reset so that the rest
* (elseif, else) is compiled correctly.
*/
realCond = 1;
compileScripts = 1;
}
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
}
/*
* Check for the optional else clause. Do not compile anything if this was
* an "if 1 {...}" case.
*/
if ((wordIdx < numWords) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
/*
* There is an else clause. Skip over the optional "else" word.
*/
word = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
if ((numBytes == 4) && (strncmp(word, "else", 4) == 0)) {
tokenPtr = TokenAfter(tokenPtr);
wordIdx++;
if (wordIdx >= numWords) {
code = TCL_ERROR;
goto done;
}
}
if (compileScripts) {
/*
* Compile the else command body.
*/
BODY(tokenPtr, wordIdx);
}
/*
* Make sure there are no words after the else clause.
*/
wordIdx++;
if (wordIdx < numWords) {
code = TCL_ERROR;
goto done;
}
} else {
/*
* No else clause: the "if" command's result is an empty string.
*/
if (compileScripts) {
PushStringLiteral(envPtr, "");
}
}
/*
* Fix the unconditional jumps to the end of the "if" command.
*/
for (j = jumpEndFixupArray.next; j > 0; j--) {
jumpIndex = (j - 1); /* i.e. process the closest jump first. */
if (TclFixupForwardJumpToHere(envPtr,
jumpEndFixupArray.fixup + jumpIndex, 127)) {
/*
* Adjust the immediately preceding "ifFalse" jump. We moved it's
* target (just after this jump) down three bytes.
*/
unsigned char *ifFalsePc = envPtr->codeStart
+ jumpFalseFixupArray.fixup[jumpIndex].codeOffset;
unsigned char opCode = *ifFalsePc;
if (opCode == INST_JUMP_FALSE1) {
jumpFalseDist = TclGetInt1AtPtr(ifFalsePc + 1);
jumpFalseDist += 3;
TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
} else if (opCode == INST_JUMP_FALSE4) {
jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
jumpFalseDist += 3;
TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
} else {
Tcl_Panic("TclCompileIfCmd: unexpected opcode \"%d\" updating ifFalse jump", opCode);
}
}
}
/*
* Free the jumpFixupArray array if malloc'ed storage was used.
*/
done:
|
| ︙ | ︙ | |||
427 428 429 430 431 432 433 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *incrTokenPtr;
| | < < < < | > > < > > > | > | > | < | | > > > | | > | | | | > | | | | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *incrTokenPtr;
int isScalar, localIndex, haveImmValue;
Tcl_WideInt immValue;
if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
return TCL_ERROR;
}
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, varTokenPtr, envPtr, TCL_NO_LARGE_INDEX,
&localIndex, &isScalar, 1);
/*
* If an increment is given, push it, but see first if it's a small
* integer.
*/
haveImmValue = 0;
immValue = 1;
if (parsePtr->numWords == 3) {
incrTokenPtr = TokenAfter(varTokenPtr);
if (incrTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
const char *word = incrTokenPtr[1].start;
size_t numBytes = incrTokenPtr[1].size;
int code;
Tcl_Obj *intObj = Tcl_NewStringObj(word, numBytes);
Tcl_IncrRefCount(intObj);
code = TclGetWideIntFromObj(NULL, intObj, &immValue);
if ((code == TCL_OK) && (-127 <= immValue) && (immValue <= 127)) {
haveImmValue = 1;
}
TclDecrRefCount(intObj);
if (!haveImmValue) {
PushLiteral(envPtr, word, numBytes);
}
} else {
SetLineInformation(2);
CompileTokens(envPtr, incrTokenPtr, interp);
}
} else { /* No incr amount given so use 1. */
haveImmValue = 1;
}
/*
* Emit the instruction to increment the variable.
*/
if (isScalar) { /* Simple scalar variable. */
if (localIndex >= 0) {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_SCALAR1_IMM, localIndex, envPtr);
TclEmitInt1(immValue, envPtr);
} else {
TclEmitInstInt1(INST_INCR_SCALAR1, localIndex, envPtr);
}
} else {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr);
} else {
TclEmitOpcode( INST_INCR_STK, envPtr);
}
}
} else { /* Simple array variable. */
if (localIndex >= 0) {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_ARRAY1_IMM, localIndex, envPtr);
TclEmitInt1(immValue, envPtr);
} else {
TclEmitInstInt1(INST_INCR_ARRAY1, localIndex, envPtr);
}
} else {
if (haveImmValue) {
TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immValue, envPtr);
} else {
TclEmitOpcode( INST_INCR_ARRAY_STK, envPtr);
}
}
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
535 536 537 538 539 540 541 |
* compiled. */
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
Tcl_Obj *objPtr;
const char *bytes;
| < | 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
* compiled. */
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
Tcl_Obj *objPtr;
const char *bytes;
/*
* We require one compile-time known argument for the case we can compile.
*/
if (parsePtr->numWords == 1) {
return TclCompileBasic0ArgCmd(interp, parsePtr, cmdPtr, envPtr);
|
| ︙ | ︙ | |||
571 572 573 574 575 576 577 |
/*
* Confirmed as a literal that will not frighten the horses. Compile.
* The result must be made into a list.
*/
/* TODO: Just push the known value */
| | | | | | | < | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 |
/*
* Confirmed as a literal that will not frighten the horses. Compile.
* The result must be made into a list.
*/
/* TODO: Just push the known value */
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_STR_LEN, envPtr);
TclEmitInstInt1( INST_JUMP_FALSE1, 7, envPtr);
TclEmitInstInt4( INST_LIST, 1, envPtr);
return TCL_OK;
notCompilable:
Tcl_DecrRefCount(objPtr);
return TclCompileBasic1ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
|
| ︙ | ︙ | |||
605 606 607 608 609 610 611 |
return TCL_ERROR;
}
/*
* Not much to do; we compile to a single instruction...
*/
| | | < | < < < | | | | | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
return TCL_ERROR;
}
/*
* Not much to do; we compile to a single instruction...
*/
TclEmitOpcode( INST_COROUTINE_NAME, envPtr);
return TCL_OK;
}
int
TclCompileInfoExistsCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int isScalar, localIndex;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
/*
* Decide if we can use a frame slot for the var/array name or if we need
* to emit code to compute and push the name at runtime. We use a frame
* slot (entry in the array of local vars) if we are compiling a procedure
* body and if the name is simple text that does not include namespace
* qualifiers.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, tokenPtr, envPtr, 0, &localIndex, &isScalar, 1);
/*
* Emit instruction to check the variable for existence.
*/
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_EXIST_STK, envPtr);
} else {
TclEmitInstInt4( INST_EXIST_SCALAR, localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_EXIST_ARRAY_STK, envPtr);
} else {
TclEmitInstInt4( INST_EXIST_ARRAY, localIndex, envPtr);
}
}
return TCL_OK;
}
int
|
| ︙ | ︙ | |||
678 679 680 681 682 683 684 |
*/
if (parsePtr->numWords == 1) {
/*
* Not much to do; we compile to a single instruction...
*/
| | | | < < < < | < < < < < < < < < < | < < < < < | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 |
*/
if (parsePtr->numWords == 1) {
/*
* Not much to do; we compile to a single instruction...
*/
TclEmitOpcode( INST_INFO_LEVEL_NUM, envPtr);
} else if (parsePtr->numWords != 2) {
return TCL_ERROR;
} else {
DefineLineInformation; /* TIP #280 */
/*
* Compile the argument, then add the instruction to convert it into a
* list of arguments.
*/
CompileWord(envPtr, TokenAfter(parsePtr->tokenPtr), interp, 1);
TclEmitOpcode( INST_INFO_LEVEL_ARGS, envPtr);
}
return TCL_OK;
}
int
TclCompileInfoObjectClassCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_TCLOO_CLASS, envPtr);
return TCL_OK;
}
int
TclCompileInfoObjectIsACmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
|
| ︙ | ︙ | |||
753 754 755 756 757 758 759 |
* words are compressed to a single token by the ensemble compilation
* engine.
*/
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
| > | | | | | | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 |
* words are compressed to a single token by the ensemble compilation
* engine.
*/
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size < 1
|| strncmp(tokenPtr[1].start, "object", tokenPtr[1].size)) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(tokenPtr);
/*
* Issue the code.
*/
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode( INST_TCLOO_IS_OBJECT, envPtr);
return TCL_OK;
}
int
TclCompileInfoObjectNamespaceCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_TCLOO_NS, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileLappendCmd --
|
| ︙ | ︙ | |||
814 815 816 817 818 819 820 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
| < | < > > | > > > > < < < | | < < < | < < | < | > > | | | < < < < < < < < < < < < < < | > | > | | | | < < < | < < < < | < < < < | < < < < < | | | < < < < < < < < | < < < < < < < < < < < < < < < < < | | < < < < < < < | < < < < < < | | | | | 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
int isScalar, localIndex, numWords, i;
/* TODO: Consider support for compiling expanded args. */
numWords = parsePtr->numWords;
if (numWords < 3) {
return TCL_ERROR;
}
if (numWords != 3 || envPtr->procPtr == NULL) {
goto lappendMultiple;
}
/*
* Decide if we can use a frame slot for the var/array name or if we
* need to emit code to compute and push the name at runtime. We use a
* frame slot (entry in the array of local vars) if we are compiling a
* procedure body and if the name is simple text that does not include
* namespace qualifiers.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, varTokenPtr, envPtr, 0,
&localIndex, &isScalar, 1);
/*
* If we are doing an assignment, push the new value. In the no values
* case, create an empty object.
*/
if (numWords > 2) {
valueTokenPtr = TokenAfter(varTokenPtr);
CompileWord(envPtr, valueTokenPtr, interp, 2);
}
/*
* Emit instructions to set/get the variable.
*/
/*
* The *_STK opcodes should be refactored to make better use of existing
* LOAD/STORE instructions.
*/
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_STK, envPtr);
} else {
Emit14Inst( INST_LAPPEND_SCALAR, localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_ARRAY_STK, envPtr);
} else {
Emit14Inst( INST_LAPPEND_ARRAY, localIndex, envPtr);
}
}
return TCL_OK;
lappendMultiple:
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, varTokenPtr, envPtr, 0,
&localIndex, &isScalar, 1);
valueTokenPtr = TokenAfter(varTokenPtr);
for (i = 2 ; i < numWords ; i++) {
CompileWord(envPtr, valueTokenPtr, interp, i);
valueTokenPtr = TokenAfter(valueTokenPtr);
}
TclEmitInstInt4( INST_LIST, numWords - 2, envPtr);
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_LIST_STK, envPtr);
} else {
TclEmitInstInt4(INST_LAPPEND_LIST, localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_LAPPEND_LIST_ARRAY_STK, envPtr);
} else {
TclEmitInstInt4(INST_LAPPEND_LIST_ARRAY, localIndex,envPtr);
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
| | > | < < | | > > | | < < < | | | | | | | | | | | | | | | | | > | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int isScalar, localIndex, numWords, idx;
numWords = parsePtr->numWords;
/*
* Check for command syntax error, but we'll punt that to runtime.
*/
if (numWords < 3) {
return TCL_ERROR;
}
/*
* Generate code to push list being taken apart by [lassign].
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
/*
* Generate code to assign values from the list to variables.
*/
for (idx=0 ; idx<numWords-2 ; idx++) {
tokenPtr = TokenAfter(tokenPtr);
/*
* Generate the next variable name.
*/
PushVarNameWord(interp, tokenPtr, envPtr, 0, &localIndex,
&isScalar, idx + 2);
/*
* Emit instructions to get the idx'th item out of the list value on
* the stack and assign it to the variable.
*/
if (isScalar) {
if (localIndex >= 0) {
TclEmitOpcode( INST_DUP, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
} else {
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
TclEmitOpcode( INST_STORE_STK, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
} else {
if (localIndex >= 0) {
TclEmitInstInt4(INST_OVER, 1, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
} else {
TclEmitInstInt4(INST_OVER, 2, envPtr);
TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
}
}
/*
* Generate code to leave the rest of the list on the stack.
*/
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *idxTokenPtr, *valTokenPtr;
| | < | | | | | | < | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *idxTokenPtr, *valTokenPtr;
int i, idx, numWords = parsePtr->numWords;
/*
* Quit if not enough args.
*/
/* TODO: Consider support for compiling expanded args. */
if (numWords <= 1) {
return TCL_ERROR;
}
valTokenPtr = TokenAfter(parsePtr->tokenPtr);
if (numWords != 3) {
goto emitComplexLindex;
}
idxTokenPtr = TokenAfter(valTokenPtr);
if (TclGetIndexFromToken(idxTokenPtr, TCL_INDEX_NONE,
TCL_INDEX_NONE, &idx) == TCL_OK) {
/*
* The idxTokenPtr parsed as a valid index value and was
* encoded as expected by INST_LIST_INDEX_IMM.
*
* NOTE: that we rely on indexing before a list producing the
* same result as indexing after a list.
*/
CompileWord(envPtr, valTokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST_INDEX_IMM, idx, envPtr);
return TCL_OK;
}
/*
* If the value was not known at compile time, the conversion failed or
* the value was negative, we just keep on going with the more complex
* compilation.
*/
/*
* Push the operands onto the stack.
*/
emitComplexLindex:
for (i=1 ; i<numWords ; i++) {
CompileWord(envPtr, valTokenPtr, interp, i);
valTokenPtr = TokenAfter(valTokenPtr);
}
/*
* Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI if there are
* multiple index args.
*/
if (numWords == 3) {
TclEmitOpcode( INST_LIST_INDEX, envPtr);
} else {
TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileListCmd --
*
* Procedure called to compile the "list" command.
*
* Results:
* Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
* evaluation to runtime.
*
* Side effects:
* Instructions are added to envPtr to execute the "list" command at
|
| ︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *valueTokenPtr;
| < | < < < | | > | > > | | | | | < < < < < < < < | | | > | 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *valueTokenPtr;
int i, numWords, concat, build;
Tcl_Obj *listObj, *objPtr;
if (parsePtr->numWords == 1) {
/*
* [list] without arguments just pushes an empty object.
*/
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
* Test if all arguments are compile-time known. If they are, we can
* implement with a simple push.
*/
numWords = parsePtr->numWords;
valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
TclNewObj(listObj);
for (i = 1; i < numWords && listObj != NULL; i++) {
TclNewObj(objPtr);
if (TclWordKnownAtCompileTime(valueTokenPtr, objPtr)) {
(void) Tcl_ListObjAppendElement(NULL, listObj, objPtr);
} else {
Tcl_DecrRefCount(objPtr);
Tcl_DecrRefCount(listObj);
listObj = NULL;
}
valueTokenPtr = TokenAfter(valueTokenPtr);
}
if (listObj != NULL) {
TclEmitPush(TclAddLiteralObj(envPtr, listObj, NULL), envPtr);
return TCL_OK;
}
/*
* Push the all values onto the stack.
*/
numWords = parsePtr->numWords;
valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
concat = build = 0;
for (i = 1; i < numWords; i++) {
if (valueTokenPtr->type == TCL_TOKEN_EXPAND_WORD && build > 0) {
TclEmitInstInt4( INST_LIST, build, envPtr);
if (concat) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
}
build = 0;
concat = 1;
}
CompileWord(envPtr, valueTokenPtr, interp, i);
if (valueTokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
if (concat) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
} else {
concat = 1;
}
} else {
build++;
}
valueTokenPtr = TokenAfter(valueTokenPtr);
}
if (build > 0) {
TclEmitInstInt4( INST_LIST, build, envPtr);
if (concat) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
}
}
/*
* If there was just one expanded word, we must ensure that it is a list
* at this point. We use an [lrange ... 0 end] for this (instead of
* [llength], as with literals) as we must drop any string representation
* that might be hanging around.
*/
if (concat && numWords == 2) {
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( (int)TCL_INDEX_END, envPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 |
Tcl_Token *varTokenPtr;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
| | | | 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
Tcl_Token *varTokenPtr;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, varTokenPtr, interp, 1);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileLrangeCmd --
|
| ︙ | ︙ | |||
1380 1381 1382 1383 1384 1385 1386 |
/*
* Issue instructions. It's not safe to skip doing the LIST_RANGE, as
* we've not proved that the 'list' argument is really a list. Not that it
* is worth trying to do that given current knowledge.
*/
| | | > | 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 |
/*
* Issue instructions. It's not safe to skip doing the LIST_RANGE, as
* we've not proved that the 'list' argument is really a list. Not that it
* is worth trying to do that given current knowledge.
*/
CompileWord(envPtr, listTokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
TclEmitInt4( idx2, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileLinsertCmd --
|
| ︙ | ︙ | |||
1405 1406 1407 1408 1409 1410 1411 |
Tcl_Interp *interp, /* Tcl interpreter for context. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
| | | < | | > | | < < > | < | > > < | | | | | 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 |
Tcl_Interp *interp, /* Tcl interpreter for context. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i;
if ((int)parsePtr->numWords < 3) {
return TCL_ERROR;
}
/* Push list, insertion index onto the stack */
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
/* Push new elements to be inserted */
for (i=3 ; i<(int)parsePtr->numWords ; i++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
/* First operand is count of arguments */
TclEmitInstInt4(INST_LREPLACE4, parsePtr->numWords - 1, envPtr);
/*
* Second operand is bitmask
* TCL_LREPLACE4_END_IS_LAST - end refers to last element
* TCL_LREPLACE4_SINGLE_INDEX - second index is not present
* indicating this is a pure insert
*/
TclEmitInt1(TCL_LREPLACE4_SINGLE_INDEX, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileLreplaceCmd --
|
| ︙ | ︙ | |||
1458 1459 1460 1461 1462 1463 1464 |
Tcl_Interp *interp, /* Tcl interpreter for context. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
| | | < | | > | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < < | | < < < < < < | < | < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 |
Tcl_Interp *interp, /* Tcl interpreter for context. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int i;
if (parsePtr->numWords < 4) {
return TCL_ERROR;
}
/* Push list, first, last onto the stack */
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
/* Push new elements to be inserted */
for (i=4 ; i< (int)parsePtr->numWords ; i++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
/* First operand is count of arguments */
TclEmitInstInt4(INST_LREPLACE4, parsePtr->numWords - 1, envPtr);
/*
* Second operand is bitmask
* TCL_LREPLACE4_END_IS_LAST - end refers to last element
*/
TclEmitInt1(TCL_LREPLACE4_END_IS_LAST, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileLsetCmd --
*
|
| ︙ | ︙ | |||
1965 1966 1967 1968 1969 1970 1971 |
Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
| | | | | > | < < < | | | > > > > | | > > > > | | | | | | | | | | | | | 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
int tempDepth; /* Depth used for emitting one part of the
* code burst. */
Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing the
* parse of the variable name. */
int localIndex; /* Index of var in local var table. */
int isScalar; /* Flag == 1 if scalar, 0 if array. */
int i;
/*
* Check argument count.
*/
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords < 3) {
/*
* Fail at run time, not in compilation.
*/
return TCL_ERROR;
}
/*
* Decide if we can use a frame slot for the var/array name or if we need
* to emit code to compute and push the name at runtime. We use a frame
* slot (entry in the array of local vars) if we are compiling a procedure
* body and if the name is simple text that does not include namespace
* qualifiers.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, varTokenPtr, envPtr, 0,
&localIndex, &isScalar, 1);
/*
* Push the "index" args and the new element value.
*/
for (i=2 ; i<(int)parsePtr->numWords ; ++i) {
varTokenPtr = TokenAfter(varTokenPtr);
CompileWord(envPtr, varTokenPtr, interp, i);
}
/*
* Duplicate the variable name if it's been pushed.
*/
if (localIndex < 0) {
if (isScalar) {
tempDepth = parsePtr->numWords - 2;
} else {
tempDepth = parsePtr->numWords - 1;
}
TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
}
/*
* Duplicate an array index if one's been pushed.
*/
if (!isScalar) {
if (localIndex < 0) {
tempDepth = parsePtr->numWords - 1;
} else {
tempDepth = parsePtr->numWords - 2;
}
TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
}
/*
* Emit code to load the variable's value.
*/
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_LOAD_STK, envPtr);
} else {
Emit14Inst( INST_LOAD_SCALAR, localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr);
} else {
Emit14Inst( INST_LOAD_ARRAY, localIndex, envPtr);
}
}
/*
* Emit the correct variety of 'lset' instruction.
*/
if (parsePtr->numWords == 4) {
TclEmitOpcode( INST_LSET_LIST, envPtr);
} else {
TclEmitInstInt4( INST_LSET_FLAT, parsePtr->numWords-1, envPtr);
}
/*
* Emit code to put the value back in the variable.
*/
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode( INST_STORE_STK, envPtr);
} else {
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
} else {
Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
}
}
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
2116 2117 2118 2119 2120 2121 2122 |
return TCL_ERROR;
}
/*
* Not much to do; we compile to a single instruction...
*/
| | | 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 |
return TCL_ERROR;
}
/*
* Not much to do; we compile to a single instruction...
*/
TclEmitOpcode( INST_NS_CURRENT, envPtr);
return TCL_OK;
}
int
TclCompileNamespaceCodeCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
|
| ︙ | ︙ | |||
2143 2144 2145 2146 2147 2148 2149 |
/*
* The specification of [namespace code] is rather shocking, in that it is
* supposed to check if the argument is itself the result of [namespace
* code] and not apply itself in that case. Which is excessively cautious,
* but what the test suite checks for.
*/
| | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | < | > | | | | | | | | | | | | > > > | > > | | | 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 |
/*
* The specification of [namespace code] is rather shocking, in that it is
* supposed to check if the argument is itself the result of [namespace
* code] and not apply itself in that case. Which is excessively cautious,
* but what the test suite checks for.
*/
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || (tokenPtr[1].size > 20
&& strncmp(tokenPtr[1].start, "::namespace inscope ", 20) == 0)) {
/*
* Technically, we could just pass a literal '::namespace inscope '
* term through, but that's something which really shouldn't be
* occurring as something that the user writes so we'll just punt it.
*/
return TCL_ERROR;
}
/*
* Now we can compile using the same strategy as [namespace code]'s normal
* implementation does internally. Note that we can't bind the namespace
* name directly here, because TclOO plays complex games with namespaces;
* the value needs to be determined at runtime for safety.
*/
PushStringLiteral(envPtr, "::namespace");
PushStringLiteral(envPtr, "inscope");
TclEmitOpcode( INST_NS_CURRENT, envPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST, 4, envPtr);
return TCL_OK;
}
int
TclCompileNamespaceOriginCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode( INST_ORIGIN_COMMAND, envPtr);
return TCL_OK;
}
int
TclCompileNamespaceQualifiersCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
int off;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
CompileWord(envPtr, tokenPtr, interp, 1);
PushStringLiteral(envPtr, "0");
PushStringLiteral(envPtr, "::");
TclEmitInstInt4( INST_OVER, 2, envPtr);
TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
off = CurrentOffset(envPtr);
PushStringLiteral(envPtr, "1");
TclEmitOpcode( INST_SUB, envPtr);
TclEmitInstInt4( INST_OVER, 2, envPtr);
TclEmitInstInt4( INST_OVER, 1, envPtr);
TclEmitOpcode( INST_STR_INDEX, envPtr);
PushStringLiteral(envPtr, ":");
TclEmitOpcode( INST_STR_EQ, envPtr);
off = off - CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, off, envPtr);
TclEmitOpcode( INST_STR_RANGE, envPtr);
return TCL_OK;
}
int
TclCompileNamespaceTailCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
JumpFixup jumpFixup;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
/*
* Take care; only add 2 to found index if the string was actually found.
*/
CompileWord(envPtr, tokenPtr, interp, 1);
PushStringLiteral(envPtr, "::");
TclEmitInstInt4( INST_OVER, 1, envPtr);
TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
TclEmitOpcode( INST_DUP, envPtr);
PushStringLiteral(envPtr, "0");
TclEmitOpcode( INST_GE, envPtr);
TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFixup);
PushStringLiteral(envPtr, "2");
TclEmitOpcode( INST_ADD, envPtr);
TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127);
PushStringLiteral(envPtr, "end");
TclEmitOpcode( INST_STR_RANGE, envPtr);
return TCL_OK;
}
int
TclCompileNamespaceUpvarCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr;
int localIndex, numWords, i;
if (envPtr->procPtr == NULL) {
return TCL_ERROR;
}
/*
* Only compile [namespace upvar ...]: needs an even number of args, >=4
*/
numWords = (int)parsePtr->numWords;
if ((numWords % 2) || (numWords < 4)) {
return TCL_ERROR;
}
/*
* Push the namespace
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
/*
* Loop over the (otherVar, thisVar) pairs. If any of the thisVar is not a
* local variable, return an error so that the non-compiled command will
* be called at runtime.
*/
localTokenPtr = tokenPtr;
for (i=2; i<numWords; i+=2) {
otherTokenPtr = TokenAfter(localTokenPtr);
localTokenPtr = TokenAfter(otherTokenPtr);
CompileWord(envPtr, otherTokenPtr, interp, i);
localIndex = LocalScalarFromToken(localTokenPtr, envPtr);
if (localIndex < 0) {
return TCL_ERROR;
}
TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
}
/*
* Pop the namespace, and set the result to empty
*/
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
return TCL_OK;
}
int
TclCompileNamespaceWhichCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr, *opt;
int idx;
if ((int)parsePtr->numWords < 2 || (int)parsePtr->numWords > 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
idx = 1;
/*
* If there's an option, check that it's "-command". We don't handle
* "-variable" (currently) and anything else is an error.
*/
if (parsePtr->numWords == 3) {
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TCL_ERROR;
}
opt = tokenPtr + 1;
if (opt->size < 2 || opt->size > 8
|| strncmp(opt->start, "-command", opt->size) != 0) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(tokenPtr);
idx++;
}
/*
* Issue the bytecode.
*/
CompileWord(envPtr, tokenPtr, interp, idx);
TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileRegexpCmd --
|
| ︙ | ︙ | |||
2390 2391 2392 2393 2394 2395 2396 |
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing the
* parse of the RE or string. */
size_t len;
| < | | | > > > > | > > > > > | | | | 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 |
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing the
* parse of the RE or string. */
size_t len;
int i, nocase, exact, sawLast, simple;
const char *str;
/*
* We are only interested in compiling simple regexp cases. Currently
* supported compile cases are:
* regexp ?-nocase? ?--? staticString $var
* regexp ?-nocase? ?--? {^staticString$} $var
*/
if ((int)parsePtr->numWords < 3) {
return TCL_ERROR;
}
simple = 0;
nocase = 0;
sawLast = 0;
varTokenPtr = parsePtr->tokenPtr;
/*
* We only look for -nocase and -- as options. Everything else gets pushed
* to runtime execution. This is different than regexp's runtime option
* handling, but satisfies our stricter needs.
*/
for (i = 1; i < (int)parsePtr->numWords - 2; i++) {
varTokenPtr = TokenAfter(varTokenPtr);
if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
/*
* Not a simple string, so punt to runtime.
*/
return TCL_ERROR;
}
str = varTokenPtr[1].start;
len = varTokenPtr[1].size;
if ((len == 2) && (str[0] == '-') && (str[1] == '-')) {
sawLast++;
i++;
break;
} else if ((len > 1) && (strncmp(str, "-nocase", len) == 0)) {
nocase = 1;
} else {
/*
* Not an option we recognize.
*/
return TCL_ERROR;
}
}
if (((int)parsePtr->numWords - i) != 2) {
/*
* We don't support capturing to variables.
*/
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2474 2475 2476 2477 2478 2479 2480 | */ /* * Attempt to convert pattern to glob. If successful, push the * converted pattern as a literal. */ | | > | | | | | | | 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 |
*/
/*
* Attempt to convert pattern to glob. If successful, push the
* converted pattern as a literal.
*/
if (TclReToGlob(NULL, varTokenPtr[1].start, len, &ds, &exact, NULL)
== TCL_OK) {
simple = 1;
PushLiteral(envPtr, Tcl_DStringValue(&ds),Tcl_DStringLength(&ds));
Tcl_DStringFree(&ds);
}
}
if (!simple) {
CompileWord(envPtr, varTokenPtr, interp, (int)parsePtr->numWords - 2);
}
/*
* Push the string arg.
*/
varTokenPtr = TokenAfter(varTokenPtr);
CompileWord(envPtr, varTokenPtr, interp, (int)parsePtr->numWords - 1);
if (simple) {
if (exact && !nocase) {
TclEmitOpcode( INST_STR_EQ, envPtr);
} else {
TclEmitInstInt1( INST_STR_MATCH, nocase, envPtr);
}
} else {
/*
* Pass correct RE compile flags. We use only Int1 (8-bit), but
* that handles all the flags we want to pass.
* Don't use TCL_REG_NOSUB as we may have backrefs.
*/
int cflags = TCL_REG_ADVANCED | (nocase ? TCL_REG_NOCASE : 0);
TclEmitInstInt1( INST_REGEXP, cflags, envPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
2560 2561 2562 2563 2564 2565 2566 |
*
* regsub -all [--] simpleRE string simpleReplacement
*
* The only optional part is the "--", and no other options are handled.
*/
DefineLineInformation; /* TIP #280 */
| < | > | | > | | | 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 |
*
* regsub -all [--] simpleRE string simpleReplacement
*
* The only optional part is the "--", and no other options are handled.
*/
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr, *stringTokenPtr;
Tcl_Obj *patternObj = NULL, *replacementObj = NULL;
Tcl_DString pattern;
const char *bytes;
int exact, quantified, result = TCL_ERROR;
Tcl_Size len;
if ((int)parsePtr->numWords < 5 || (int)parsePtr->numWords > 6) {
return TCL_ERROR;
}
/*
* Parse the "-all", which must be the first argument (other options not
* supported, non-"-all" substitution we can't compile).
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 4
|| strncmp(tokenPtr[1].start, "-all", 4)) {
return TCL_ERROR;
}
/*
* Get the pattern into patternObj, checking for "--" in the process.
*/
Tcl_DStringInit(&pattern);
tokenPtr = TokenAfter(tokenPtr);
TclNewObj(patternObj);
if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
goto done;
}
if (TclGetString(patternObj)[0] == '-') {
if (strcmp(TclGetString(patternObj), "--") != 0
|| parsePtr->numWords == 5) {
goto done;
}
tokenPtr = TokenAfter(tokenPtr);
Tcl_DecrRefCount(patternObj);
TclNewObj(patternObj);
if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
goto done;
}
} else if (parsePtr->numWords == 6) {
goto done;
}
/*
* Identify the code which produces the string to apply the substitution
* to (stringTokenPtr), and the replacement string (into replacementObj).
*/
|
| ︙ | ︙ | |||
2671 2672 2673 2674 2675 2676 2677 |
/*
* Proved the simplicity constraints! Time to issue the code.
*/
result = TCL_OK;
bytes = Tcl_DStringValue(&pattern) + 1;
| | | > | | > | > > | > | 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 |
/*
* Proved the simplicity constraints! Time to issue the code.
*/
result = TCL_OK;
bytes = Tcl_DStringValue(&pattern) + 1;
PushLiteral(envPtr, bytes, len);
bytes = TclGetStringFromObj(replacementObj, &len);
PushLiteral(envPtr, bytes, len);
CompileWord(envPtr, stringTokenPtr, interp, (int)parsePtr->numWords - 2);
TclEmitOpcode( INST_STR_MAP, envPtr);
done:
Tcl_DStringFree(&pattern);
if (patternObj) {
Tcl_DecrRefCount(patternObj);
}
if (replacementObj) {
Tcl_DecrRefCount(replacementObj);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* TclCompileReturnCmd --
|
| ︙ | ︙ | |||
2716 2717 2718 2719 2720 2721 2722 |
DefineLineInformation; /* TIP #280 */
/*
* General syntax: [return ?-option value ...? ?result?]
* An even number of words means an explicit result argument is present.
*/
int level, code, objc, status = TCL_OK;
Tcl_Size size;
| | | < < < < | > > | | | | < | 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 |
DefineLineInformation; /* TIP #280 */
/*
* General syntax: [return ?-option value ...? ?result?]
* An even number of words means an explicit result argument is present.
*/
int level, code, objc, status = TCL_OK;
Tcl_Size size;
int numWords = parsePtr->numWords;
int explicitResult = (0 == (numWords % 2));
int numOptionWords = numWords - 1 - explicitResult;
Tcl_Obj *returnOpts, **objv;
Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
/*
* Check for special case which can always be compiled:
* return -options <opts> <msg>
* Unlike the normal [return] compilation, this version does everything at
* runtime so it can handle arbitrary words and not just literals. Note
* that if INST_RETURN_STK wasn't already needed for something else
* ('finally' clause processing) this piece of code would not be present.
*/
if ((numWords == 4) && (wordTokenPtr->type == TCL_TOKEN_SIMPLE_WORD)
&& (wordTokenPtr[1].size == 8)
&& (strncmp(wordTokenPtr[1].start, "-options", 8) == 0)) {
Tcl_Token *optsTokenPtr = TokenAfter(wordTokenPtr);
Tcl_Token *msgTokenPtr = TokenAfter(optsTokenPtr);
CompileWord(envPtr, optsTokenPtr, interp, 2);
CompileWord(envPtr, msgTokenPtr, interp, 3);
TclEmitInvoke(envPtr, INST_RETURN_STK);
return TCL_OK;
}
/*
* Allocate some working space.
*/
objv = (Tcl_Obj **)TclStackAlloc(interp, numOptionWords * sizeof(Tcl_Obj *));
/*
* Scan through the return options. If any are unknown at compile time,
* there is no value in bytecompiling. Save the option values known in an
* objv array for merging into a return options dictionary.
*
* TODO: There is potential for improvement if all option keys are known
|
| ︙ | ︙ | |||
2801 2802 2803 2804 2805 2806 2807 |
/*
* All options are known at compile time, so we're going to bytecompile.
* Emit instructions to push the result on the stack.
*/
if (explicitResult) {
| | | | | | | | | | | 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 |
/*
* All options are known at compile time, so we're going to bytecompile.
* Emit instructions to push the result on the stack.
*/
if (explicitResult) {
CompileWord(envPtr, wordTokenPtr, interp, numWords - 1);
} else {
/*
* No explict result argument, so default result is empty string.
*/
PushStringLiteral(envPtr, "");
}
/*
* Check for optimization: When [return] is in a proc, and there's no
* enclosing [catch], and there are no return options, then the INST_DONE
* instruction is equivalent, and may be more efficient.
*/
if (numOptionWords == 0 && envPtr->procPtr != NULL) {
/*
* We have default return options and we're in a proc ...
*/
int index = envPtr->exceptArrayNext - 1;
int enclosingCatch = 0;
while (index >= 0) {
ExceptionRange range = envPtr->exceptArrayPtr[index];
if ((range.type == CATCH_EXCEPTION_RANGE)
&& (range.catchOffset == TCL_INDEX_NONE)) {
enclosingCatch = 1;
break;
}
index--;
}
if (!enclosingCatch) {
/*
* ... and there is no enclosing catch. Issue the maximally
* efficient exit instruction.
*/
Tcl_DecrRefCount(returnOpts);
TclEmitOpcode(INST_DONE, envPtr);
TclAdjustStackDepth(1, envPtr);
return TCL_OK;
}
}
/* Optimize [return -level 0 $x]. */
Tcl_DictObjSize(NULL, returnOpts, &size);
if (size == 0 && level == 0 && code == TCL_OK) {
|
| ︙ | ︙ | |||
2869 2870 2871 2872 2873 2874 2875 |
issueRuntimeReturn:
/*
* Assemble the option dictionary (as a list as that's good enough).
*/
wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
for (objc=1 ; objc<=numOptionWords ; objc++) {
| | | | | | | 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 |
issueRuntimeReturn:
/*
* Assemble the option dictionary (as a list as that's good enough).
*/
wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
for (objc=1 ; objc<=numOptionWords ; objc++) {
CompileWord(envPtr, wordTokenPtr, interp, objc);
wordTokenPtr = TokenAfter(wordTokenPtr);
}
TclEmitInstInt4(INST_LIST, numOptionWords, envPtr);
/*
* Push the result.
*/
if (explicitResult) {
CompileWord(envPtr, wordTokenPtr, interp, numWords - 1);
} else {
PushStringLiteral(envPtr, "");
}
/*
* Issue the RETURN itself.
*/
TclEmitInvoke(envPtr, INST_RETURN_STK);
return TCL_OK;
}
static void
CompileReturnInternal(
CompileEnv *envPtr,
unsigned char op,
|
| ︙ | ︙ | |||
2917 2918 2919 2920 2921 2922 2923 |
TclAddLoopContinueFixup(envPtr, exceptAux);
}
Tcl_DecrRefCount(returnOpts);
return;
}
}
| | > | | | 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 |
TclAddLoopContinueFixup(envPtr, exceptAux);
}
Tcl_DecrRefCount(returnOpts);
return;
}
}
TclEmitPush(TclAddLiteralObj(envPtr, returnOpts, NULL), envPtr);
TclEmitInstInt4(op, code, envPtr);
TclEmitInt4(level, envPtr);
}
void
TclCompileSyntaxError(
Tcl_Interp *interp,
CompileEnv *envPtr)
{
Tcl_Obj *msg = Tcl_GetObjResult(interp);
Tcl_Size numBytes;
const char *bytes = TclGetStringFromObj(msg, &numBytes);
TclErrorStackResetIf(interp, bytes, numBytes);
TclEmitPush(TclRegisterLiteral(envPtr, bytes, numBytes, 0), envPtr);
CompileReturnInternal(envPtr, INST_SYNTAX, TCL_ERROR, 0,
TclNoErrorStack(interp, Tcl_GetReturnOptions(interp, TCL_ERROR)));
Tcl_ResetResult(interp);
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
2965 2966 2967 2968 2969 2970 2971 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr;
| | < | > | > > > | > | > | | | | | | | | | | | | 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr;
int localIndex, numWords, i;
Tcl_Obj *objPtr;
if (envPtr->procPtr == NULL) {
return TCL_ERROR;
}
numWords = parsePtr->numWords;
if (numWords < 3) {
return TCL_ERROR;
}
/*
* Push the frame index if it is known at compile time
*/
TclNewObj(objPtr);
tokenPtr = TokenAfter(parsePtr->tokenPtr);
if (TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
CallFrame *framePtr;
const Tcl_ObjType *newTypePtr, *typePtr = objPtr->typePtr;
/*
* Attempt to convert to a level reference. Note that TclObjGetFrame
* only changes the obj type when a conversion was successful.
*/
TclObjGetFrame(interp, objPtr, &framePtr);
newTypePtr = objPtr->typePtr;
Tcl_DecrRefCount(objPtr);
if (newTypePtr != typePtr) {
if (numWords%2) {
return TCL_ERROR;
}
/* TODO: Push the known value instead? */
CompileWord(envPtr, tokenPtr, interp, 1);
otherTokenPtr = TokenAfter(tokenPtr);
i = 2;
} else {
if (!(numWords%2)) {
return TCL_ERROR;
}
PushStringLiteral(envPtr, "1");
otherTokenPtr = tokenPtr;
i = 1;
}
} else {
Tcl_DecrRefCount(objPtr);
return TCL_ERROR;
}
/*
* Loop over the (otherVar, thisVar) pairs. If any of the thisVar is not a
* local variable, return an error so that the non-compiled command will
* be called at runtime.
*/
for (; i<numWords; i+=2, otherTokenPtr = TokenAfter(localTokenPtr)) {
localTokenPtr = TokenAfter(otherTokenPtr);
CompileWord(envPtr, otherTokenPtr, interp, i);
localIndex = LocalScalarFromToken(localTokenPtr, envPtr);
if (localIndex < 0) {
return TCL_ERROR;
}
TclEmitInstInt4( INST_UPVAR, localIndex, envPtr);
}
/*
* Pop the frame index, and set the result to empty
*/
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileVariableCmd --
|
| ︙ | ︙ | |||
3066 3067 3068 3069 3070 3071 3072 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
| | < > | | | 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
int localIndex, numWords, i;
numWords = parsePtr->numWords;
if (numWords < 2) {
return TCL_ERROR;
}
/*
* Bail out if not compiling a proc body
*/
if (envPtr->procPtr == NULL) {
return TCL_ERROR;
}
/*
* Loop over the (var, value) pairs.
*/
|
| ︙ | ︙ | |||
3099 3100 3101 3102 3103 3104 3105 |
if (localIndex < 0) {
return TCL_ERROR;
}
/* TODO: Consider what value can pass through the
* IndexTailVarIfKnown() screen. Full CompileWord()
* likely does not apply here. Push known value instead. */
| | | | | | | | 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 |
if (localIndex < 0) {
return TCL_ERROR;
}
/* 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_VARIABLE, localIndex, envPtr);
if (i + 1 < numWords) {
/*
* A value has been given: set the variable, pop the value
*/
CompileWord(envPtr, valueTokenPtr, interp, i + 1);
Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
}
/*
* Set the result to empty
*/
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* IndexTailVarIfKnown --
|
| ︙ | ︙ | |||
3140 3141 3142 3143 3144 3145 3146 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | | > | < | | | | | | | 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
IndexTailVarIfKnown(
TCL_UNUSED(Tcl_Interp *),
Tcl_Token *varTokenPtr, /* Token representing the variable name */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Obj *tailPtr;
const char *tailName, *p;
int n = varTokenPtr->numComponents;
Tcl_Size len;
Tcl_Token *lastTokenPtr;
int full, localIndex;
/*
* Determine if the tail is (a) known at compile time, and (b) not an
* array element. Should any of these fail, return an error so that the
* non-compiled command will be called at runtime.
*
* In order for the tail to be known at compile time, the last token in
* the word has to be constant and contain "::" if it is not the only one.
*/
if (!EnvHasLVT(envPtr)) {
return -1;
}
TclNewObj(tailPtr);
if (TclWordKnownAtCompileTime(varTokenPtr, tailPtr)) {
full = 1;
lastTokenPtr = varTokenPtr;
} else {
full = 0;
lastTokenPtr = varTokenPtr + n;
if (lastTokenPtr->type != TCL_TOKEN_TEXT) {
Tcl_DecrRefCount(tailPtr);
return -1;
}
Tcl_SetStringObj(tailPtr, lastTokenPtr->start, lastTokenPtr->size);
}
tailName = TclGetStringFromObj(tailPtr, &len);
if (len) {
if (*(tailName + len - 1) == ')') {
/*
* Possible array: bail out
*/
Tcl_DecrRefCount(tailPtr);
return -1;
}
/*
* Get the tail: immediately after the last '::'
*/
for (p = tailName + len -1; p > tailName; p--) {
if ((p[0] == ':') && (p[- 1] == ':')) {
p++;
break;
}
}
if (!full && (p == tailName)) {
/*
* No :: in the last component.
*/
Tcl_DecrRefCount(tailPtr);
return -1;
}
len -= p - tailName;
tailName = p;
}
localIndex = TclFindCompiledLocal(tailName, len, 1, envPtr);
Tcl_DecrRefCount(tailPtr);
return localIndex;
}
/*
* ----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
3240 3241 3242 3243 3244 3245 3246 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
| < | < < | | < < < < < < < < < < < < < < < | | < < < < < < < < < < | < < < > | < < < < < < < < < < < < < < < < < < < < < < < | < < | | < < < < | < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | > > > | > > | | | | | | 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
int i;
if ((int)parsePtr->numWords > 255) {
return TCL_ERROR;
}
for (i=0 ; i<(int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt1( INST_TCLOO_NEXT, i, envPtr);
return TCL_OK;
}
int
TclCompileObjectNextToCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
int i;
if ((int)parsePtr->numWords < 2 || (int)parsePtr->numWords > 255) {
return TCL_ERROR;
}
for (i=0 ; i<(int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt1( INST_TCLOO_NEXT_CLASS, i, envPtr);
return TCL_OK;
}
int
TclCompileObjectSelfCmd(
TCL_UNUSED(Tcl_Interp *),
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
/*
* We only handle [self] and [self object] (which is the same operation).
* These are the only very common operations on [self] for which
* bytecoding is at all reasonable.
*/
if (parsePtr->numWords == 1) {
goto compileSelfObject;
} else if (parsePtr->numWords == 2) {
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr), *subcmd;
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size==0) {
return TCL_ERROR;
}
subcmd = tokenPtr + 1;
if (strncmp(subcmd->start, "object", subcmd->size) == 0) {
goto compileSelfObject;
} else if (strncmp(subcmd->start, "namespace", subcmd->size) == 0) {
goto compileSelfNamespace;
}
}
/*
* Can't compile; handle with runtime call.
*/
return TCL_ERROR;
compileSelfObject:
/*
* This delegates the entire problem to a single opcode.
*/
TclEmitOpcode( INST_TCLOO_SELF, envPtr);
return TCL_OK;
compileSelfNamespace:
/*
* This is formally only correct with TclOO methods as they are currently
* implemented; it assumes that the current namespace is invariably when a
* TclOO context is present is the object's namespace, and that's
* technically only something that's a matter of current policy. But it
* avoids creating another opcode, so that's all good!
*/
TclEmitOpcode( INST_TCLOO_SELF, envPtr);
TclEmitOpcode( INST_POP, envPtr);
TclEmitOpcode( INST_NS_CURRENT, envPtr);
return TCL_OK;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclCompCmdsSZ.c.
1 2 3 4 5 6 7 8 9 10 11 |
/*
* tclCompCmdsSZ.c --
*
* This file contains compilation procedures that compile various Tcl
* commands (beginning with the letters 's' through 'z', except for
* [upvar] and [variable]) into a sequence of instructions ("bytecodes").
* Also includes the operator command compilers.
*
* Copyright © 1997-1998 Sun Microsystems, Inc.
* Copyright © 2001 Kevin B. Kenny. All rights reserved.
* Copyright © 2002 ActiveState Corporation.
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | < | | < | | | < | < | < | < < | > | | | | < > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
/*
* tclCompCmdsSZ.c --
*
* This file contains compilation procedures that compile various Tcl
* commands (beginning with the letters 's' through 'z', except for
* [upvar] and [variable]) into a sequence of instructions ("bytecodes").
* Also includes the operator command compilers.
*
* Copyright © 1997-1998 Sun Microsystems, Inc.
* Copyright © 2001 Kevin B. Kenny. All rights reserved.
* Copyright © 2002 ActiveState Corporation.
* Copyright © 2004-2010 Donal K. Fellows.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
#include "tclCompile.h"
#include "tclStringTrim.h"
/*
* Prototypes for procedures defined later in this file:
*/
static AuxDataDupProc DupJumptableInfo;
static AuxDataFreeProc FreeJumptableInfo;
static AuxDataPrintProc PrintJumptableInfo;
static AuxDataPrintProc DisassembleJumptableInfo;
static int CompileAssociativeBinaryOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, const char *identity,
int instruction, CompileEnv *envPtr);
static int CompileComparisonOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, int instruction,
CompileEnv *envPtr);
static int CompileStrictlyBinaryOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, int instruction,
CompileEnv *envPtr);
static int CompileUnaryOpCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, int instruction,
CompileEnv *envPtr);
static void IssueSwitchChainedTests(Tcl_Interp *interp,
CompileEnv *envPtr, int mode, int noCase,
Tcl_Size numWords, Tcl_Token **bodyToken,
Tcl_Size *bodyLines, Tcl_Size **bodyNext);
static void IssueSwitchJumpTable(Tcl_Interp *interp,
CompileEnv *envPtr, int numWords,
Tcl_Token **bodyToken, Tcl_Size *bodyLines,
Tcl_Size **bodyContLines);
static int IssueTryClausesInstructions(Tcl_Interp *interp,
CompileEnv *envPtr, Tcl_Token *bodyToken,
int numHandlers, int *matchCodes,
Tcl_Obj **matchClauses, int *resultVarIndices,
int *optionVarIndices, Tcl_Token **handlerTokens);
static int IssueTryClausesFinallyInstructions(Tcl_Interp *interp,
CompileEnv *envPtr, Tcl_Token *bodyToken,
int numHandlers, int *matchCodes,
Tcl_Obj **matchClauses, int *resultVarIndices,
int *optionVarIndices, Tcl_Token **handlerTokens,
Tcl_Token *finallyToken);
static int IssueTryFinallyInstructions(Tcl_Interp *interp,
CompileEnv *envPtr, Tcl_Token *bodyToken,
Tcl_Token *finallyToken);
/*
* The structures below define the AuxData types defined in this file.
*/
const AuxDataType tclJumptableInfoType = {
"JumptableInfo", /* name */
DupJumptableInfo, /* dupProc */
FreeJumptableInfo, /* freeProc */
PrintJumptableInfo, /* printProc */
DisassembleJumptableInfo /* disassembleProc */
};
/*
* Shorthand macros for instruction issuing.
*/
#define OP(name) TclEmitOpcode(INST_##name, envPtr)
#define OP1(name,val) TclEmitInstInt1(INST_##name,(val),envPtr)
#define OP4(name,val) TclEmitInstInt4(INST_##name,(val),envPtr)
#define OP14(name,val1,val2) \
TclEmitInstInt1(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr)
#define OP44(name,val1,val2) \
TclEmitInstInt4(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr)
#define PUSH(str) \
PushStringLiteral(envPtr, str)
#define JUMP4(name,var) \
(var) = CurrentOffset(envPtr);TclEmitInstInt4(INST_##name##4,0,envPtr)
#define FIXJUMP4(var) \
TclStoreInt4AtPtr(CurrentOffset(envPtr)-(var),envPtr->codeStart+(var)+1)
#define JUMP1(name,var) \
(var) = CurrentOffset(envPtr);TclEmitInstInt1(INST_##name##1,0,envPtr)
#define FIXJUMP1(var) \
TclStoreInt1AtPtr(CurrentOffset(envPtr)-(var),envPtr->codeStart+(var)+1)
#define LOAD(idx) \
if ((idx)<256) {OP1(LOAD_SCALAR1,(idx));} else {OP4(LOAD_SCALAR4,(idx));}
#define STORE(idx) \
if ((idx)<256) {OP1(STORE_SCALAR1,(idx));} else {OP4(STORE_SCALAR4,(idx));}
#define INVOKE(name) \
TclEmitInvoke(envPtr,INST_##name)
/*
*----------------------------------------------------------------------
*
* TclCompileSetCmd --
*
* Procedure called to compile the "set" command.
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
| | < < > > | < < < | | | | | | > | < > | | | < | < | | | | | > | < > | | | < | < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr, *valueTokenPtr;
int isAssignment, isScalar, localIndex, numWords;
numWords = parsePtr->numWords;
if ((numWords != 2) && (numWords != 3)) {
return TCL_ERROR;
}
isAssignment = (numWords == 3);
/*
* Decide if we can use a frame slot for the var/array name or if we need
* to emit code to compute and push the name at runtime. We use a frame
* slot (entry in the array of local vars) if we are compiling a procedure
* body and if the name is simple text that does not include namespace
* qualifiers.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
PushVarNameWord(interp, varTokenPtr, envPtr, 0,
&localIndex, &isScalar, 1);
/*
* If we are doing an assignment, push the new value.
*/
if (isAssignment) {
valueTokenPtr = TokenAfter(varTokenPtr);
CompileWord(envPtr, valueTokenPtr, interp, 2);
}
/*
* Emit instructions to set/get the variable.
*/
if (isScalar) {
if (localIndex < 0) {
TclEmitOpcode((isAssignment?
INST_STORE_STK : INST_LOAD_STK), envPtr);
} else if (localIndex <= 255) {
TclEmitInstInt1((isAssignment?
INST_STORE_SCALAR1 : INST_LOAD_SCALAR1),
localIndex, envPtr);
} else {
TclEmitInstInt4((isAssignment?
INST_STORE_SCALAR4 : INST_LOAD_SCALAR4),
localIndex, envPtr);
}
} else {
if (localIndex < 0) {
TclEmitOpcode((isAssignment?
INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
} else if (localIndex <= 255) {
TclEmitInstInt1((isAssignment?
INST_STORE_ARRAY1 : INST_LOAD_ARRAY1),
localIndex, envPtr);
} else {
TclEmitInstInt4((isAssignment?
INST_STORE_ARRAY4 : INST_LOAD_ARRAY4),
localIndex, envPtr);
}
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
235 236 237 238 239 240 241 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
| | < | | | | > > > > | | | | | > > > > | | | | | > | | < | | | > | | < | | | > | < | | | | > | < | | | | > | | < | | > | > | | > | > < < | | | | | | | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
int i, numWords = parsePtr->numWords, numArgs;
Tcl_Token *wordTokenPtr;
Tcl_Obj *obj, *folded;
/* Trivial case, no arg */
if (numWords<2) {
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/* General case: issue CONCAT1's (by chunks of 254 if needed), folding
* contiguous constants along the way */
numArgs = 0;
folded = NULL;
wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
for (i = 1; i < numWords; i++) {
TclNewObj(obj);
if (TclWordKnownAtCompileTime(wordTokenPtr, obj)) {
if (folded) {
Tcl_AppendObjToObj(folded, obj);
Tcl_DecrRefCount(obj);
} else {
folded = obj;
}
} else {
Tcl_DecrRefCount(obj);
if (folded) {
Tcl_Size len;
const char *bytes = TclGetStringFromObj(folded, &len);
PushLiteral(envPtr, bytes, len);
Tcl_DecrRefCount(folded);
folded = NULL;
numArgs ++;
}
CompileWord(envPtr, wordTokenPtr, interp, i);
numArgs ++;
if (numArgs >= 254) { /* 254 to take care of the possible +1 of "folded" above */
TclEmitInstInt1(INST_STR_CONCAT1, numArgs, envPtr);
numArgs = 1; /* concat pushes 1 obj, the result */
}
}
wordTokenPtr = TokenAfter(wordTokenPtr);
}
if (folded) {
Tcl_Size len;
const char *bytes = TclGetStringFromObj(folded, &len);
PushLiteral(envPtr, bytes, len);
Tcl_DecrRefCount(folded);
folded = NULL;
numArgs ++;
}
if (numArgs > 1) {
TclEmitInstInt1(INST_STR_CONCAT1, numArgs, envPtr);
}
return TCL_OK;
}
int
TclCompileStringCmpCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
/*
* We don't support any flags; the bytecode isn't that sophisticated.
*/
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
/*
* Push the two operands onto the stack and then the test.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode(INST_STR_CMP, envPtr);
return TCL_OK;
}
int
TclCompileStringEqualCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
/*
* We don't support any flags; the bytecode isn't that sophisticated.
*/
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
/*
* Push the two operands onto the stack and then the test.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode(INST_STR_EQ, envPtr);
return TCL_OK;
}
int
TclCompileStringFirstCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
/*
* We don't support any flags; the bytecode isn't that sophisticated.
*/
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
/*
* Push the two operands onto the stack and then the test.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
OP(STR_FIND);
return TCL_OK;
}
int
TclCompileStringLastCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
/*
* We don't support any flags; the bytecode isn't that sophisticated.
*/
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
/*
* Push the two operands onto the stack and then the test.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
OP(STR_FIND_LAST);
return TCL_OK;
}
int
TclCompileStringIndexCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
/*
* Push the two operands onto the stack and then the index operation.
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode(INST_STR_INDEX, envPtr);
return TCL_OK;
}
int
TclCompileStringInsertCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
int idx;
if (parsePtr->numWords != 4) {
return TCL_ERROR;
}
/* Compute and push the string in which to insert */
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
/* See what can be discovered about index at compile time */
tokenPtr = TokenAfter(tokenPtr);
if (TCL_OK != TclGetIndexFromToken(tokenPtr, TCL_INDEX_START,
TCL_INDEX_END, &idx)) {
/* Nothing useful knowable - cease compile; let it direct eval */
return TCL_ERROR;
}
/* Compute and push the string to be inserted */
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
if (idx == (int)TCL_INDEX_START) {
/* Prepend the insertion string */
OP4( REVERSE, 2);
OP1( STR_CONCAT1, 2);
} else if (idx == (int)TCL_INDEX_END) {
/* Append the insertion string */
OP1( STR_CONCAT1, 2);
} else {
/* Prefix + insertion + suffix */
if (idx < (int)TCL_INDEX_END) {
/* See comments in compiler for [linsert]. */
idx++;
}
OP4( OVER, 1);
OP44( STR_RANGE_IMM, 0, idx-1);
OP4( REVERSE, 3);
OP44( STR_RANGE_IMM, idx, TCL_INDEX_END);
OP1( STR_CONCAT1, 3);
}
return TCL_OK;
}
int
TclCompileStringIsCmd(
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 |
STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL,
STR_IS_BOOL, STR_IS_DICT, STR_IS_DIGIT, STR_IS_DOUBLE,
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT,
STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT,
STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER,
STR_IS_WIDE, STR_IS_WORD, STR_IS_XDIGIT
} t;
| | < < > > > > > > | > | | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
STR_IS_ALNUM, STR_IS_ALPHA, STR_IS_ASCII, STR_IS_CONTROL,
STR_IS_BOOL, STR_IS_DICT, STR_IS_DIGIT, STR_IS_DOUBLE,
STR_IS_ENTIER, STR_IS_FALSE, STR_IS_GRAPH, STR_IS_INT,
STR_IS_LIST, STR_IS_LOWER, STR_IS_PRINT, STR_IS_PUNCT,
STR_IS_SPACE, STR_IS_TRUE, STR_IS_UPPER,
STR_IS_WIDE, STR_IS_WORD, STR_IS_XDIGIT
} t;
int range, allowEmpty = 0, end;
InstStringClassType strClassType;
Tcl_Obj *isClass;
if (parsePtr->numWords < 3 || parsePtr->numWords > 6) {
return TCL_ERROR;
}
TclNewObj(isClass);
if (!TclWordKnownAtCompileTime(tokenPtr, isClass)) {
Tcl_DecrRefCount(isClass);
return TCL_ERROR;
} else if (Tcl_GetIndexFromObj(interp, isClass, isClasses, "class", 0,
&t) != TCL_OK) {
Tcl_DecrRefCount(isClass);
TclCompileSyntaxError(interp, envPtr);
return TCL_OK;
}
Tcl_DecrRefCount(isClass);
#define GotLiteral(tokenPtr, word) \
((tokenPtr)->type == TCL_TOKEN_SIMPLE_WORD && \
(tokenPtr)[1].size > 1 && \
(tokenPtr)[1].start[0] == word[0] && \
strncmp((tokenPtr)[1].start, (word), (tokenPtr)[1].size) == 0)
/*
* Cannot handle the -failindex option at all, and that's the only legal
* way to have more than 4 arguments.
*/
if (parsePtr->numWords != 3 && parsePtr->numWords != 4) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(tokenPtr);
if (parsePtr->numWords == 3) {
allowEmpty = 1;
} else {
if (!GotLiteral(tokenPtr, "-strict")) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(tokenPtr);
}
#undef GotLiteral
/*
* Compile the code. There are several main classes of check here.
* 1. Character classes
* 2. Booleans
* 3. Integers
* 4. Floats
* 5. Lists
*/
CompileWord(envPtr, tokenPtr, interp, (int)parsePtr->numWords-1);
switch (t) {
case STR_IS_ALNUM:
strClassType = STR_CLASS_ALNUM;
goto compileStrClass;
case STR_IS_ALPHA:
strClassType = STR_CLASS_ALPHA;
|
| ︙ | ︙ | |||
614 615 616 617 618 619 620 |
case STR_IS_WORD:
strClassType = STR_CLASS_WORD;
goto compileStrClass;
case STR_IS_XDIGIT:
strClassType = STR_CLASS_XDIGIT;
compileStrClass:
if (allowEmpty) {
| | | | | | | | | | | | | | | | > | | | | | | | | | > | | | < | < | | < | > | | | < | | < | | > | | | | | | | | | | | | | | | | | | | | | | | > | | < > | | | | | | | | | | | | | > | < | < | > | | | | | | > | < | < | | > | | | | > | < > | | > > > | > > | > > > | | | | | | > > | | | > > > | > | | | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 |
case STR_IS_WORD:
strClassType = STR_CLASS_WORD;
goto compileStrClass;
case STR_IS_XDIGIT:
strClassType = STR_CLASS_XDIGIT;
compileStrClass:
if (allowEmpty) {
OP1( STR_CLASS, strClassType);
} else {
int over, over2;
OP( DUP);
OP1( STR_CLASS, strClassType);
JUMP1( JUMP_TRUE, over);
OP( POP);
PUSH( "0");
JUMP1( JUMP, over2);
FIXJUMP1(over);
PUSH( "");
OP( STR_NEQ);
FIXJUMP1(over2);
}
return TCL_OK;
case STR_IS_BOOL:
case STR_IS_FALSE:
case STR_IS_TRUE:
OP( TRY_CVT_TO_BOOLEAN);
switch (t) {
int over, over2;
case STR_IS_BOOL:
if (allowEmpty) {
JUMP1( JUMP_TRUE, over);
PUSH( "");
OP( STR_EQ);
JUMP1( JUMP, over2);
FIXJUMP1(over);
OP( POP);
PUSH( "1");
FIXJUMP1(over2);
} else {
OP4( REVERSE, 2);
OP( POP);
}
return TCL_OK;
case STR_IS_TRUE:
JUMP1( JUMP_TRUE, over);
if (allowEmpty) {
PUSH( "");
OP( STR_EQ);
} else {
OP( POP);
PUSH( "0");
}
FIXJUMP1( over);
OP( LNOT);
OP( LNOT);
return TCL_OK;
case STR_IS_FALSE:
JUMP1( JUMP_TRUE, over);
if (allowEmpty) {
PUSH( "");
OP( STR_NEQ);
} else {
OP( POP);
PUSH( "1");
}
FIXJUMP1( over);
OP( LNOT);
return TCL_OK;
default:
break;
}
break;
case STR_IS_DOUBLE: {
int satisfied, isEmpty;
if (allowEmpty) {
OP( DUP);
PUSH( "");
OP( STR_EQ);
JUMP1( JUMP_TRUE, isEmpty);
OP( NUM_TYPE);
JUMP1( JUMP_TRUE, satisfied);
PUSH( "0");
JUMP1( JUMP, end);
FIXJUMP1( isEmpty);
OP( POP);
FIXJUMP1( satisfied);
} else {
OP( NUM_TYPE);
JUMP1( JUMP_TRUE, satisfied);
PUSH( "0");
JUMP1( JUMP, end);
TclAdjustStackDepth(-1, envPtr);
FIXJUMP1( satisfied);
}
PUSH( "1");
FIXJUMP1( end);
return TCL_OK;
}
case STR_IS_INT:
case STR_IS_WIDE:
case STR_IS_ENTIER:
if (allowEmpty) {
int testNumType;
OP( DUP);
OP( NUM_TYPE);
OP( DUP);
JUMP1( JUMP_TRUE, testNumType);
OP( POP);
PUSH( "");
OP( STR_EQ);
JUMP1( JUMP, end);
TclAdjustStackDepth(1, envPtr);
FIXJUMP1( testNumType);
OP4( REVERSE, 2);
OP( POP);
} else {
OP( NUM_TYPE);
OP( DUP);
JUMP1( JUMP_FALSE, end);
}
switch (t) {
case STR_IS_WIDE:
PUSH( "2");
OP( LE);
break;
case STR_IS_INT:
case STR_IS_ENTIER:
PUSH( "3");
OP( LE);
break;
default:
break;
}
FIXJUMP1( end);
return TCL_OK;
case STR_IS_DICT:
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
OP( DUP);
OP( DICT_VERIFY);
ExceptionRangeEnds(envPtr, range);
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( POP);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
OP( LNOT);
return TCL_OK;
case STR_IS_LIST:
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
OP( DUP);
OP( LIST_LENGTH);
OP( POP);
ExceptionRangeEnds(envPtr, range);
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( POP);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
OP( LNOT);
return TCL_OK;
}
return TclCompileBasicMin0ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
int
TclCompileStringMatchCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
size_t length;
int i, exactMatch = 0, nocase = 0;
const char *str;
if (parsePtr->numWords < 3 || parsePtr->numWords > 4) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
/*
* Check if we have a -nocase flag.
*/
if (parsePtr->numWords == 4) {
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
str = tokenPtr[1].start;
length = tokenPtr[1].size;
if ((length <= 1) || strncmp(str, "-nocase", length)) {
/*
* Fail at run time, not in compilation.
*/
return TclCompileBasic3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
nocase = 1;
tokenPtr = TokenAfter(tokenPtr);
}
/*
* Push the strings to match against each other.
*/
for (i = 0; i < 2; i++) {
if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
str = tokenPtr[1].start;
length = tokenPtr[1].size;
if (!nocase && (i == 0)) {
/*
* Trivial matches can be done by 'string equal'. If -nocase
* was specified, we can't do this because INST_STR_EQ has no
* support for nocase.
*/
Tcl_Obj *copy = Tcl_NewStringObj(str, length);
Tcl_IncrRefCount(copy);
exactMatch = TclMatchIsTrivial(TclGetString(copy));
TclDecrRefCount(copy);
}
PushLiteral(envPtr, str, length);
} else {
SetLineInformation(i+1+nocase);
CompileTokens(envPtr, tokenPtr, interp);
}
tokenPtr = TokenAfter(tokenPtr);
}
/*
* Push the matcher.
*/
if (exactMatch) {
TclEmitOpcode(INST_STR_EQ, envPtr);
} else {
TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr);
}
return TCL_OK;
}
int
TclCompileStringLenCmd(
Tcl_Interp *interp, /* Used for error reporting. */
|
| ︙ | ︙ | |||
874 875 876 877 878 879 880 |
if (TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
/*
* Here someone is asking for the length of a static string (or
* something with backslashes). Just push the actual character (not
* byte) length.
*/
| > | | > > | > | | 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
if (TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
/*
* Here someone is asking for the length of a static string (or
* something with backslashes). Just push the actual character (not
* byte) length.
*/
char buf[TCL_INTEGER_SPACE];
size_t len = Tcl_GetCharLength(objPtr);
len = snprintf(buf, sizeof(buf), "%" TCL_Z_MODIFIER "u", len);
PushLiteral(envPtr, buf, len);
} else {
SetLineInformation(1);
CompileTokens(envPtr, tokenPtr, interp);
TclEmitOpcode(INST_STR_LEN, envPtr);
}
TclDecrRefCount(objPtr);
return TCL_OK;
}
int
TclCompileStringMapCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *mapTokenPtr, *stringTokenPtr;
Tcl_Obj *mapObj, **objv;
const char *bytes;
Tcl_Size len, slen;
/*
* We only handle the case:
*
* string map {foo bar} $thing
*
* That is, a literal two-element list (doesn't need to be brace-quoted,
|
| ︙ | ︙ | |||
933 934 935 936 937 938 939 |
/*
* Now issue the opcodes. Note that in the case that we know that the
* first word is an empty word, we don't issue the map at all. That is the
* correct semantics for mapping.
*/
| | > | < > | > | | | 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
/*
* Now issue the opcodes. Note that in the case that we know that the
* first word is an empty word, we don't issue the map at all. That is the
* correct semantics for mapping.
*/
bytes = TclGetStringFromObj(objv[0], &slen);
if (slen == 0) {
CompileWord(envPtr, stringTokenPtr, interp, 2);
} else {
PushLiteral(envPtr, bytes, slen);
bytes = TclGetStringFromObj(objv[1], &slen);
PushLiteral(envPtr, bytes, slen);
CompileWord(envPtr, stringTokenPtr, interp, 2);
OP(STR_MAP);
}
Tcl_DecrRefCount(mapObj);
return TCL_OK;
}
int
TclCompileStringRangeCmd(
|
| ︙ | ︙ | |||
965 966 967 968 969 970 971 |
return TCL_ERROR;
}
stringTokenPtr = TokenAfter(parsePtr->tokenPtr);
fromTokenPtr = TokenAfter(stringTokenPtr);
toTokenPtr = TokenAfter(fromTokenPtr);
/* Every path must push the string argument */
| | | | | | | | | | | | | 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 |
return TCL_ERROR;
}
stringTokenPtr = TokenAfter(parsePtr->tokenPtr);
fromTokenPtr = TokenAfter(stringTokenPtr);
toTokenPtr = TokenAfter(fromTokenPtr);
/* Every path must push the string argument */
CompileWord(envPtr, stringTokenPtr, interp, 1);
/*
* Parse the two indices.
*/
if (TclGetIndexFromToken(fromTokenPtr, TCL_INDEX_START, TCL_INDEX_NONE,
&idx1) != TCL_OK) {
goto nonConstantIndices;
}
/*
* Token parsed as an index expression. We treat all indices before
* the string the same as the start of the string.
*/
if (idx1 == (int)TCL_INDEX_NONE) {
/* [string range $s end+1 $last] must be empty string */
OP( POP);
PUSH( "");
return TCL_OK;
}
if (TclGetIndexFromToken(toTokenPtr, TCL_INDEX_NONE, TCL_INDEX_END,
&idx2) != TCL_OK) {
goto nonConstantIndices;
}
/*
* Token parsed as an index expression. We treat all indices after
* the string the same as the end of the string.
*/
if (idx2 == (int)TCL_INDEX_NONE) {
/* [string range $s $first -1] must be empty string */
OP( POP);
PUSH( "");
return TCL_OK;
}
/*
* Push the operand onto the stack and then the substring operation.
*/
OP44( STR_RANGE_IMM, idx1, idx2);
return TCL_OK;
/*
* Push the operands onto the stack and then the substring operation.
*/
nonConstantIndices:
CompileWord(envPtr, fromTokenPtr, interp, 2);
CompileWord(envPtr, toTokenPtr, interp, 3);
OP( STR_RANGE);
return TCL_OK;
}
int
TclCompileStringReplaceCmd(
Tcl_Interp *interp, /* Tcl interpreter for context. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr, *valueTokenPtr;
int first, last;
if ((int)parsePtr->numWords < 4 || (int)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.
*/
tokenPtr = TokenAfter(valueTokenPtr);
if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_NONE,
&first) != TCL_OK) {
|
| ︙ | ︙ | |||
1099 1100 1101 1102 1103 1104 1105 |
* (last <= TCL_INDEX_END) => cannot tell REJECT
* else [[last >= TCL_INDEX START]] && (last < first) => ACCEPT
*/
|| ((first >= (int)TCL_INDEX_START) && (last >= (int)TCL_INDEX_START)
&& (last < first))) { /* Know (last < first) */
if (parsePtr->numWords == 5) {
tokenPtr = TokenAfter(tokenPtr);
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 |
* (last <= TCL_INDEX_END) => cannot tell REJECT
* else [[last >= TCL_INDEX START]] && (last < first) => ACCEPT
*/
|| ((first >= (int)TCL_INDEX_START) && (last >= (int)TCL_INDEX_START)
&& (last < first))) { /* Know (last < first) */
if (parsePtr->numWords == 5) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
OP( POP); /* Pop newString */
}
/* Original string argument now on TOS as result */
return TCL_OK;
}
if (parsePtr->numWords == 5) {
/*
* When we have a string replacement, we have to take care about
* not replacing empty substrings that [string replace] promises
* not to replace
*
* The remaining index values might be suitable for conventional
* string replacement, but only if they cannot possibly meet the
* conditions described above at runtime. If there's a chance they
* might, we would have to emit bytecode to check and at that point
* we're paying more in bytecode execution time than would make
* things worthwhile. Trouble is we are very limited in
* how much we can detect that at compile time. After decoding,
* we need, first:
*
* (first <= end)
*
* The encoded indices (first <= TCL_INDEX END) and
* (first == TCL_INDEX_NONE) always meets this condition, but
* any other encoded first index has some list for which it fails.
*
* We also need, second:
*
* (last >= 0)
*
* The encoded index (last >= TCL_INDEX_START) always meet this
* condition but any other encoded last index has some list for
* which it fails.
*
* Finally we need, third:
*
* (first <= last)
*
* Considered in combination with the constraints we already have,
* we see that we can proceed when (first == TCL_INDEX_NONE).
* These also permit simplification of the prefix|replace|suffix
* construction. The other constraints, though, interfere with
* getting a guarantee that first <= last.
*/
if ((first == (int)TCL_INDEX_START) && (last >= (int)TCL_INDEX_START)) {
/* empty prefix */
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
OP4( REVERSE, 2);
if (last == INT_MAX) {
OP( POP); /* Pop original */
} else {
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
OP1( STR_CONCAT1, 2);
}
return TCL_OK;
}
if ((last == (int)TCL_INDEX_NONE) && (first <= (int)TCL_INDEX_END)) {
OP44( STR_RANGE_IMM, 0, first-1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
OP1( STR_CONCAT1, 2);
return TCL_OK;
}
/* 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.
*/
if (first == (int)TCL_INDEX_START) {
/* empty prefix - build suffix only */
if (last == (int)TCL_INDEX_END) {
/* empty suffix too => empty result */
OP( POP); /* Pop original */
PUSH ( "");
return TCL_OK;
}
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
return TCL_OK;
} else {
if (last == (int)TCL_INDEX_END) {
/* empty suffix - build prefix only */
OP44( STR_RANGE_IMM, 0, first-1);
return TCL_OK;
}
OP( DUP);
OP44( STR_RANGE_IMM, 0, first-1);
OP4( REVERSE, 2);
OP44( STR_RANGE_IMM, last + 1, (int)TCL_INDEX_END);
OP1( STR_CONCAT1, 2);
return TCL_OK;
}
}
genericReplace:
tokenPtr = TokenAfter(valueTokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
if (parsePtr->numWords == 5) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 4);
} else {
PUSH( "");
}
OP( STR_REPLACE);
return TCL_OK;
}
int
TclCompileStringTrimLCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
} else {
PushLiteral(envPtr, tclDefaultTrimSet, strlen(tclDefaultTrimSet));
}
OP( STR_TRIM_LEFT);
return TCL_OK;
}
int
TclCompileStringTrimRCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
} else {
PushLiteral(envPtr, tclDefaultTrimSet, strlen(tclDefaultTrimSet));
}
OP( STR_TRIM_RIGHT);
return TCL_OK;
}
int
TclCompileStringTrimCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
} else {
PushLiteral(envPtr, tclDefaultTrimSet, strlen(tclDefaultTrimSet));
}
OP( STR_TRIM);
return TCL_OK;
}
int
TclCompileStringToUpperCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TclCompileBasic1To3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
OP( STR_UPPER);
return TCL_OK;
}
int
TclCompileStringToLowerCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TclCompileBasic1To3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
OP( STR_LOWER);
return TCL_OK;
}
int
TclCompileStringToTitleCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TclCompileBasic1To3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
OP( STR_TITLE);
return TCL_OK;
}
/*
* Support definitions for the [string is] compilation.
*/
|
| ︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
| | | | | | | < > < > | | | | | | | < | | | < < < > > > | > | > | 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
int numArgs = parsePtr->numWords - 1;
int numOpts = numArgs - 1;
int objc, flags = TCL_SUBST_ALL;
Tcl_Obj **objv/*, *toSubst = NULL*/;
Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
int code = TCL_ERROR;
if (numArgs == 0) {
return TCL_ERROR;
}
objv = (Tcl_Obj **)TclStackAlloc(interp, /*numArgs*/ numOpts * sizeof(Tcl_Obj *));
for (objc = 0; objc < /*numArgs*/ numOpts; objc++) {
TclNewObj(objv[objc]);
Tcl_IncrRefCount(objv[objc]);
if (!TclWordKnownAtCompileTime(wordTokenPtr, objv[objc])) {
objc++;
goto cleanup;
}
wordTokenPtr = TokenAfter(wordTokenPtr);
}
/*
if (TclSubstOptions(NULL, numOpts, objv, &flags) == TCL_OK) {
toSubst = objv[numOpts];
Tcl_IncrRefCount(toSubst);
}
*/
/* TODO: Figure out expansion to cover WordKnownAtCompileTime
* The difficulty is that WKACT makes a copy, and if TclSubstParse
* below parses the copy of the original source string, some deep
* parts of the compile machinery get upset. They want all pointers
* stored in Tcl_Tokens to point back to the same original string.
*/
if (wordTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
code = TclSubstOptions(NULL, numOpts, objv, &flags);
}
cleanup:
while (--objc >= 0) {
TclDecrRefCount(objv[objc]);
}
TclStackFree(interp, objv);
if (/*toSubst == NULL*/ code != TCL_OK) {
return TCL_ERROR;
}
SetLineInformation(numArgs);
TclSubstCompile(interp, wordTokenPtr[1].start, wordTokenPtr[1].size,
flags, mapPtr->loc[eclIndex].line[numArgs], envPtr);
/* TclDecrRefCount(toSubst);*/
return TCL_OK;
}
void
TclSubstCompile(
Tcl_Interp *interp,
const char *bytes,
Tcl_Size numBytes,
int flags,
Tcl_Size line,
CompileEnv *envPtr)
{
Tcl_Token *endTokenPtr, *tokenPtr;
int breakOffset = 0, count = 0;
Tcl_Size bline = line;
Tcl_Parse parse;
Tcl_InterpState state = NULL;
TclSubstParse(interp, bytes, numBytes, flags, &parse, &state);
if (state != NULL) {
Tcl_ResetResult(interp);
}
/*
* Tricky point! If the first token does not result in a *guaranteed* push
* of a Tcl_Obj on the stack, we must push an empty object. Otherwise it
* is possible to get to an INST_STR_CONCAT1 or INST_DONE without enough
* values on the stack, resulting in a crash. Thanks to Joe Mistachkin for
* identifying a script that could trigger this case.
*/
tokenPtr = parse.tokenPtr;
if (tokenPtr->type != TCL_TOKEN_TEXT && tokenPtr->type != TCL_TOKEN_BS) {
PUSH("");
count++;
}
for (endTokenPtr = tokenPtr + parse.numTokens;
tokenPtr < endTokenPtr; tokenPtr = TokenAfter(tokenPtr)) {
Tcl_Size length;
int literal, catchRange, breakJump;
char buf[4] = "";
JumpFixup startFixup, okFixup, returnFixup, breakFixup;
JumpFixup continueFixup, otherFixup, endFixup;
switch (tokenPtr->type) {
case TCL_TOKEN_TEXT:
literal = TclRegisterLiteral(envPtr,
tokenPtr->start, tokenPtr->size, 0);
TclEmitPush(literal, envPtr);
TclAdvanceLines(&bline, tokenPtr->start,
tokenPtr->start + tokenPtr->size);
count++;
continue;
case TCL_TOKEN_BS:
length = TclParseBackslash(tokenPtr->start, tokenPtr->size,
NULL, buf);
literal = TclRegisterLiteral(envPtr, buf, length, 0);
TclEmitPush(literal, envPtr);
count++;
continue;
case TCL_TOKEN_VARIABLE:
/*
* Check for simple variable access; see if we can only generate
* TCL_OK or TCL_ERROR from the substituted variable read; if so,
* there is no need to generate elaborate exception-management
|
| ︙ | ︙ | |||
1583 1584 1585 1586 1587 1588 1589 |
}
if (count > 1) {
OP1( STR_CONCAT1, count);
count = 1;
}
if (breakOffset == 0) {
| < | | > > > | | | > | | | > | | | | | | | | | | | | | | | > | | | | > > | | < < < < | < | | | | > | > > > > > > > > > > > > > > > | < | > > > > | > > | > > > | | > > > > > > | < < > > > > > > < > > > > | | > > > | | | < < < | < < < < < < < < < < | < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < | 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 |
}
if (count > 1) {
OP1( STR_CONCAT1, count);
count = 1;
}
if (breakOffset == 0) {
/* Jump to the start (jump over the jump to end) */
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &startFixup);
/* Jump to the end (all BREAKs land here) */
breakOffset = CurrentOffset(envPtr);
TclEmitInstInt4(INST_JUMP4, 0, envPtr);
/* Start */
if (TclFixupForwardJumpToHere(envPtr, &startFixup, 127)) {
Tcl_Panic("TclCompileSubstCmd: bad start jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - startFixup.codeOffset);
}
}
envPtr->line = bline;
catchRange = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, catchRange);
ExceptionRangeStarts(envPtr, catchRange);
switch (tokenPtr->type) {
case TCL_TOKEN_COMMAND:
TclCompileScript(interp, tokenPtr->start+1, tokenPtr->size-2,
envPtr);
count++;
break;
case TCL_TOKEN_VARIABLE:
TclCompileVarSubst(interp, tokenPtr, envPtr);
count++;
break;
default:
Tcl_Panic("unexpected token type in TclCompileSubstCmd: %d",
tokenPtr->type);
}
ExceptionRangeEnds(envPtr, catchRange);
/* Substitution produced TCL_OK */
OP( END_CATCH);
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &okFixup);
TclAdjustStackDepth(-1, envPtr);
/* Exceptional return codes processed here */
ExceptionRangeTarget(envPtr, catchRange, catchOffset);
OP( PUSH_RETURN_OPTIONS);
OP( PUSH_RESULT);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
OP( RETURN_CODE_BRANCH);
/* ERROR -> reraise it; NB: can't require BREAK/CONTINUE handling */
OP( RETURN_STK);
OP( NOP);
/* RETURN */
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &returnFixup);
/* BREAK */
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &breakFixup);
/* CONTINUE */
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &continueFixup);
/* OTHER */
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &otherFixup);
TclAdjustStackDepth(1, envPtr);
/* BREAK destination */
if (TclFixupForwardJumpToHere(envPtr, &breakFixup, 127)) {
Tcl_Panic("TclCompileSubstCmd: bad break jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - breakFixup.codeOffset);
}
OP( POP);
OP( POP);
breakJump = CurrentOffset(envPtr) - breakOffset;
if (breakJump > 127) {
OP4(JUMP4, -breakJump);
} else {
OP1(JUMP1, -breakJump);
}
TclAdjustStackDepth(2, envPtr);
/* CONTINUE destination */
if (TclFixupForwardJumpToHere(envPtr, &continueFixup, 127)) {
Tcl_Panic("TclCompileSubstCmd: bad continue jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - continueFixup.codeOffset);
}
OP( POP);
OP( POP);
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &endFixup);
TclAdjustStackDepth(2, envPtr);
/* RETURN + other destination */
if (TclFixupForwardJumpToHere(envPtr, &returnFixup, 127)) {
Tcl_Panic("TclCompileSubstCmd: bad return jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - returnFixup.codeOffset);
}
if (TclFixupForwardJumpToHere(envPtr, &otherFixup, 127)) {
Tcl_Panic("TclCompileSubstCmd: bad other jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - otherFixup.codeOffset);
}
/*
* Pull the result to top of stack, discard options dict.
*/
OP4( REVERSE, 2);
OP( POP);
/* OK destination */
if (TclFixupForwardJumpToHere(envPtr, &okFixup, 127)) {
Tcl_Panic("TclCompileSubstCmd: bad ok jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - okFixup.codeOffset);
}
if (count > 1) {
OP1(STR_CONCAT1, count);
count = 1;
}
/* CONTINUE jump to here */
if (TclFixupForwardJumpToHere(envPtr, &endFixup, 127)) {
Tcl_Panic("TclCompileSubstCmd: bad end jump distance %" TCL_Z_MODIFIER "d",
CurrentOffset(envPtr) - endFixup.codeOffset);
}
bline = envPtr->line;
}
while (count > 255) {
OP1( STR_CONCAT1, 255);
count -= 254;
}
if (count > 1) {
OP1( STR_CONCAT1, count);
}
Tcl_FreeParse(&parse);
if (state != NULL) {
Tcl_RestoreInterpState(interp, state);
TclCompileSyntaxError(interp, envPtr);
TclAdjustStackDepth(-1, envPtr);
}
/* Final target of the multi-jump from all BREAKs */
if (breakOffset > 0) {
TclUpdateInstInt4AtPc(INST_JUMP4, CurrentOffset(envPtr) - breakOffset,
envPtr->codeStart + breakOffset);
}
}
/*
*----------------------------------------------------------------------
*
* TclCompileSwitchCmd --
*
* Procedure called to compile the "switch" command.
|
| ︙ | ︙ | |||
1753 1754 1755 1756 1757 1758 1759 | * Side effects: * Instructions are added to envPtr to execute the "switch" command at * runtime. * *---------------------------------------------------------------------- */ | < < < < < < < < | > | > > | > > | | | | | < | | | | < | | < < < | 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 |
* Side effects:
* Instructions are added to envPtr to execute the "switch" command at
* runtime.
*
*----------------------------------------------------------------------
*/
int
TclCompileSwitchCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr; /* Pointer to tokens in command. */
int numWords; /* Number of words in command. */
Tcl_Token *valueTokenPtr; /* Token for the value to switch on. */
enum {Switch_Exact, Switch_Glob, Switch_Regexp} mode;
/* What kind of switch are we doing? */
Tcl_Token *bodyTokenArray; /* Array of real pattern list items. */
Tcl_Token **bodyToken; /* Array of pointers to pattern list items. */
Tcl_Size *bodyLines; /* Array of line numbers for body list
* items. */
Tcl_Size **bodyContLines; /* Array of continuation line info. */
int noCase; /* Has the -nocase flag been given? */
int foundMode = 0; /* Have we seen a mode flag yet? */
int i, valueIndex;
int result = TCL_ERROR;
Tcl_Size *clNext = envPtr->clNext;
/*
* Only handle the following versions:
* switch ?--? word {pattern body ...}
* switch -exact ?--? word {pattern body ...}
* switch -glob ?--? word {pattern body ...}
* switch -regexp ?--? word {pattern body ...}
* switch -- word simpleWordPattern simpleWordBody ...
* switch -exact -- word simpleWordPattern simpleWordBody ...
* switch -glob -- word simpleWordPattern simpleWordBody ...
* switch -regexp -- word simpleWordPattern simpleWordBody ...
* When the mode is -glob, can also handle a -nocase flag.
*
* First off, we don't care how the command's word was generated; we're
* compiling it anyway! So skip it...
*/
tokenPtr = TokenAfter(parsePtr->tokenPtr);
valueIndex = 1;
numWords = parsePtr->numWords-1;
/*
* Check for options.
*/
noCase = 0;
mode = Switch_Exact;
|
| ︙ | ︙ | |||
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 |
* way to statically avoid the problems you get from strings-to-be-matched
* that start with a - (the interpreted code falls apart if it encounters
* them, so we punt if we *might* encounter them as that is the easiest
* way of emulating the behaviour).
*/
for (; numWords>=3 ; tokenPtr=TokenAfter(tokenPtr),numWords--) {
/*
* We only process literal options, and we assume that -e, -g and -n
* are unique prefixes of -exact, -glob and -nocase respectively (true
* at time of writing). Note that -exact and -glob may only be given
* at most once or we bail out (error case).
*/
| > > > > > > | > | | < < < < < < < < | | < < < < < < < < > > | | > > > > > > > | 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 |
* way to statically avoid the problems you get from strings-to-be-matched
* that start with a - (the interpreted code falls apart if it encounters
* them, so we punt if we *might* encounter them as that is the easiest
* way of emulating the behaviour).
*/
for (; numWords>=3 ; tokenPtr=TokenAfter(tokenPtr),numWords--) {
size_t size = tokenPtr[1].size;
const char *chrs = tokenPtr[1].start;
/*
* We only process literal options, and we assume that -e, -g and -n
* are unique prefixes of -exact, -glob and -nocase respectively (true
* at time of writing). Note that -exact and -glob may only be given
* at most once or we bail out (error case).
*/
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || size < 2) {
return TCL_ERROR;
}
if ((size <= 6) && !memcmp(chrs, "-exact", size)) {
if (foundMode) {
return TCL_ERROR;
}
mode = Switch_Exact;
foundMode = 1;
valueIndex++;
continue;
} else if ((size <= 5) && !memcmp(chrs, "-glob", size)) {
if (foundMode) {
return TCL_ERROR;
}
mode = Switch_Glob;
foundMode = 1;
valueIndex++;
continue;
} else if ((size <= 7) && !memcmp(chrs, "-regexp", size)) {
if (foundMode) {
return TCL_ERROR;
}
mode = Switch_Regexp;
foundMode = 1;
valueIndex++;
continue;
} else if ((size <= 7) && !memcmp(chrs, "-nocase", size)) {
noCase = 1;
valueIndex++;
continue;
} else if ((size == 2) && !memcmp(chrs, "--", 2)) {
valueIndex++;
break;
}
/*
* The switch command has many flags we cannot compile at all (e.g.
* all the RE-related ones) which we must have encountered. Either
* that or we have run off the end. The action here is the same: punt
* to interpreted version.
*/
return TCL_ERROR;
}
if (numWords < 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(tokenPtr);
numWords--;
if (noCase && (mode == Switch_Exact)) {
/*
* Can't compile this case; no opcode for case-insensitive equality!
*/
return TCL_ERROR;
}
/*
* The value to test against is going to always get pushed on the stack.
* But not yet; we need to verify that the rest of the command is
* compilable too.
*/
|
| ︙ | ︙ | |||
1925 1926 1927 1928 1929 1930 1931 |
* causes a crash during exception handling). When multiple tokens are
* available at this point, this is pretty easy.
*/
if (numWords == 1) {
const char *bytes;
Tcl_Size maxLen, numBytes;
| | < < < | | | | | < < < < < < | < < | | | | | < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | < | | > > > > > | | | < < < < < > < < < < < > > > | | | < < < < < < < < < < < < < < < < < < < < < < < | > | | | | < | > | > > | < < < < | > > > > > | > | > | | | | < | | | | > | | | < < | > | < | | | | | | < < < < < < | | | | | > | | | | > | | | | | | | > | | | > | | > | 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 |
* causes a crash during exception handling). When multiple tokens are
* available at this point, this is pretty easy.
*/
if (numWords == 1) {
const char *bytes;
Tcl_Size maxLen, numBytes;
Tcl_Size bline; /* TIP #280: line of the pattern/action list,
* and start of list for when tracking the
* location. This list comes immediately after
* the value we switch on. */
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TCL_ERROR;
}
bytes = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
/* Allocate enough space to work in. */
maxLen = TclMaxListLength(bytes, numBytes, NULL);
if (maxLen < 2) {
return TCL_ERROR;
}
bodyTokenArray = (Tcl_Token *)Tcl_Alloc(sizeof(Tcl_Token) * maxLen);
bodyToken = (Tcl_Token **)Tcl_Alloc(sizeof(Tcl_Token *) * maxLen);
bodyLines = (Tcl_Size *)Tcl_Alloc(sizeof(Tcl_Size) * maxLen);
bodyContLines = (Tcl_Size **)Tcl_Alloc(sizeof(Tcl_Size*) * maxLen);
bline = mapPtr->loc[eclIndex].line[valueIndex+1];
numWords = 0;
while (numBytes > 0) {
const char *prevBytes = bytes;
int literal;
if (TCL_OK != TclFindElement(NULL, bytes, numBytes,
&(bodyTokenArray[numWords].start), &bytes,
&(bodyTokenArray[numWords].size), &literal) || !literal) {
goto abort;
}
bodyTokenArray[numWords].type = TCL_TOKEN_TEXT;
bodyTokenArray[numWords].numComponents = 0;
bodyToken[numWords] = bodyTokenArray + numWords;
/*
* TIP #280: Now determine the line the list element starts on
* (there is no need to do it earlier, due to the possibility of
* aborting, see above).
*/
TclAdvanceLines(&bline, prevBytes, bodyTokenArray[numWords].start);
TclAdvanceContinuations(&bline, &clNext,
bodyTokenArray[numWords].start - envPtr->source);
bodyLines[numWords] = bline;
bodyContLines[numWords] = clNext;
TclAdvanceLines(&bline, bodyTokenArray[numWords].start, bytes);
TclAdvanceContinuations(&bline, &clNext, bytes - envPtr->source);
numBytes -= (bytes - prevBytes);
numWords++;
}
if (numWords % 2) {
abort:
Tcl_Free(bodyToken);
Tcl_Free(bodyTokenArray);
Tcl_Free(bodyLines);
Tcl_Free(bodyContLines);
return TCL_ERROR;
}
} else if (numWords % 2 || numWords == 0) {
/*
* Odd number of words (>1) available, or no words at all available.
* Both are error cases, so punt and let the interpreted-version
* generate the error message. Note that the second case probably
* should get caught earlier, but it's easy to check here again anyway
* because it'd cause a nasty crash otherwise.
*/
return TCL_ERROR;
} else {
/*
* Multi-word definition of patterns & actions.
*/
bodyToken = (Tcl_Token **)Tcl_Alloc(sizeof(Tcl_Token *) * numWords);
bodyLines = (Tcl_Size *)Tcl_Alloc(sizeof(Tcl_Size) * numWords);
bodyContLines = (Tcl_Size **)Tcl_Alloc(sizeof(Tcl_Size*) * numWords);
bodyTokenArray = NULL;
for (i=0 ; i<numWords ; i++) {
/*
* We only handle the very simplest case. Anything more complex is
* a good reason to go to the interpreted case anyway due to
* traces, etc.
*/
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
goto freeTemporaries;
}
bodyToken[i] = tokenPtr+1;
/*
* TIP #280: Copy line information from regular cmd info.
*/
bodyLines[i] = mapPtr->loc[eclIndex].line[valueIndex+1+i];
bodyContLines[i] = mapPtr->loc[eclIndex].next[valueIndex+1+i];
tokenPtr = TokenAfter(tokenPtr);
}
}
/*
* Fall back to interpreted if the last body is a continuation (it's
* illegal, but this makes the error happen at the right time).
*/
if (bodyToken[numWords-1]->size == 1 &&
bodyToken[numWords-1]->start[0] == '-') {
goto freeTemporaries;
}
/*
* Now we commit to generating code; the parsing stage per se is done.
* Check if we can generate a jump table, since if so that's faster than
* doing an explicit compare with each body. Note that we're definitely
* over-conservative with determining whether we can do the jump table,
* but it handles the most common case well enough.
*/
/* Both methods push the value to match against onto the stack. */
CompileWord(envPtr, valueTokenPtr, interp, valueIndex);
if (mode == Switch_Exact) {
IssueSwitchJumpTable(interp, envPtr, numWords, bodyToken,
bodyLines, bodyContLines);
} else {
IssueSwitchChainedTests(interp, envPtr, mode, noCase,
numWords, bodyToken, bodyLines, bodyContLines);
}
result = TCL_OK;
/*
* Clean up all our temporary space and return.
*/
freeTemporaries:
Tcl_Free(bodyToken);
Tcl_Free(bodyLines);
Tcl_Free(bodyContLines);
if (bodyTokenArray != NULL) {
Tcl_Free(bodyTokenArray);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* IssueSwitchChainedTests --
*
* Generate instructions for a [switch] command that is to be compiled
* into a sequence of tests. This is the generic handle-everything mode
* that inherently has performance that is (on average) linear in the
* number of tests. It is the only mode that can handle -glob and -regexp
* matches, or anything that is case-insensitive. It does not handle the
* wild-and-wooly end of regexp matching (i.e., capture of match results)
* so that's when we spill to the interpreted version.
*
*----------------------------------------------------------------------
*/
static void
IssueSwitchChainedTests(
Tcl_Interp *interp, /* Context for compiling script bodies. */
CompileEnv *envPtr, /* Holds resulting instructions. */
int mode, /* Exact, Glob or Regexp */
int noCase, /* Case-insensitivity flag. */
Tcl_Size numBodyTokens, /* Number of tokens describing things the
* switch can match against and bodies to
* execute when the match succeeds. */
Tcl_Token **bodyToken, /* Array of pointers to pattern list items. */
Tcl_Size *bodyLines, /* Array of line numbers for body list
* items. */
Tcl_Size **bodyContLines) /* Array of continuation line info. */
{
enum {Switch_Exact, Switch_Glob, Switch_Regexp};
int foundDefault; /* Flag to indicate whether a "default" clause
* is present. */
JumpFixup *fixupArray; /* Array of forward-jump fixup records. */
unsigned int *fixupTargetArray; /* Array of places for fixups to point at. */
int fixupCount; /* Number of places to fix up. */
int contFixIndex; /* Where the first of the jumps due to a group
* of continuation bodies starts, or -1 if
* there aren't any. */
int contFixCount; /* Number of continuation bodies pointing to
* the current (or next) real body. */
int nextArmFixupIndex;
int simple, exact; /* For extracting the type of regexp. */
int i;
/*
* Generate a test for each arm.
*/
contFixIndex = -1;
contFixCount = 0;
fixupArray = (JumpFixup *)TclStackAlloc(interp, sizeof(JumpFixup) * numBodyTokens);
fixupTargetArray = (unsigned int *)TclStackAlloc(interp, sizeof(int) * numBodyTokens);
memset(fixupTargetArray, 0, numBodyTokens * sizeof(int));
fixupCount = 0;
foundDefault = 0;
for (i=0 ; i<numBodyTokens ; i+=2) {
nextArmFixupIndex = -1;
if (i!=numBodyTokens-2 || bodyToken[numBodyTokens-2]->size != 7 ||
memcmp(bodyToken[numBodyTokens-2]->start, "default", 7)) {
/*
* Generate the test for the arm.
*/
switch (mode) {
case Switch_Exact:
OP( DUP);
TclCompileTokens(interp, bodyToken[i], 1, envPtr);
OP( STR_EQ);
break;
case Switch_Glob:
TclCompileTokens(interp, bodyToken[i], 1, envPtr);
OP4( OVER, 1);
OP1( STR_MATCH, noCase);
break;
case Switch_Regexp:
simple = exact = 0;
/*
* Keep in sync with TclCompileRegexpCmd.
*/
if (bodyToken[i]->type == TCL_TOKEN_TEXT) {
Tcl_DString ds;
if (bodyToken[i]->size == 0) {
/*
* The semantics of regexps are that they always match
* when the RE == "".
*/
PUSH("1");
break;
}
/*
* Attempt to convert pattern to glob. If successful, push
* the converted pattern.
*/
if (TclReToGlob(NULL, bodyToken[i]->start,
bodyToken[i]->size, &ds, &exact, NULL) == TCL_OK){
simple = 1;
PushLiteral(envPtr, Tcl_DStringValue(&ds),
Tcl_DStringLength(&ds));
Tcl_DStringFree(&ds);
}
}
if (!simple) {
TclCompileTokens(interp, bodyToken[i], 1, envPtr);
}
OP4( OVER, 1);
if (!simple) {
/*
* Pass correct RE compile flags. We use only Int1
* (8-bit), but that handles all the flags we want to
* pass. Don't use TCL_REG_NOSUB as we may have backrefs
* or capture vars.
*/
int cflags = TCL_REG_ADVANCED
| (noCase ? TCL_REG_NOCASE : 0);
OP1(REGEXP, cflags);
} else if (exact && !noCase) {
OP( STR_EQ);
} else {
OP1(STR_MATCH, noCase);
}
break;
default:
TCL_UNREACHABLE();
}
/*
* In a fall-through case, we will jump on _true_ to the place
* where the body starts (generated later, with guarantee of this
* ensured earlier; the final body is never a fall-through).
*/
if (bodyToken[i+1]->size==1 && bodyToken[i+1]->start[0]=='-') {
if (contFixIndex == -1) {
contFixIndex = fixupCount;
contFixCount = 0;
}
TclEmitForwardJump(envPtr, TCL_TRUE_JUMP,
&fixupArray[contFixIndex+contFixCount]);
fixupCount++;
contFixCount++;
continue;
}
TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
&fixupArray[fixupCount]);
nextArmFixupIndex = fixupCount;
fixupCount++;
} else {
/*
* Got a default clause; set a flag to inhibit the generation of
* the jump after the body and the cleanup of the intermediate
* value that we are switching against.
*
* Note that default clauses (which are always terminal clauses)
|
| ︙ | ︙ | |||
2318 2319 2320 2321 2322 2323 2324 | /* * Generate the body for the arm. This is guaranteed not to be a * fall-through case, but it might have preceding fall-through cases, * so we must process those first. */ | > > | | < | | | | > | > | | < | | | > > > > > > > > > > > > > > | < > | | > > | > > > | | | > | > < < < < < | > > > > > | | | < < | < < < < < < < | > | | < | > > > | | | > | < < | > < < < | > > | < > > < < > < < > | | | > | | | | > > > > > > > > > | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < < < < | > > | | 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 |
/*
* Generate the body for the arm. This is guaranteed not to be a
* fall-through case, but it might have preceding fall-through cases,
* so we must process those first.
*/
if (contFixIndex != -1) {
int j;
for (j=0 ; j<contFixCount ; j++) {
fixupTargetArray[contFixIndex+j] = CurrentOffset(envPtr);
}
contFixIndex = -1;
}
/*
* Now do the actual compilation. Note that we do not use BODY()
* because we may have synthesized the tokens in a non-standard
* pattern.
*/
OP( POP);
envPtr->line = bodyLines[i+1]; /* TIP #280 */
envPtr->clNext = bodyContLines[i+1]; /* TIP #280 */
TclCompileCmdWord(interp, bodyToken[i+1], 1, envPtr);
if (!foundDefault) {
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
&fixupArray[fixupCount]);
fixupCount++;
fixupTargetArray[nextArmFixupIndex] = CurrentOffset(envPtr);
}
}
/*
* Discard the value we are matching against unless we've had a default
* clause (in which case it will already be gone due to the code at the
* start of processing an arm, guaranteed) and make the result of the
* command an empty string.
*/
if (!foundDefault) {
OP( POP);
PUSH("");
}
/*
* Do jump fixups for arms that were executed. First, fill in the jumps of
* all jumps that don't point elsewhere to point to here.
*/
for (i=0 ; i<fixupCount ; i++) {
if (fixupTargetArray[i] == 0) {
fixupTargetArray[i] = envPtr->codeNext-envPtr->codeStart;
}
}
/*
* Now scan backwards over all the jumps (all of which are forward jumps)
* doing each one. When we do one and there is a size changes, we must
* scan back over all the previous ones and see if they need adjusting
* before proceeding with further jump fixups (the interleaved nature of
* all the jumps makes this impossible to do without nested loops).
*/
for (i=fixupCount-1 ; i>=0 ; i--) {
if (TclFixupForwardJump(envPtr, &fixupArray[i],
fixupTargetArray[i] - fixupArray[i].codeOffset, 127)) {
int j;
for (j=i-1 ; j>=0 ; j--) {
if (fixupTargetArray[j] > fixupArray[i].codeOffset) {
fixupTargetArray[j] += 3;
}
}
}
}
TclStackFree(interp, fixupTargetArray);
TclStackFree(interp, fixupArray);
}
/*
*----------------------------------------------------------------------
*
* IssueSwitchJumpTable --
*
* Generate instructions for a [switch] command that is to be compiled
* into a jump table. This only handles the case where case-sensitive,
* exact matching is used, but this is actually the most common case in
* real code.
*
*----------------------------------------------------------------------
*/
static void
IssueSwitchJumpTable(
Tcl_Interp *interp, /* Context for compiling script bodies. */
CompileEnv *envPtr, /* Holds resulting instructions. */
int numBodyTokens, /* Number of tokens describing things the
* switch can match against and bodies to
* execute when the match succeeds. */
Tcl_Token **bodyToken, /* Array of pointers to pattern list items. */
Tcl_Size *bodyLines, /* Array of line numbers for body list
* items. */
Tcl_Size **bodyContLines) /* Array of continuation line info. */
{
JumptableInfo *jtPtr;
int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation;
int mustGenerate, foundDefault, jumpToDefault, i;
Tcl_DString buffer;
Tcl_HashEntry *hPtr;
/*
* Compile the switch by using a jump table, which is basically a
* hashtable that maps from literal values to match against to the offset
* (relative to the INST_JUMP_TABLE instruction) to jump to. The jump
* table itself is independent of any invocation of the bytecode, and as
* such is stored in an auxData block.
*
* Start by allocating the jump table itself, plus some workspace.
*/
jtPtr = (JumptableInfo *)Tcl_Alloc(sizeof(JumptableInfo));
Tcl_InitHashTable(&jtPtr->hashTable, TCL_STRING_KEYS);
infoIndex = TclCreateAuxData(jtPtr, &tclJumptableInfoType, envPtr);
finalFixups = (int *)TclStackAlloc(interp, sizeof(int) * (numBodyTokens/2));
foundDefault = 0;
mustGenerate = 1;
/*
* Next, issue the instruction to do the jump, together with what we want
* to do if things do not work out (jump to either the default clause or
* the "default" default, which just sets the result to empty). Note that
* we will come back and rewrite the jump's offset parameter when we know
* what it should be, and that all jumps we issue are of the wide kind
* because that makes the code much easier to debug!
*/
jumpLocation = CurrentOffset(envPtr);
OP4( JUMP_TABLE, infoIndex);
jumpToDefault = CurrentOffset(envPtr);
OP4( JUMP4, 0);
for (i=0 ; i<numBodyTokens ; i+=2) {
/*
* For each arm, we must first work out what to do with the match
* term.
*/
if (i!=numBodyTokens-2 || bodyToken[numBodyTokens-2]->size != 7 ||
memcmp(bodyToken[numBodyTokens-2]->start, "default", 7)) {
/*
* This is not a default clause, so insert the current location as
* a target in the jump table (assuming it isn't already there,
* which would indicate that this clause is probably masked by an
* earlier one). Note that we use a Tcl_DString here simply
* because the hash API does not let us specify the string length.
*/
Tcl_DStringInit(&buffer);
TclDStringAppendToken(&buffer, bodyToken[i]);
hPtr = Tcl_CreateHashEntry(&jtPtr->hashTable,
Tcl_DStringValue(&buffer), &isNew);
if (isNew) {
/*
* First time we've encountered this match clause, so it must
* point to here.
*/
Tcl_SetHashValue(hPtr, INT2PTR(CurrentOffset(envPtr) - jumpLocation));
}
Tcl_DStringFree(&buffer);
} else {
/*
* This is a default clause, so patch up the fallthrough from the
* INST_JUMP_TABLE instruction to here.
*/
foundDefault = 1;
isNew = 1;
TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault,
envPtr->codeStart+jumpToDefault+1);
}
/*
* Now, for each arm we must deal with the body of the clause.
*
* If this is a continuation body (never true of a final clause,
* whether default or not) we're done because the next jump target
* will also point here, so we advance to the next clause.
*/
if (bodyToken[i+1]->size == 1 && bodyToken[i+1]->start[0] == '-') {
mustGenerate = 1;
continue;
}
/*
* Also skip this arm if its only match clause is masked. (We could
* probably be more aggressive about this, but that would be much more
* difficult to get right.)
*/
if (!isNew && !mustGenerate) {
continue;
}
mustGenerate = 0;
/*
* Compile the body of the arm.
*/
envPtr->line = bodyLines[i+1]; /* TIP #280 */
envPtr->clNext = bodyContLines[i+1]; /* TIP #280 */
TclCompileCmdWord(interp, bodyToken[i+1], 1, envPtr);
/*
* Compile a jump in to the end of the command if this body is
* anything other than a user-supplied default arm (to either skip
* over the remaining bodies or the code that generates an empty
* result).
*/
if (i+2 < numBodyTokens || !foundDefault) {
finalFixups[numRealBodies++] = CurrentOffset(envPtr);
/*
* Easier by far to issue this jump as a fixed-width jump, since
* otherwise we'd need to do a lot more (and more awkward)
* rewriting when we fixed this all up.
*/
OP4( JUMP4, 0);
TclAdjustStackDepth(-1, envPtr);
}
}
/*
* We're at the end. If we've not already done so through the processing
* of a user-supplied default clause, add in a "default" default clause
* now.
*/
if (!foundDefault) {
TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault,
envPtr->codeStart+jumpToDefault+1);
PUSH("");
}
/*
* No more instructions to be issued; everything that needs to jump to the
* end of the command is fixed up at this point.
*/
for (i=0 ; i<numRealBodies ; i++) {
TclStoreInt4AtPtr(CurrentOffset(envPtr)-finalFixups[i],
envPtr->codeStart+finalFixups[i]+1);
}
/*
* Clean up all our temporary space and return.
*/
TclStackFree(interp, finalFixups);
}
/*
*----------------------------------------------------------------------
*
* DupJumptableInfo, FreeJumptableInfo --
*
* Functions to duplicate, release and print a jump-table created for use
* with the INST_JUMP_TABLE instruction.
*
* Results:
* DupJumptableInfo: a copy of the jump-table
* FreeJumptableInfo: none
* PrintJumptableInfo: none
* DisassembleJumptableInfo: none
*
* Side effects:
* DupJumptableInfo: allocates memory
* FreeJumptableInfo: releases memory
* PrintJumptableInfo: none
* DisassembleJumptableInfo: none
*
*----------------------------------------------------------------------
*/
static void *
DupJumptableInfo(
void *clientData)
{
JumptableInfo *jtPtr = (JumptableInfo *)clientData;
JumptableInfo *newJtPtr = (JumptableInfo *)Tcl_Alloc(sizeof(JumptableInfo));
Tcl_HashEntry *hPtr, *newHPtr;
Tcl_HashSearch search;
int isNew;
Tcl_InitHashTable(&newJtPtr->hashTable, TCL_STRING_KEYS);
hPtr = Tcl_FirstHashEntry(&jtPtr->hashTable, &search);
for (; hPtr ; hPtr = Tcl_NextHashEntry(&search)) {
newHPtr = Tcl_CreateHashEntry(&newJtPtr->hashTable,
Tcl_GetHashKey(&jtPtr->hashTable, hPtr), &isNew);
Tcl_SetHashValue(newHPtr, Tcl_GetHashValue(hPtr));
}
return newJtPtr;
}
static void
FreeJumptableInfo(
|
| ︙ | ︙ | |||
2788 2789 2790 2791 2792 2793 2794 |
hPtr = Tcl_FirstHashEntry(&jtPtr->hashTable, &search);
for (; hPtr ; hPtr = Tcl_NextHashEntry(&search)) {
keyPtr = (const char *)Tcl_GetHashKey(&jtPtr->hashTable, hPtr);
offset = PTR2INT(Tcl_GetHashValue(hPtr));
if (i++) {
| | | | | 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 |
hPtr = Tcl_FirstHashEntry(&jtPtr->hashTable, &search);
for (; hPtr ; hPtr = Tcl_NextHashEntry(&search)) {
keyPtr = (const char *)Tcl_GetHashKey(&jtPtr->hashTable, hPtr);
offset = PTR2INT(Tcl_GetHashValue(hPtr));
if (i++) {
Tcl_AppendToObj(appendObj, ", ", -1);
if (i%4==0) {
Tcl_AppendToObj(appendObj, "\n\t\t", -1);
}
}
Tcl_AppendPrintfToObj(appendObj, "\"%s\"->pc %" TCL_Z_MODIFIER "u",
keyPtr, pcOffset + offset);
}
}
|
| ︙ | ︙ | |||
2819 2820 2821 2822 2823 2824 2825 |
TclNewObj(mapping);
hPtr = Tcl_FirstHashEntry(&jtPtr->hashTable, &search);
for (; hPtr ; hPtr = Tcl_NextHashEntry(&search)) {
keyPtr = (const char *)Tcl_GetHashKey(&jtPtr->hashTable, hPtr);
offset = PTR2INT(Tcl_GetHashValue(hPtr));
TclDictPut(NULL, mapping, keyPtr, Tcl_NewWideIntObj(offset));
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 |
TclNewObj(mapping);
hPtr = Tcl_FirstHashEntry(&jtPtr->hashTable, &search);
for (; hPtr ; hPtr = Tcl_NextHashEntry(&search)) {
keyPtr = (const char *)Tcl_GetHashKey(&jtPtr->hashTable, hPtr);
offset = PTR2INT(Tcl_GetHashValue(hPtr));
TclDictPut(NULL, mapping, keyPtr, Tcl_NewWideIntObj(offset));
}
TclDictPut(NULL, dictObj, "mapping", mapping);
}
/*
*----------------------------------------------------------------------
*
* TclCompileTailcallCmd --
|
| ︙ | ︙ | |||
2926 2927 2928 2929 2930 2931 2932 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
| < < | > | < < | < < < < < | < < < < < < < < | < | < < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
int i;
if (parsePtr->numWords < 2 || parsePtr->numWords >= 256
|| envPtr->procPtr == NULL) {
return TCL_ERROR;
}
/* make room for the nsObjPtr */
/* TODO: Doesn't this have to be a known value? */
CompileWord(envPtr, tokenPtr, interp, 0);
for (i=1 ; i<(int)parsePtr->numWords ; i++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
TclEmitInstInt1( INST_TAILCALL, (int)parsePtr->numWords, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileThrowCmd --
|
| ︙ | ︙ | |||
3047 3048 3049 3050 3051 3052 3053 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
| | | 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
int numWords = parsePtr->numWords;
Tcl_Token *codeToken, *msgToken;
Tcl_Obj *objPtr;
int codeKnown, codeIsList, codeIsValid;
Tcl_Size len;
if (numWords != 3) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
3069 3070 3071 3072 3073 3074 3075 |
codeKnown = TclWordKnownAtCompileTime(codeToken, objPtr);
/*
* First we must emit the code to substitute the arguments. This
* must come first in case substitution raises errors.
*/
if (!codeKnown) {
| | | | < | | < < | 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 |
codeKnown = TclWordKnownAtCompileTime(codeToken, objPtr);
/*
* First we must emit the code to substitute the arguments. This
* must come first in case substitution raises errors.
*/
if (!codeKnown) {
CompileWord(envPtr, codeToken, interp, 1);
PUSH( "-errorcode");
}
CompileWord(envPtr, msgToken, interp, 2);
codeIsList = codeKnown && (TCL_OK ==
TclListObjLength(interp, objPtr, &len));
codeIsValid = codeIsList && (len != 0);
if (codeIsValid) {
Tcl_Obj *dictPtr;
TclNewObj(dictPtr);
TclDictPut(NULL, dictPtr, "-errorcode", objPtr);
TclEmitPush(TclAddLiteralObj(envPtr, dictPtr, NULL), envPtr);
}
TclDecrRefCount(objPtr);
/*
* Simpler bytecodes when we detect invalid arguments at compile time.
*/
if (codeKnown && !codeIsValid) {
OP( POP);
if (codeIsList) {
/* Must be an empty list */
goto issueErrorForEmptyCode;
}
TclCompileSyntaxError(interp, envPtr);
return TCL_OK;
}
if (!codeKnown) {
/*
* Argument validity checking has to be done by bytecode at
* run time.
*/
OP4( REVERSE, 3);
OP( DUP);
OP( LIST_LENGTH);
OP1( JUMP_FALSE1, 16);
OP4( LIST, 2);
OP44( RETURN_IMM, TCL_ERROR, 0);
TclAdjustStackDepth(2, envPtr);
OP( POP);
OP( POP);
OP( POP);
issueErrorForEmptyCode:
PUSH( "type must be non-empty list");
PUSH( "-errorcode {TCL OPERATION THROW BADEXCEPTION}");
}
|
| ︙ | ︙ | |||
3152 3153 3154 3155 3156 3157 3158 |
TclCompileTryCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
| | < | | > > | > > > > > > > > > > > | | | < | < | < | < | | < > > > | > | > | < | < | > > | | | < | > | | > | | | < | > | | | < | | | | | | > | < < < < < < < < < < < < | < < < < | | < > < < < < | > | < | | > | | | | < > > | > > | | < > > | > > > > | | < | | < | | > | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < > | | | | | | | | | | < < < | | | | | | | | | > | > > > > > > > > > | > > > > > > > > > > > > > > > > > | | | | < | | | | | > | | | > > | > > | | | > | > > > | < < < < < < | < < < | | | | < | | | | < | | | | | | | | | > > > | | < | | > > > > | | | | | < | < | | | > > | > > > > | < < | < > | > | < | | | | | | | | < > | | | | | | | < < < | | | | | | | < < < | | | | | | | < | | > > | < > | | | | | | | > > | > | | > > | < < | | | | < | < | | < | | | | | | | | | < | | | | | < < | | | | | | | | | | | < < < | | | < | | | | | | > | < | > > > | | | | | | | | | | > | | | | | < < < < | < < < < < < < | < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < | < < < < < | < | < | | < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < | < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < | < < < < < < | | | < < < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < < < | < < < < < < < < < < < < < < < < < < | < | < | < | | | < > | | | < | < < | | < | | | | < < > | | | | < | | | | < < | | | | | | | | | | | | < | < > | | 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 |
TclCompileTryCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
int numWords = parsePtr->numWords, numHandlers, result = TCL_ERROR;
Tcl_Token *bodyToken, *finallyToken, *tokenPtr;
Tcl_Token **handlerTokens = NULL;
Tcl_Obj **matchClauses = NULL;
int *matchCodes=NULL, *resultVarIndices=NULL, *optionVarIndices=NULL;
int i;
if (numWords < 2) {
return TCL_ERROR;
}
bodyToken = TokenAfter(parsePtr->tokenPtr);
if (numWords == 2) {
/*
* No handlers or finally; do nothing beyond evaluating the body.
*/
DefineLineInformation; /* TIP #280 */
BODY(bodyToken, 1);
return TCL_OK;
}
numWords -= 2;
tokenPtr = TokenAfter(bodyToken);
/*
* Extract information about what handlers there are.
*/
numHandlers = numWords >> 2;
numWords -= numHandlers * 4;
if (numHandlers > 0) {
handlerTokens = (Tcl_Token**)TclStackAlloc(interp, sizeof(Tcl_Token*)*numHandlers);
matchClauses = (Tcl_Obj **)TclStackAlloc(interp, sizeof(Tcl_Obj *) * numHandlers);
memset(matchClauses, 0, sizeof(Tcl_Obj *) * numHandlers);
matchCodes = (int *)TclStackAlloc(interp, sizeof(int) * numHandlers);
resultVarIndices = (int *)TclStackAlloc(interp, sizeof(int) * numHandlers);
optionVarIndices = (int *)TclStackAlloc(interp, sizeof(int) * numHandlers);
for (i=0 ; i<numHandlers ; i++) {
Tcl_Obj *tmpObj, **objv;
Tcl_Size objc;
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
goto failedToCompile;
}
if (tokenPtr[1].size == 4
&& !strncmp(tokenPtr[1].start, "trap", 4)) {
/*
* Parse the list of errorCode words to match against.
*/
matchCodes[i] = TCL_ERROR;
tokenPtr = TokenAfter(tokenPtr);
TclNewObj(tmpObj);
Tcl_IncrRefCount(tmpObj);
if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)
|| TclListObjLength(NULL, tmpObj, &objc) != TCL_OK
|| (objc == 0)) {
TclDecrRefCount(tmpObj);
goto failedToCompile;
}
Tcl_ListObjReplace(NULL, tmpObj, 0, 0, 0, NULL);
matchClauses[i] = tmpObj;
} else if (tokenPtr[1].size == 2
&& !strncmp(tokenPtr[1].start, "on", 2)) {
int code;
/*
* Parse the result code to look for.
*/
tokenPtr = TokenAfter(tokenPtr);
TclNewObj(tmpObj);
Tcl_IncrRefCount(tmpObj);
if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
TclDecrRefCount(tmpObj);
goto failedToCompile;
}
if (TCL_ERROR == TclGetCompletionCodeFromObj(NULL, tmpObj, &code)) {
TclDecrRefCount(tmpObj);
goto failedToCompile;
}
matchCodes[i] = code;
TclDecrRefCount(tmpObj);
} else {
goto failedToCompile;
}
/*
* Parse the variable binding.
*/
tokenPtr = TokenAfter(tokenPtr);
TclNewObj(tmpObj);
Tcl_IncrRefCount(tmpObj);
if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
TclDecrRefCount(tmpObj);
goto failedToCompile;
}
if (TclListObjGetElements(NULL, tmpObj, &objc, &objv) != TCL_OK
|| (objc > 2)) {
TclDecrRefCount(tmpObj);
goto failedToCompile;
}
if (objc > 0) {
Tcl_Size len;
const char *varname = TclGetStringFromObj(objv[0], &len);
resultVarIndices[i] = LocalScalar(varname, len, envPtr);
if (resultVarIndices[i] < 0) {
TclDecrRefCount(tmpObj);
goto failedToCompile;
}
} else {
resultVarIndices[i] = -1;
}
if (objc == 2) {
Tcl_Size len;
const char *varname = TclGetStringFromObj(objv[1], &len);
optionVarIndices[i] = LocalScalar(varname, len, envPtr);
if (optionVarIndices[i] < 0) {
TclDecrRefCount(tmpObj);
goto failedToCompile;
}
} else {
optionVarIndices[i] = -1;
}
TclDecrRefCount(tmpObj);
/*
* Extract the body for this handler.
*/
tokenPtr = TokenAfter(tokenPtr);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
goto failedToCompile;
}
if (tokenPtr[1].size == 1 && tokenPtr[1].start[0] == '-') {
handlerTokens[i] = NULL;
} else {
handlerTokens[i] = tokenPtr;
}
tokenPtr = TokenAfter(tokenPtr);
}
if (handlerTokens[numHandlers-1] == NULL) {
goto failedToCompile;
}
}
/*
* Parse the finally clause
*/
if (numWords == 0) {
finallyToken = NULL;
} else if (numWords == 2) {
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 7
|| strncmp(tokenPtr[1].start, "finally", 7)) {
goto failedToCompile;
}
finallyToken = TokenAfter(tokenPtr);
if (finallyToken->type != TCL_TOKEN_SIMPLE_WORD) {
goto failedToCompile;
}
} else {
goto failedToCompile;
}
/*
* Issue the bytecode.
*/
if (!finallyToken) {
result = IssueTryClausesInstructions(interp, envPtr, bodyToken,
numHandlers, matchCodes, matchClauses, resultVarIndices,
optionVarIndices, handlerTokens);
} else if (numHandlers == 0) {
result = IssueTryFinallyInstructions(interp, envPtr, bodyToken,
finallyToken);
} else {
result = IssueTryClausesFinallyInstructions(interp, envPtr, bodyToken,
numHandlers, matchCodes, matchClauses, resultVarIndices,
optionVarIndices, handlerTokens, finallyToken);
}
/*
* Delete any temporary state and finish off.
*/
failedToCompile:
if (numHandlers > 0) {
for (i=0 ; i<numHandlers ; i++) {
if (matchClauses[i]) {
TclDecrRefCount(matchClauses[i]);
}
}
TclStackFree(interp, optionVarIndices);
TclStackFree(interp, resultVarIndices);
TclStackFree(interp, matchCodes);
TclStackFree(interp, matchClauses);
TclStackFree(interp, handlerTokens);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* IssueTryClausesInstructions, IssueTryClausesFinallyInstructions,
* IssueTryFinallyInstructions --
*
* The code generators for [try]. Split from the parsing engine for
* reasons of developer sanity, and also split between no-finally,
* just-finally and with-finally cases because so many of the details of
* generation vary between the three.
*
* The macros below make the instruction issuing easier to follow.
*
*----------------------------------------------------------------------
*/
static int
IssueTryClausesInstructions(
Tcl_Interp *interp,
CompileEnv *envPtr,
Tcl_Token *bodyToken,
int numHandlers,
int *matchCodes,
Tcl_Obj **matchClauses,
int *resultVars,
int *optionVars,
Tcl_Token **handlerTokens)
{
DefineLineInformation; /* TIP #280 */
int range, resultVar, optionsVar;
int i, j, forwardsNeedFixing = 0, trapZero = 0, afterBody = 0;
Tcl_Size slen, len;
int *addrsToFix, *forwardsToFix, notCodeJumpSource, notECJumpSource;
int *noError;
char buf[TCL_INTEGER_SPACE];
resultVar = AnonymousLocal(envPtr);
optionsVar = AnonymousLocal(envPtr);
if (resultVar < 0 || optionsVar < 0) {
return TCL_ERROR;
}
/*
* Check if we're supposed to trap a normal TCL_OK completion of the body.
* If not, we can handle that case much more efficiently.
*/
for (i=0 ; i<numHandlers ; i++) {
if (matchCodes[i] == 0) {
trapZero = 1;
break;
}
}
/*
* Compile the body, trapping any error in it so that we can trap on it
* and/or run a finally clause. Note that there must be at least one
* on/trap clause; when none is present, this whole function is not called
* (and it's never called when there's a finally clause).
*/
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
BODY( bodyToken, 1);
ExceptionRangeEnds(envPtr, range);
if (!trapZero) {
OP( END_CATCH);
JUMP4( JUMP, afterBody);
TclAdjustStackDepth(-1, envPtr);
} else {
PUSH( "0");
OP4( REVERSE, 2);
OP1( JUMP1, 4);
TclAdjustStackDepth(-2, envPtr);
}
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( PUSH_RETURN_CODE);
OP( PUSH_RESULT);
OP( PUSH_RETURN_OPTIONS);
OP( END_CATCH);
STORE( optionsVar);
OP( POP);
STORE( resultVar);
OP( POP);
/*
* Now we handle all the registered 'on' and 'trap' handlers in order.
* For us to be here, there must be at least one handler.
*
* Slight overallocation, but reduces size of this function.
*/
addrsToFix = (int *)TclStackAlloc(interp, sizeof(int)*numHandlers);
forwardsToFix = (int *)TclStackAlloc(interp, sizeof(int)*numHandlers);
noError = (int *)TclStackAlloc(interp, sizeof(int)*numHandlers);
for (i=0 ; i<numHandlers ; i++) {
noError[i] = -1;
snprintf(buf, sizeof(buf), "%d", matchCodes[i]);
OP( DUP);
PushLiteral(envPtr, buf, strlen(buf));
OP( EQ);
JUMP4( JUMP_FALSE, notCodeJumpSource);
if (matchClauses[i]) {
const char *p;
TclListObjLength(NULL, matchClauses[i], &len);
/*
* Match the errorcode according to try/trap rules.
*/
LOAD( optionsVar);
PUSH( "-errorcode");
OP4( DICT_GET, 1);
TclAdjustStackDepth(-1, envPtr);
OP44( LIST_RANGE_IMM, 0, len-1);
p = TclGetStringFromObj(matchClauses[i], &slen);
PushLiteral(envPtr, p, slen);
OP( STR_EQ);
JUMP4( JUMP_FALSE, notECJumpSource);
} else {
notECJumpSource = -1;
}
OP( POP);
/*
* There is no finally clause, so we can avoid wrapping a catch
* context around the handler. That simplifies what instructions need
* to be issued a lot since we can let errors just fall through.
*/
if (resultVars[i] >= 0) {
LOAD( resultVar);
STORE( resultVars[i]);
OP( POP);
if (optionVars[i] >= 0) {
LOAD( optionsVar);
STORE( optionVars[i]);
OP( POP);
}
}
if (!handlerTokens[i]) {
forwardsNeedFixing = 1;
JUMP4( JUMP, forwardsToFix[i]);
TclAdjustStackDepth(1, envPtr);
} else {
int dontChangeOptions;
forwardsToFix[i] = -1;
if (forwardsNeedFixing) {
forwardsNeedFixing = 0;
for (j=0 ; j<i ; j++) {
if (forwardsToFix[j] == -1) {
continue;
}
FIXJUMP4(forwardsToFix[j]);
forwardsToFix[j] = -1;
}
}
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
BODY( handlerTokens[i], 5+i*4);
ExceptionRangeEnds(envPtr, range);
OP( END_CATCH);
JUMP4( JUMP, noError[i]);
ExceptionRangeTarget(envPtr, range, catchOffset);
TclAdjustStackDepth(-1, envPtr);
OP( PUSH_RESULT);
OP( PUSH_RETURN_OPTIONS);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
PUSH( "1");
OP( EQ);
JUMP1( JUMP_FALSE, dontChangeOptions);
LOAD( optionsVar);
OP4( REVERSE, 2);
STORE( optionsVar);
OP( POP);
PUSH( "-during");
OP4( REVERSE, 2);
OP44( DICT_SET, 1, optionsVar);
TclAdjustStackDepth(-1, envPtr);
FIXJUMP1( dontChangeOptions);
OP4( REVERSE, 2);
INVOKE( RETURN_STK);
}
JUMP4( JUMP, addrsToFix[i]);
if (matchClauses[i]) {
FIXJUMP4( notECJumpSource);
}
FIXJUMP4( notCodeJumpSource);
}
/*
* Drop the result code since it didn't match any clause, and reissue the
* exception. Note also that INST_RETURN_STK can proceed to the next
* instruction.
*/
OP( POP);
LOAD( optionsVar);
LOAD( resultVar);
INVOKE( RETURN_STK);
/*
* Fix all the jumps from taken clauses to here (which is the end of the
* [try]).
*/
if (!trapZero) {
FIXJUMP4(afterBody);
}
for (i=0 ; i<numHandlers ; i++) {
FIXJUMP4(addrsToFix[i]);
if (noError[i] != -1) {
FIXJUMP4(noError[i]);
}
}
TclStackFree(interp, noError);
TclStackFree(interp, forwardsToFix);
TclStackFree(interp, addrsToFix);
return TCL_OK;
}
static int
IssueTryClausesFinallyInstructions(
Tcl_Interp *interp,
CompileEnv *envPtr,
Tcl_Token *bodyToken,
int numHandlers,
int *matchCodes,
Tcl_Obj **matchClauses,
int *resultVars,
int *optionVars,
Tcl_Token **handlerTokens,
Tcl_Token *finallyToken) /* Not NULL */
{
DefineLineInformation; /* TIP #280 */
int range, resultVar, optionsVar, i, j, forwardsNeedFixing = 0;
int trapZero = 0, afterBody = 0, finalOK, finalError, noFinalError;
int *addrsToFix, *forwardsToFix, notCodeJumpSource, notECJumpSource;
char buf[TCL_INTEGER_SPACE];
Tcl_Size slen, len;
resultVar = AnonymousLocal(envPtr);
optionsVar = AnonymousLocal(envPtr);
if (resultVar < 0 || optionsVar < 0) {
return TCL_ERROR;
}
/*
* Check if we're supposed to trap a normal TCL_OK completion of the body.
* If not, we can handle that case much more efficiently.
*/
for (i=0 ; i<numHandlers ; i++) {
if (matchCodes[i] == 0) {
trapZero = 1;
break;
}
}
/*
* Compile the body, trapping any error in it so that we can trap on it
* (if any trap matches) and run a finally clause.
*/
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
BODY( bodyToken, 1);
ExceptionRangeEnds(envPtr, range);
if (!trapZero) {
OP( END_CATCH);
STORE( resultVar);
OP( POP);
PUSH( "-level 0 -code 0");
STORE( optionsVar);
OP( POP);
JUMP4( JUMP, afterBody);
} else {
PUSH( "0");
OP4( REVERSE, 2);
OP1( JUMP1, 4);
TclAdjustStackDepth(-2, envPtr);
}
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( PUSH_RETURN_CODE);
OP( PUSH_RESULT);
OP( PUSH_RETURN_OPTIONS);
OP( END_CATCH);
STORE( optionsVar);
OP( POP);
STORE( resultVar);
OP( POP);
/*
* Now we handle all the registered 'on' and 'trap' handlers in order.
*
* Slight overallocation, but reduces size of this function.
*/
addrsToFix = (int *)TclStackAlloc(interp, sizeof(int)*numHandlers);
forwardsToFix = (int *)TclStackAlloc(interp, sizeof(int)*numHandlers);
for (i=0 ; i<numHandlers ; i++) {
int noTrapError, trapError;
const char *p;
snprintf(buf, sizeof(buf), "%d", matchCodes[i]);
OP( DUP);
PushLiteral(envPtr, buf, strlen(buf));
OP( EQ);
JUMP4( JUMP_FALSE, notCodeJumpSource);
if (matchClauses[i]) {
TclListObjLength(NULL, matchClauses[i], &len);
/*
* Match the errorcode according to try/trap rules.
*/
LOAD( optionsVar);
PUSH( "-errorcode");
OP4( DICT_GET, 1);
TclAdjustStackDepth(-1, envPtr);
OP44( LIST_RANGE_IMM, 0, len-1);
p = TclGetStringFromObj(matchClauses[i], &slen);
PushLiteral(envPtr, p, slen);
OP( STR_EQ);
JUMP4( JUMP_FALSE, notECJumpSource);
} else {
notECJumpSource = -1;
}
OP( POP);
/*
* There is a finally clause, so we need a fairly complex sequence of
* instructions to deal with an on/trap handler because we must call
* the finally handler *and* we need to substitute the result from a
* failed trap for the result from the main script.
*/
if (resultVars[i] >= 0 || handlerTokens[i]) {
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
}
if (resultVars[i] >= 0) {
LOAD( resultVar);
STORE( resultVars[i]);
OP( POP);
if (optionVars[i] >= 0) {
LOAD( optionsVar);
STORE( optionVars[i]);
OP( POP);
}
if (!handlerTokens[i]) {
/*
* No handler. Will not be the last handler (that is a
* condition that is checked by the caller). Chain to the next
* one.
*/
ExceptionRangeEnds(envPtr, range);
OP( END_CATCH);
forwardsNeedFixing = 1;
JUMP4( JUMP, forwardsToFix[i]);
goto finishTrapCatchHandling;
}
} else if (!handlerTokens[i]) {
/*
* No handler. Will not be the last handler (that condition is
* checked by the caller). Chain to the next one.
*/
forwardsNeedFixing = 1;
JUMP4( JUMP, forwardsToFix[i]);
goto endOfThisArm;
}
/*
* Got a handler. Make sure that any pending patch-up actions from
* previous unprocessed handlers are dealt with now that we know where
* they are to jump to.
*/
if (forwardsNeedFixing) {
forwardsNeedFixing = 0;
OP1( JUMP1, 7);
for (j=0 ; j<i ; j++) {
if (forwardsToFix[j] == -1) {
continue;
}
FIXJUMP4( forwardsToFix[j]);
forwardsToFix[j] = -1;
}
OP4( BEGIN_CATCH4, range);
}
BODY( handlerTokens[i], 5+i*4);
ExceptionRangeEnds(envPtr, range);
PUSH( "0");
OP( PUSH_RETURN_OPTIONS);
OP4( REVERSE, 3);
OP1( JUMP1, 5);
TclAdjustStackDepth(-3, envPtr);
forwardsToFix[i] = -1;
/*
* Error in handler or setting of variables; replace the stored
* exception with the new one. Note that we only push this if we have
* either a body or some variable setting here. Otherwise this code is
* unreachable.
*/
finishTrapCatchHandling:
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( PUSH_RETURN_OPTIONS);
OP( PUSH_RETURN_CODE);
OP( PUSH_RESULT);
OP( END_CATCH);
STORE( resultVar);
OP( POP);
PUSH( "1");
OP( EQ);
JUMP1( JUMP_FALSE, noTrapError);
LOAD( optionsVar);
PUSH( "-during");
OP4( REVERSE, 3);
STORE( optionsVar);
OP( POP);
OP44( DICT_SET, 1, optionsVar);
TclAdjustStackDepth(-1, envPtr);
JUMP1( JUMP, trapError);
FIXJUMP1( noTrapError);
STORE( optionsVar);
FIXJUMP1( trapError);
/* Skip POP at end; can clean up with subsequent POP */
if (i+1 < numHandlers) {
OP( POP);
}
endOfThisArm:
if (i+1 < numHandlers) {
JUMP4( JUMP, addrsToFix[i]);
TclAdjustStackDepth(1, envPtr);
}
if (matchClauses[i]) {
FIXJUMP4( notECJumpSource);
}
FIXJUMP4( notCodeJumpSource);
}
/*
* Drop the result code, and fix all the jumps from taken clauses - which
* drop the result code as their first action - to point straight after
* (i.e., to the start of the finally clause).
*/
OP( POP);
for (i=0 ; i<numHandlers-1 ; i++) {
FIXJUMP4( addrsToFix[i]);
}
TclStackFree(interp, forwardsToFix);
TclStackFree(interp, addrsToFix);
/*
* Process the finally clause (at last!) Note that we do not wrap this in
* error handlers because we would just rethrow immediately anyway. Then
* (on normal success) we reissue the exception. Note also that
* INST_RETURN_STK can proceed to the next instruction; that'll be the
* next command (or some inter-command manipulation).
*/
if (!trapZero) {
FIXJUMP4( afterBody);
}
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
BODY( finallyToken, 3 + 4*numHandlers);
ExceptionRangeEnds(envPtr, range);
OP( END_CATCH);
OP( POP);
JUMP1( JUMP, finalOK);
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( PUSH_RESULT);
OP( PUSH_RETURN_OPTIONS);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
PUSH( "1");
OP( EQ);
JUMP1( JUMP_FALSE, noFinalError);
LOAD( optionsVar);
PUSH( "-during");
OP4( REVERSE, 3);
STORE( optionsVar);
OP( POP);
OP44( DICT_SET, 1, optionsVar);
TclAdjustStackDepth(-1, envPtr);
OP( POP);
JUMP1( JUMP, finalError);
TclAdjustStackDepth(1, envPtr);
FIXJUMP1( noFinalError);
STORE( optionsVar);
OP( POP);
FIXJUMP1( finalError);
STORE( resultVar);
OP( POP);
FIXJUMP1( finalOK);
LOAD( optionsVar);
LOAD( resultVar);
INVOKE( RETURN_STK);
return TCL_OK;
}
static int
IssueTryFinallyInstructions(
Tcl_Interp *interp,
CompileEnv *envPtr,
Tcl_Token *bodyToken,
Tcl_Token *finallyToken)
{
DefineLineInformation; /* TIP #280 */
int range, jumpOK, jumpSplice;
/*
* Note that this one is simple enough that we can issue it without
* needing a local variable table, making it a universal compilation.
*/
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
BODY( bodyToken, 1);
ExceptionRangeEnds(envPtr, range);
OP1( JUMP1, 3);
TclAdjustStackDepth(-1, envPtr);
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( PUSH_RESULT);
OP( PUSH_RETURN_OPTIONS);
OP( END_CATCH);
range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
OP4( BEGIN_CATCH4, range);
ExceptionRangeStarts(envPtr, range);
BODY( finallyToken, 3);
ExceptionRangeEnds(envPtr, range);
OP( END_CATCH);
OP( POP);
JUMP1( JUMP, jumpOK);
ExceptionRangeTarget(envPtr, range, catchOffset);
OP( PUSH_RESULT);
OP( PUSH_RETURN_OPTIONS);
OP( PUSH_RETURN_CODE);
OP( END_CATCH);
PUSH( "1");
OP( EQ);
JUMP1( JUMP_FALSE, jumpSplice);
PUSH( "-during");
OP4( OVER, 3);
OP4( LIST, 2);
OP( LIST_CONCAT);
FIXJUMP1( jumpSplice);
OP4( REVERSE, 4);
OP( POP);
OP( POP);
OP1( JUMP1, 7);
FIXJUMP1( jumpOK);
OP4( REVERSE, 2);
INVOKE( RETURN_STK);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileUnsetCmd --
|
| ︙ | ︙ | |||
4452 4453 4454 4455 4456 4457 4458 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr;
| | < < < < < < | | 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *varTokenPtr;
int isScalar, localIndex, flags = 1, i, varCount = 0, haveFlags = 0;
/* TODO: Consider support for compiling expanded args. */
/*
* Verify that all words - except the first non-option one - are known at
* compile time so that we can handle them without needing to do a nasty
* push/rotate. [Bug 3970f54c4e]
*/
for (i=1,varTokenPtr=parsePtr->tokenPtr ; i<(int)parsePtr->numWords ; i++) {
Tcl_Obj *leadingWord;
TclNewObj(leadingWord);
varTokenPtr = TokenAfter(varTokenPtr);
if (!TclWordKnownAtCompileTime(varTokenPtr, leadingWord)) {
TclDecrRefCount(leadingWord);
|
| ︙ | ︙ | |||
4532 4533 4534 4535 4536 4537 4538 |
* Issue instructions to unset each of the named variables.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
for (i=0; i<haveFlags;i++) {
varTokenPtr = TokenAfter(varTokenPtr);
}
| | > | < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 |
* Issue instructions to unset each of the named variables.
*/
varTokenPtr = TokenAfter(parsePtr->tokenPtr);
for (i=0; i<haveFlags;i++) {
varTokenPtr = TokenAfter(varTokenPtr);
}
for (i=1+haveFlags ; i<(int)parsePtr->numWords ; i++) {
/*
* Decide if we can use a frame slot for the var/array name or if we
* need to emit code to compute and push the name at runtime. We use a
* frame slot (entry in the array of local vars) if we are compiling a
* procedure body and if the name is simple text that does not include
* namespace qualifiers.
*/
PushVarNameWord(interp, varTokenPtr, envPtr, 0,
&localIndex, &isScalar, i);
/*
* Emit instructions to unset the variable.
*/
if (isScalar) {
if (localIndex < 0) {
OP1( UNSET_STK, flags);
} else {
OP14( UNSET_SCALAR, flags, localIndex);
}
} else {
if (localIndex < 0) {
OP1( UNSET_ARRAY_STK, flags);
} else {
OP14( UNSET_ARRAY, flags, localIndex);
}
}
varTokenPtr = TokenAfter(varTokenPtr);
}
PUSH("");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileWhileCmd --
|
| ︙ | ︙ | |||
4687 4688 4689 4690 4691 4692 4693 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *testTokenPtr, *bodyTokenPtr;
| | | < < | < < < | < > > | | 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *testTokenPtr, *bodyTokenPtr;
JumpFixup jumpEvalCondFixup;
int testCodeOffset, bodyCodeOffset, jumpDist, range, code, boolVal;
int loopMayEnd = 1; /* This is set to 0 if it is recognized as an
* infinite loop. */
Tcl_Obj *boolObj;
if (parsePtr->numWords != 3) {
return TCL_ERROR;
}
/*
* If the test expression requires substitutions, don't compile the while
* command inline. E.g., the expression might cause the loop to never
* execute or execute forever, as in "while "$x < 5" {}".
*
* Bail out also if the body expression requires substitutions in order to
* insure correct behaviour [Bug 219166]
*/
testTokenPtr = TokenAfter(parsePtr->tokenPtr);
bodyTokenPtr = TokenAfter(testTokenPtr);
if ((testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)
|| (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) {
return TCL_ERROR;
}
/*
* Find out if the condition is a constant.
*/
boolObj = Tcl_NewStringObj(testTokenPtr[1].start, testTokenPtr[1].size);
Tcl_IncrRefCount(boolObj);
code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
TclDecrRefCount(boolObj);
if (code == TCL_OK) {
if (boolVal) {
/*
* It is an infinite loop; flag it so that we generate a more
* efficient body.
*/
|
| ︙ | ︙ | |||
4749 4750 4751 4752 4753 4754 4755 |
}
/*
* Create a ExceptionRange record for the loop body. This is used to
* implement break and continue.
*/
| | > | > | | | > | > > | > | < > > > > > | > | > > | > > > | > > > > > | > > | | | | 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 |
}
/*
* Create a ExceptionRange record for the loop body. This is used to
* implement break and continue.
*/
range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
/*
* Jump to the evaluation of the condition. This code uses the "loop
* rotation" optimisation (which eliminates one branch from the loop).
* "while cond body" produces then:
* goto A
* B: body : bodyCodeOffset
* A: cond -> result : testCodeOffset, continueOffset
* if (result) goto B
*
* The infinite loop "while 1 body" produces:
* B: body : all three offsets here
* goto B
*/
if (loopMayEnd) {
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
&jumpEvalCondFixup);
testCodeOffset = 0; /* Avoid compiler warning. */
} else {
/*
* Make sure that the first command in the body is preceded by an
* INST_START_CMD, and hence counted properly. [Bug 1752146]
*/
envPtr->atCmdStart &= ~1;
testCodeOffset = CurrentOffset(envPtr);
}
/*
* Compile the loop body.
*/
bodyCodeOffset = ExceptionRangeStarts(envPtr, range);
if (!loopMayEnd) {
envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
}
BODY(bodyTokenPtr, 2);
ExceptionRangeEnds(envPtr, range);
OP( POP);
/*
* Compile the test expression then emit the conditional jump that
* terminates the while. We already know it's a simple word.
*/
if (loopMayEnd) {
testCodeOffset = CurrentOffset(envPtr);
jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
bodyCodeOffset += 3;
testCodeOffset += 3;
}
SetLineInformation(1);
TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
if (jumpDist > 127) {
TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
} else {
TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
}
} else {
jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
if (jumpDist > 127) {
TclEmitInstInt4(INST_JUMP4, -jumpDist, envPtr);
} else {
TclEmitInstInt1(INST_JUMP1, -jumpDist, envPtr);
}
}
/*
* Set the loop's body, continue and break offsets.
*/
envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
ExceptionRangeTarget(envPtr, range, breakOffset);
TclFinalizeLoopExceptionRange(envPtr, range);
/*
* The while command's result is an empty string.
*/
pushResult:
PUSH("");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileYieldCmd --
|
| ︙ | ︙ | |||
4848 4849 4850 4851 4852 4853 4854 |
CompileEnv *envPtr) /* Holds resulting instructions. */
{
if (parsePtr->numWords < 1 || parsePtr->numWords > 2) {
return TCL_ERROR;
}
if (parsePtr->numWords == 1) {
| | | | | 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 |
CompileEnv *envPtr) /* Holds resulting instructions. */
{
if (parsePtr->numWords < 1 || parsePtr->numWords > 2) {
return TCL_ERROR;
}
if (parsePtr->numWords == 1) {
PUSH("");
} else {
DefineLineInformation; /* TIP #280 */
Tcl_Token *valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, valueTokenPtr, interp, 1);
}
OP( YIELD);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileYieldToCmd --
|
| ︙ | ︙ | |||
4887 4888 4889 4890 4891 4892 4893 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
| < | < | < < < < < < < < < | < < < < | < < | < < < | < < | < > < | < < < < | | 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 |
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
TCL_UNUSED(Command *),
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
int i;
if ((int)parsePtr->numWords < 2) {
return TCL_ERROR;
}
OP( NS_CURRENT);
for (i = 1 ; i < (int)parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
OP4( LIST, i);
OP( YIELD_TO_INVOKE);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* CompileUnaryOpCmd --
|
| ︙ | ︙ | |||
4962 4963 4964 4965 4966 4967 4968 |
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
| | | 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 |
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
TclEmitOpcode(instruction, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
5002 5003 5004 5005 5006 5007 5008 |
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Size words;
/* TODO: Consider support for compiling expanded args. */
| < < < | | | | 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 |
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Size words;
/* TODO: Consider support for compiling expanded args. */
for (words=1 ; words<parsePtr->numWords ; words++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
}
if (parsePtr->numWords <= 2) {
PushLiteral(envPtr, identity, -1);
words++;
}
if (words > 3) {
/*
* Reverse order of arguments to get precise agreement with [expr] in
* calculations, including roundoff errors.
*/
OP4( REVERSE, words-1);
}
while (--words > 1) {
TclEmitOpcode(instruction, envPtr);
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
5089 5090 5091 5092 5093 5094 5095 |
int instruction,
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
/* TODO: Consider support for compiling expanded args. */
| < < < | | | | | | < < < | | | | | | | | | 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 |
int instruction,
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
/* TODO: Consider support for compiling expanded args. */
if ((int)parsePtr->numWords < 3) {
PUSH("1");
} else if (parsePtr->numWords == 3) {
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
TclEmitOpcode(instruction, envPtr);
} else if (envPtr->procPtr == NULL) {
/*
* No local variable space!
*/
return TCL_ERROR;
} else {
int tmpIndex = AnonymousLocal(envPtr);
Tcl_Size words;
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
STORE(tmpIndex);
TclEmitOpcode(instruction, envPtr);
for (words=3 ; words<parsePtr->numWords ;) {
LOAD(tmpIndex);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
if (++words < parsePtr->numWords) {
STORE(tmpIndex);
}
TclEmitOpcode(instruction, envPtr);
}
for (; words>3 ; words--) {
OP( BITAND);
}
/*
* Drop the value from the temp variable; retaining that reference
* might be expensive elsewhere.
*/
OP14( UNSET_SCALAR, 0, tmpIndex);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
5249 5250 5251 5252 5253 5254 5255 |
TCL_UNUSED(Command *),
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Size words;
| < < < < | | | | 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 |
TCL_UNUSED(Command *),
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Size words;
/*
* This one has its own implementation because the ** operator is the only
* one with right associativity.
*/
for (words=1 ; words<parsePtr->numWords ; words++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
}
if (parsePtr->numWords <= 2) {
PUSH("1");
words++;
}
while (--words > 1) {
TclEmitOpcode(INST_EXPON, envPtr);
}
return TCL_OK;
}
int
TclCompileLshiftOpCmd(
Tcl_Interp *interp,
|
| ︙ | ︙ | |||
5455 5456 5457 5458 5459 5460 5461 |
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Size words;
/* TODO: Consider support for compiling expanded args. */
| | | | | | | | | | | | | | | | 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 |
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Size words;
/* TODO: Consider support for compiling expanded args. */
if (parsePtr->numWords == 1) {
/*
* Fallback to direct eval to report syntax error.
*/
return TCL_ERROR;
}
for (words=1 ; words<parsePtr->numWords ; words++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
}
if (words == 2) {
TclEmitOpcode(INST_UMINUS, envPtr);
return TCL_OK;
}
if (words == 3) {
TclEmitOpcode(INST_SUB, envPtr);
return TCL_OK;
}
/*
* Reverse order of arguments to get precise agreement with [expr] in
* calculations, including roundoff errors.
*/
TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
while (--words > 1) {
TclEmitInstInt4(INST_REVERSE, 2, envPtr);
TclEmitOpcode(INST_SUB, envPtr);
}
return TCL_OK;
}
int
TclCompileDivOpCmd(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
TCL_UNUSED(Command *),
CompileEnv *envPtr)
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
Tcl_Size words;
/* TODO: Consider support for compiling expanded args. */
if (parsePtr->numWords == 1) {
/*
* Fallback to direct eval to report syntax error.
*/
return TCL_ERROR;
}
if (parsePtr->numWords == 2) {
PUSH("1.0");
}
for (words=1 ; words<parsePtr->numWords ; words++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, words);
}
if (words <= 3) {
TclEmitOpcode(INST_DIV, envPtr);
return TCL_OK;
}
/*
* Reverse order of arguments to get precise agreement with [expr] in
* calculations, including roundoff errors.
*/
TclEmitInstInt4(INST_REVERSE, words-1, envPtr);
while (--words > 1) {
TclEmitInstInt4(INST_REVERSE, 2, envPtr);
TclEmitOpcode(INST_DIV, envPtr);
}
return TCL_OK;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclCompExpr.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 |
typedef struct {
int left; /* "Pointer" to the left operand. */
int right; /* "Pointer" to the right operand. */
union {
int parent; /* "Pointer" to the parent operand. */
int prev; /* "Pointer" joining incomplete tree stack */
| | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
typedef struct {
int left; /* "Pointer" to the left operand. */
int right; /* "Pointer" to the right operand. */
union {
int parent; /* "Pointer" to the parent operand. */
int prev; /* "Pointer" joining incomplete tree stack */
} p;
unsigned char lexeme; /* Code that identifies the operator. */
unsigned char precedence; /* Precedence of the operator */
unsigned char mark; /* Mark used to control traversal. */
unsigned char constant; /* Flag marking constant subexpressions. */
} OpNode;
/*
|
| ︙ | ︙ | |||
57 58 59 60 61 62 63 |
* Tcl_Tokens. These non-operator elements of the expression are the leaves of
* the completed parse tree. When an operand of an OpNode is one of these leaf
* elements, the following negative integer codes are used to indicate which
* kind of elements it is.
*/
enum OperandTypes {
| | | | | | | | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
* Tcl_Tokens. These non-operator elements of the expression are the leaves of
* the completed parse tree. When an operand of an OpNode is one of these leaf
* elements, the following negative integer codes are used to indicate which
* kind of elements it is.
*/
enum OperandTypes {
OT_LITERAL = -3, /* Operand is a literal in the literal list */
OT_TOKENS = -2, /* Operand is sequence of Tcl_Tokens */
OT_EMPTY = -1 /* "Operand" is an empty string. This is a special
* case used only to represent the EMPTY lexeme. See
* below. */
};
/*
* Readable macros to test whether a "pointer" value points to an operator.
* They operate on the "non-negative integer -> operator; negative integer ->
* a non-operator OperandType" distinction.
*/
#define IsOperator(l) ((l) >= 0)
#define NotOperator(l) ((l) < 0)
/*
* Note that it is sufficient to store in the tree just the type of leaf
* operand, without any explicit pointer to which leaf. This is true because
* the traversals of the completed tree we perform are known to visit the
* leaves in the same order as the original parse.
*
* In a completed parse tree, those OpNodes that are themselves (roots of
* subexpression trees that are) operands of some operator store in their
* p.parent field a "pointer" to the OpNode of that operator. The p.parent
* field permits a traversal of the tree within a non-recursive routine
* (ConvertTreeToTokens() and CompileExprTree()). This means that even
* expression trees of great depth pose no risk of blowing the C stack.
*
* While the parse tree is being constructed, the same memory space is used to
* hold the p.prev field which chains together a stack of incomplete trees
* awaiting their right operands.
*
* The lexeme field is filled in with the lexeme of the operator that is
* returned by the ParseLexeme() routine. Only lexemes for unary and binary
* operators get stored in an OpNode. Other lexmes get different treatment.
*
* The precedence field provides a place to store the precedence of the
* operator, so it need not be looked up again and again.
*
* The mark field is use to control the traversal of the tree, so that it can
* be done non-recursively. The mark values are:
*/
enum Marks {
MARK_LEFT, /* Next step of traversal is to visit left subtree */
MARK_RIGHT, /* Next step of traversal is to visit right subtree */
MARK_PARENT /* Next step of traversal is to return to parent */
};
/*
* The constant field is a boolean flag marking which subexpressions are
* completely known at compile time, and are eligible for computing then
* rather than waiting until run time.
*/
|
| ︙ | ︙ | |||
158 159 160 161 162 163 164 |
* BINARY_PLUS according to context. */
MINUS = 2, /* Ambiguous. Resolves to UNARY_MINUS or
* BINARY_MINUS according to context. */
BAREWORD = 3, /* Ambiguous. Resolves to BOOL_LIT or to
* FUNCTION or a parse error according to
* context and value. */
INCOMPLETE = 4, /* A parse error. Used only when the single
| | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
* BINARY_PLUS according to context. */
MINUS = 2, /* Ambiguous. Resolves to UNARY_MINUS or
* BINARY_MINUS according to context. */
BAREWORD = 3, /* Ambiguous. Resolves to BOOL_LIT or to
* FUNCTION or a parse error according to
* context and value. */
INCOMPLETE = 4, /* A parse error. Used only when the single
* "=" is encountered. */
INVALID = 5, /* A parse error. Used when any punctuation
* appears that's not a supported operator. */
COMMENT = 6, /* Comment. Lasts to end of line or end of
* expression, whichever comes first. */
/* Leaf lexemes */
|
| ︙ | ︙ | |||
219 220 221 222 223 224 225 |
BINARY_MINUS = BINARY | MINUS,
COMMA = BINARY | 3, /* The "," operator is a low precedence binary
* operator that separates the arguments in a
* function call. The additional constraint
* that this operator can only legally appear
* at the right places within a function call
* argument list are hard coded within
| | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
BINARY_MINUS = BINARY | MINUS,
COMMA = BINARY | 3, /* The "," operator is a low precedence binary
* operator that separates the arguments in a
* function call. The additional constraint
* that this operator can only legally appear
* at the right places within a function call
* argument list are hard coded within
* ParseExpr(). */
MULT = BINARY | 4,
DIVIDE = BINARY | 5,
MOD = BINARY | 6,
LESS = BINARY | 7,
GREATER = BINARY | 8,
BIT_AND = BINARY | 9,
BIT_XOR = BINARY | 10,
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
* The greater an operator's precedence the greater claim it has to link to an
* available operand. The Precedence enumeration lists the precedence values
* used by Tcl expression operators, from lowest to highest claim. Each
* precedence level is commented with the operators that hold that precedence.
*/
enum Precedence {
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
* The greater an operator's precedence the greater claim it has to link to an
* available operand. The Precedence enumeration lists the precedence values
* used by Tcl expression operators, from lowest to highest claim. Each
* precedence level is commented with the operators that hold that precedence.
*/
enum Precedence {
PREC_END = 1, /* END */
PREC_START, /* START */
PREC_CLOSE_PAREN, /* ")" */
PREC_OPEN_PAREN, /* "(" */
PREC_COMMA, /* "," */
PREC_CONDITIONAL, /* "?", ":" */
PREC_OR, /* "||" */
PREC_AND, /* "&&" */
PREC_BIT_OR, /* "|" */
PREC_BIT_XOR, /* "^" */
PREC_BIT_AND, /* "&" */
PREC_EQUAL, /* "==", "!=", "eq", "ne", "in", "ni" */
PREC_COMPARE, /* "<", ">", "<=", ">=" */
PREC_SHIFT, /* "<<", ">>" */
PREC_ADD, /* "+", "-" */
PREC_MULT, /* "*", "/", "%" */
PREC_EXPON, /* "**" */
PREC_UNARY /* "+", "-", FUNCTION, "!", "~" */
};
/*
* Here the same information contained in the comments above is stored in
* inverted form, so that given a lexeme, one can quickly look up its
* precedence value.
*/
static const unsigned char prec[] = {
/* Non-operator lexemes */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Binary operator lexemes */
PREC_ADD, /* BINARY_PLUS */
PREC_ADD, /* BINARY_MINUS */
PREC_COMMA, /* COMMA */
PREC_MULT, /* MULT */
PREC_MULT, /* DIVIDE */
PREC_MULT, /* MOD */
PREC_COMPARE, /* LESS */
PREC_COMPARE, /* GREATER */
PREC_BIT_AND, /* BIT_AND */
PREC_BIT_XOR, /* BIT_XOR */
PREC_BIT_OR, /* BIT_OR */
PREC_CONDITIONAL, /* QUESTION */
PREC_CONDITIONAL, /* COLON */
PREC_SHIFT, /* LEFT_SHIFT */
PREC_SHIFT, /* RIGHT_SHIFT */
PREC_COMPARE, /* LEQ */
PREC_COMPARE, /* GEQ */
PREC_EQUAL, /* EQUAL */
PREC_EQUAL, /* NEQ */
PREC_AND, /* AND */
PREC_OR, /* OR */
PREC_EQUAL, /* STREQ */
PREC_EQUAL, /* STRNEQ */
PREC_EXPON, /* EXPON */
PREC_EQUAL, /* IN_LIST */
PREC_EQUAL, /* NOT_IN_LIST */
PREC_CLOSE_PAREN, /* CLOSE_PAREN */
PREC_COMPARE, /* STR_LT */
PREC_COMPARE, /* STR_GT */
PREC_COMPARE, /* STR_LEQ */
PREC_COMPARE, /* STR_GEQ */
PREC_END, /* END */
/* Expansion room for more binary operators */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* Unary operator lexemes */
PREC_UNARY, /* UNARY_PLUS */
PREC_UNARY, /* UNARY_MINUS */
PREC_UNARY, /* FUNCTION */
PREC_START, /* START */
PREC_OPEN_PAREN, /* OPEN_PAREN */
PREC_UNARY, /* NOT*/
PREC_UNARY, /* BIT_NOT*/
};
/*
* A table mapping lexemes to bytecode instructions, used by CompileExprTree().
*/
static const unsigned char instruction[] = {
/* Non-operator lexemes */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
/* Binary operator lexemes */
INST_ADD, /* BINARY_PLUS */
INST_SUB, /* BINARY_MINUS */
0, /* COMMA */
INST_MULT, /* MULT */
INST_DIV, /* DIVIDE */
INST_MOD, /* MOD */
INST_LT, /* LESS */
INST_GT, /* GREATER */
INST_BITAND, /* BIT_AND */
INST_BITXOR, /* BIT_XOR */
INST_BITOR, /* BIT_OR */
0, /* QUESTION */
0, /* COLON */
INST_LSHIFT, /* LEFT_SHIFT */
INST_RSHIFT, /* RIGHT_SHIFT */
INST_LE, /* LEQ */
INST_GE, /* GEQ */
INST_EQ, /* EQUAL */
INST_NEQ, /* NEQ */
0, /* AND */
0, /* OR */
INST_STR_EQ, /* STREQ */
INST_STR_NEQ, /* STRNEQ */
INST_EXPON, /* EXPON */
INST_LIST_IN, /* IN_LIST */
INST_LIST_NOT_IN, /* NOT_IN_LIST */
0, /* CLOSE_PAREN */
INST_STR_LT, /* STR_LT */
INST_STR_GT, /* STR_GT */
INST_STR_LE, /* STR_LEQ */
INST_STR_GE, /* STR_GEQ */
0, /* END */
/* Expansion room for more binary operators */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* Unary operator lexemes */
INST_UPLUS, /* UNARY_PLUS */
INST_UMINUS, /* UNARY_MINUS */
0, /* FUNCTION */
0, /* START */
0, /* OPEN_PAREN */
INST_LNOT, /* NOT*/
INST_BITNOT, /* BIT_NOT*/
};
/*
* A table mapping a byte value to the corresponding lexeme for use by
* ParseLexeme().
*/
|
| ︙ | ︙ | |||
491 492 493 494 495 496 497 | } JumpList; /* * Declarations for local functions to this file: */ static void CompileExprTree(Tcl_Interp *interp, OpNode *nodes, | | | | | | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | } JumpList; /* * Declarations for local functions to this file: */ static void CompileExprTree(Tcl_Interp *interp, OpNode *nodes, int index, Tcl_Obj *const **litObjvPtr, Tcl_Obj *const *funcObjv, Tcl_Token *tokenPtr, CompileEnv *envPtr, int optimize); static void ConvertTreeToTokens(const char *start, Tcl_Size numBytes, OpNode *nodes, Tcl_Token *tokenPtr, Tcl_Parse *parsePtr); static int ExecConstantExprTree(Tcl_Interp *interp, OpNode *nodes, int index, Tcl_Obj * const **litObjvPtr); static int ParseExpr(Tcl_Interp *interp, const char *start, Tcl_Size numBytes, OpNode **opTreePtr, Tcl_Obj *litList, Tcl_Obj *funcList, Tcl_Parse *parsePtr, int parseOnly); static Tcl_Size ParseLexeme(const char *start, Tcl_Size numBytes, unsigned char *lexemePtr, Tcl_Obj **literalPtr); /* *---------------------------------------------------------------------- * * ParseExpr -- |
| ︙ | ︙ | |||
549 550 551 552 553 554 555 |
OpNode **opTreePtr, /* Points to space where a pointer to the
* allocated OpNode tree should go. */
Tcl_Obj *litList, /* List to append literals to. */
Tcl_Obj *funcList, /* List to append function names to. */
Tcl_Parse *parsePtr, /* Structure to fill with tokens representing
* those operands that require run time
* substitutions. */
| | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
OpNode **opTreePtr, /* Points to space where a pointer to the
* allocated OpNode tree should go. */
Tcl_Obj *litList, /* List to append literals to. */
Tcl_Obj *funcList, /* List to append function names to. */
Tcl_Parse *parsePtr, /* Structure to fill with tokens representing
* those operands that require run time
* substitutions. */
int parseOnly) /* A boolean indicating whether the caller's
* aim is just a parse, or whether it will go
* on to compile the expression. Different
* optimizations are appropriate for the two
* scenarios. */
{
OpNode *nodes = NULL; /* Pointer to the OpNode storage array where
* we build the parse tree. */
|
| ︙ | ︙ | |||
606 607 608 609 610 611 612 |
* errorCode. */
const char *mark = "_@_"; /* In the portion of the complete error
* message where the error location is
* reported, this "mark" substring is inserted
* into the string being parsed to aid in
* pinpointing the location of the syntax
* error in the expression. */
| | | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 |
* errorCode. */
const char *mark = "_@_"; /* In the portion of the complete error
* message where the error location is
* reported, this "mark" substring is inserted
* into the string being parsed to aid in
* pinpointing the location of the syntax
* error in the expression. */
int insertMark = 0; /* A boolean controlling whether the "mark"
* should be inserted. */
const int limit = 25; /* Portions of the error message are
* constructed out of substrings of the
* original expression. In order to keep the
* error message readable, we impose this
* limit on the substring size we extract. */
|
| ︙ | ︙ | |||
655 656 657 658 659 660 661 |
/*
* Each pass through this loop adds up to one more OpNode. Allocate
* space for one if required.
*/
if (nodesUsed >= nodesAvailable) {
| | | 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
/*
* Each pass through this loop adds up to one more OpNode. Allocate
* space for one if required.
*/
if (nodesUsed >= nodesAvailable) {
unsigned int size = nodesUsed * 2;
OpNode *newPtr = NULL;
do {
if (size <= UINT_MAX/sizeof(OpNode)) {
newPtr = (OpNode *) Tcl_AttemptRealloc(nodes,
size * sizeof(OpNode));
}
|
| ︙ | ︙ | |||
691 692 693 694 695 696 697 |
scanned = ParseLexeme(start, numBytes, &lexeme, &literal);
/*
* Use context to categorize the lexemes that are ambiguous.
*/
if ((NODE_TYPE & lexeme) == 0) {
| | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
scanned = ParseLexeme(start, numBytes, &lexeme, &literal);
/*
* Use context to categorize the lexemes that are ambiguous.
*/
if ((NODE_TYPE & lexeme) == 0) {
int b;
switch (lexeme) {
case COMMENT:
start += scanned;
numBytes -= scanned;
continue;
case INVALID:
|
| ︙ | ︙ | |||
717 718 719 720 721 722 723 | /* * Most barewords in an expression are a syntax error. The * exceptions are that when a bareword is followed by an open * paren, it might be a function call, and when the bareword * is a legal literal boolean value, we accept that as well. */ | | | | | < | < | 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 |
/*
* Most barewords in an expression are a syntax error. The
* exceptions are that when a bareword is followed by an open
* paren, it might be a function call, and when the bareword
* is a legal literal boolean value, we accept that as well.
*/
if (start[scanned+TclParseAllWhiteSpace(
start+scanned, numBytes-scanned)] == '(') {
lexeme = FUNCTION;
/*
* When we compile the expression we'll need the function
* name, and there's no place in the parse tree to store
* it, so we keep a separate list of all the function
* names we've parsed in the order we found them.
*/
Tcl_ListObjAppendElement(NULL, funcList, literal);
} else if (Tcl_GetBooleanFromObj(NULL,literal,&b) == TCL_OK) {
lexeme = BOOL_LIT;
} else {
/*
* Tricky case: see test expr-62.10
*/
int scanned2 = scanned;
do {
scanned2 += TclParseAllWhiteSpace(
start + scanned2, numBytes - scanned2);
scanned2 += ParseLexeme(
start + scanned2, numBytes - scanned2, &lexeme,
NULL);
} while (lexeme == COMMENT);
if (lexeme == OPEN_PAREN) {
/*
* Actually a function call, but with obscuring
* comments. Skip to the start of the parentheses.
* Note that we assume that open parentheses are one
* byte long.
*/
lexeme = FUNCTION;
Tcl_ListObjAppendElement(NULL, funcList, literal);
scanned = scanned2 - 1;
break;
}
Tcl_DecrRefCount(literal);
msg = Tcl_ObjPrintf("invalid bareword \"%.*s%s\"",
(int)((scanned < limit) ? scanned : limit - 3), start,
(scanned < limit) ? "" : "...");
post = Tcl_ObjPrintf(
"should be \"$%.*s%s\" or \"{%.*s%s}\"",
(int) ((scanned < limit) ? scanned : limit - 3),
start, (scanned < limit) ? "" : "...",
|
| ︙ | ︙ | |||
783 784 785 786 787 788 789 |
TclParseNumber(NULL, NULL, NULL, start, scanned,
&stop, TCL_PARSE_NO_WHITESPACE);
if (isdigit(UCHAR(*stop)) || (stop == start + 1)) {
switch (start[1]) {
case 'b':
Tcl_AppendToObj(post,
| | < | < | < | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 |
TclParseNumber(NULL, NULL, NULL, start, scanned,
&stop, TCL_PARSE_NO_WHITESPACE);
if (isdigit(UCHAR(*stop)) || (stop == start + 1)) {
switch (start[1]) {
case 'b':
Tcl_AppendToObj(post,
" (invalid binary number?)", -1);
parsePtr->errorType = TCL_PARSE_BAD_NUMBER;
errCode = "BADNUMBER";
subErrCode = "BINARY";
break;
case 'o':
Tcl_AppendToObj(post,
" (invalid octal number?)", -1);
parsePtr->errorType = TCL_PARSE_BAD_NUMBER;
errCode = "BADNUMBER";
subErrCode = "OCTAL";
break;
default:
if (isdigit(UCHAR(start[1]))) {
Tcl_AppendToObj(post,
" (invalid octal number?)", -1);
parsePtr->errorType = TCL_PARSE_BAD_NUMBER;
errCode = "BADNUMBER";
subErrCode = "OCTAL";
}
break;
}
}
|
| ︙ | ︙ | |||
843 844 845 846 847 848 849 | * litList, or a sequence of Tcl_Tokens representing a Tcl word * getting appended to the parsePtr->tokens. No OpNode is filled * for this lexeme. */ Tcl_Token *tokenPtr; const char *end = start; | | | | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 |
* litList, or a sequence of Tcl_Tokens representing a Tcl word
* getting appended to the parsePtr->tokens. No OpNode is filled
* for this lexeme.
*/
Tcl_Token *tokenPtr;
const char *end = start;
int wordIndex;
int code = TCL_OK;
/*
* A leaf operand appearing just after something that's not an
* operator is a syntax error.
*/
if (NotOperator(lastParsed)) {
msg = Tcl_ObjPrintf("missing operator at %s", mark);
errCode = "MISSING";
scanned = 0;
insertMark = 1;
/*
* Free any literal to avoid a memleak.
*/
if ((lexeme == NUMBER) || (lexeme == BOOL_LIT)) {
Tcl_DecrRefCount(literal);
|
| ︙ | ︙ | |||
1054 1055 1056 1057 1058 1059 1060 |
* operator is a syntax error -- something trying to be the left
* operand of an operator that doesn't take one.
*/
if (NotOperator(lastParsed)) {
msg = Tcl_ObjPrintf("missing operator at %s", mark);
scanned = 0;
| | | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 |
* operator is a syntax error -- something trying to be the left
* operand of an operator that doesn't take one.
*/
if (NotOperator(lastParsed)) {
msg = Tcl_ObjPrintf("missing operator at %s", mark);
scanned = 0;
insertMark = 1;
errCode = "MISSING";
goto error;
}
/*
* Create an OpNode for the unary operator.
*/
|
| ︙ | ︙ | |||
1082 1083 1084 1085 1086 1087 1088 | /* * This unary operator is a new incomplete tree, so push it onto * our stack of incomplete trees. Also remember it as the last * lexeme we parsed. */ | | | 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 |
/*
* This unary operator is a new incomplete tree, so push it onto
* our stack of incomplete trees. Also remember it as the last
* lexeme we parsed.
*/
nodePtr->p.prev = incomplete;
incomplete = lastParsed = nodesUsed;
nodesUsed++;
break;
case BINARY: {
OpNode *incompletePtr;
unsigned char precedence = prec[lexeme];
|
| ︙ | ︙ | |||
1116 1117 1118 1119 1120 1121 1122 |
scanned = 0;
complete = lastParsed = OT_EMPTY;
break;
}
msg = Tcl_ObjPrintf("empty subexpression at %s", mark);
scanned = 0;
| | | | | | 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 |
scanned = 0;
complete = lastParsed = OT_EMPTY;
break;
}
msg = Tcl_ObjPrintf("empty subexpression at %s", mark);
scanned = 0;
insertMark = 1;
errCode = "EMPTY";
goto error;
}
if (nodePtr[-1].precedence > precedence) {
if (nodePtr[-1].lexeme == OPEN_PAREN) {
TclNewLiteralStringObj(msg, "unbalanced open paren");
parsePtr->errorType = TCL_PARSE_MISSING_PAREN;
errCode = "UNBALANCED";
} else if (nodePtr[-1].lexeme == COMMA) {
msg = Tcl_ObjPrintf(
"missing function argument at %s", mark);
scanned = 0;
insertMark = 1;
errCode = "MISSING";
} else if (nodePtr[-1].lexeme == START) {
TclNewLiteralStringObj(msg, "empty expression");
errCode = "EMPTY";
}
} else if (lexeme == CLOSE_PAREN) {
TclNewLiteralStringObj(msg, "unbalanced close paren");
errCode = "UNBALANCED";
} else if ((lexeme == COMMA)
&& (nodePtr[-1].lexeme == OPEN_PAREN)
&& (nodePtr[-2].lexeme == FUNCTION)) {
msg = Tcl_ObjPrintf("missing function argument at %s",
mark);
scanned = 0;
insertMark = 1;
errCode = "UNBALANCED";
}
if (msg == NULL) {
msg = Tcl_ObjPrintf("missing operand at %s", mark);
scanned = 0;
insertMark = 1;
errCode = "MISSING";
}
goto error;
}
/*
* Here is where the tree comes together. At this point, we have a
|
| ︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 |
/* Right operand of "?" must be ":" */
if ((incompletePtr->lexeme == QUESTION)
&& (NotOperator(complete)
|| (nodes[complete].lexeme != COLON))) {
msg = Tcl_ObjPrintf("missing operator \":\" at %s", mark);
scanned = 0;
| | | 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 |
/* Right operand of "?" must be ":" */
if ((incompletePtr->lexeme == QUESTION)
&& (NotOperator(complete)
|| (nodes[complete].lexeme != COLON))) {
msg = Tcl_ObjPrintf("missing operator \":\" at %s", mark);
scanned = 0;
insertMark = 1;
errCode = "MISSING";
goto error;
}
/* Operator ":" may only be right operand of "?" */
if (IsOperator(complete)
&& (nodes[complete].lexeme == COLON)
|
| ︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 |
/*
* Attach complete tree as right operand of most recent
* incomplete tree.
*/
incompletePtr->right = complete;
if (IsOperator(complete)) {
| | | 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 |
/*
* Attach complete tree as right operand of most recent
* incomplete tree.
*/
incompletePtr->right = complete;
if (IsOperator(complete)) {
nodes[complete].p.parent = incomplete;
incompletePtr->constant = incompletePtr->constant
&& nodes[complete].constant;
} else {
incompletePtr->constant = incompletePtr->constant
&& (complete == OT_LITERAL);
}
|
| ︙ | ︙ | |||
1298 1299 1300 1301 1302 1303 1304 | /* * With a right operand attached, last incomplete tree has * become the complete tree. Pop it from the incomplete tree * stack. */ complete = incomplete; | | | 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 |
/*
* With a right operand attached, last incomplete tree has
* become the complete tree. Pop it from the incomplete tree
* stack.
*/
complete = incomplete;
incomplete = incompletePtr->p.prev;
/* CLOSE_PAREN can only close one OPEN_PAREN. */
if (incompletePtr->lexeme == OPEN_PAREN) {
break;
}
}
|
| ︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 |
errCode = "UNBALANCED";
goto error;
}
}
/* Commas must appear only in function argument lists. */
if (lexeme == COMMA) {
| | | 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 |
errCode = "UNBALANCED";
goto error;
}
}
/* Commas must appear only in function argument lists. */
if (lexeme == COMMA) {
if ((incompletePtr->lexeme != OPEN_PAREN)
|| (incompletePtr[-1].lexeme != FUNCTION)) {
TclNewLiteralStringObj(msg,
"unexpected \",\" outside function argument list");
errCode = "SURPRISE";
goto error;
}
}
|
| ︙ | ︙ | |||
1365 1366 1367 1368 1369 1370 1371 |
* number. Other binary operators root constant expressions when
* both arguments are constant expressions.
*/
nodePtr->constant = (lexeme != COMMA);
if (IsOperator(complete)) {
| | | | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 |
* number. Other binary operators root constant expressions when
* both arguments are constant expressions.
*/
nodePtr->constant = (lexeme != COMMA);
if (IsOperator(complete)) {
nodes[complete].p.parent = nodesUsed;
nodePtr->constant = nodePtr->constant
&& nodes[complete].constant;
} else {
nodePtr->constant = nodePtr->constant
&& (complete == OT_LITERAL);
}
/*
* With a left operand attached and a right operand missing, the
* just-parsed binary operator is root of a new incomplete tree.
* Push it onto the stack of incomplete trees.
*/
nodePtr->p.prev = incomplete;
incomplete = lastParsed = nodesUsed;
nodesUsed++;
break;
} /* case BINARY */
} /* lexeme handler */
/* Advance past the just-parsed lexeme */
|
| ︙ | ︙ | |||
1450 1451 1452 1453 1454 1455 1456 |
(start + scanned + limit > parsePtr->end) ? "" : "...");
/*
* Next, append any postscript message.
*/
if (post != NULL) {
| | | 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 |
(start + scanned + limit > parsePtr->end) ? "" : "...");
/*
* Next, append any postscript message.
*/
if (post != NULL) {
Tcl_AppendToObj(msg, ";\n", -1);
Tcl_AppendObjToObj(msg, post);
Tcl_DecrRefCount(post);
}
Tcl_SetObjResult(interp, msg);
/*
* Finally, place context information in the errorInfo.
|
| ︙ | ︙ | |||
1505 1506 1507 1508 1509 1510 1511 |
ConvertTreeToTokens(
const char *start,
Tcl_Size numBytes,
OpNode *nodes,
Tcl_Token *tokenPtr,
Tcl_Parse *parsePtr)
{
| | | | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 |
ConvertTreeToTokens(
const char *start,
Tcl_Size numBytes,
OpNode *nodes,
Tcl_Token *tokenPtr,
Tcl_Parse *parsePtr)
{
int subExprTokenIdx = 0;
OpNode *nodePtr = nodes;
int next = nodePtr->right;
while (1) {
Tcl_Token *subExprTokenPtr;
int scanned, parentIdx;
unsigned char lexeme;
/*
* Advance the mark so the next exit from this node won't retrace
* steps over ground already covered.
*/
|
| ︙ | ︙ | |||
1578 1579 1580 1581 1582 1583 1584 | * grouping device so that TCL_TOKEN_SUB_EXPR always has only one * element. Wise or not, these are the rules the Tcl expr parser * has followed, and for the sake of those few callers of * Tcl_ParseExpr() we do not change them now. Internally, we can * do better. */ | | | 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 |
* grouping device so that TCL_TOKEN_SUB_EXPR always has only one
* element. Wise or not, these are the rules the Tcl expr parser
* has followed, and for the sake of those few callers of
* Tcl_ParseExpr() we do not change them now. Internally, we can
* do better.
*/
int toCopy = tokenPtr->numComponents + 1;
if (tokenPtr->numComponents == tokenPtr[1].numComponents + 1) {
/*
* Single element word. Copy tokens and convert the leading
* token to TCL_TOKEN_SUB_EXPR.
*/
|
| ︙ | ︙ | |||
1794 1795 1796 1797 1798 1799 1800 | * All the Tcl_Tokens allocated and filled belong to * this subexpression. The first token is the leading * TCL_TOKEN_SUB_EXPR token, and all the rest (one fewer) * are its components. */ subExprTokenPtr->numComponents = | | | | 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 |
* All the Tcl_Tokens allocated and filled belong to
* this subexpression. The first token is the leading
* TCL_TOKEN_SUB_EXPR token, and all the rest (one fewer)
* are its components.
*/
subExprTokenPtr->numComponents =
((int)parsePtr->numTokens - subExprTokenIdx) - 1;
/*
* Finally, as we return up the tree to our parent, pop the
* parent subexpression off our subexpression stack, and
* fill in the zero numComponents for the operator Tcl_Token.
*/
parentIdx = subExprTokenPtr[1].numComponents;
subExprTokenPtr[1].numComponents = 0;
subExprTokenIdx = parentIdx;
break;
}
/*
* Since we're returning to parent, skip child handling code.
*/
nodePtr = nodes + nodePtr->p.parent;
goto router;
}
}
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1857 1858 1859 1860 1861 1862 1863 |
* first null character. */
Tcl_Parse *parsePtr) /* Structure to fill with information about
* the parsed expression; any previous
* information in the structure is ignored. */
{
int code;
OpNode *opTree = NULL; /* Will point to the tree of operators. */
| | | | | | | 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 |
* first null character. */
Tcl_Parse *parsePtr) /* Structure to fill with information about
* the parsed expression; any previous
* information in the structure is ignored. */
{
int code;
OpNode *opTree = NULL; /* Will point to the tree of operators. */
Tcl_Obj *litList; /* List to hold the literals. */
Tcl_Obj *funcList; /* List to hold the functon names. */
Tcl_Parse *exprParsePtr = (Tcl_Parse *)TclStackAlloc(interp, sizeof(Tcl_Parse));
/* Holds the Tcl_Tokens of substitutions. */
TclNewObj(litList);
TclNewObj(funcList);
if (numBytes < 0) {
numBytes = (start ? strlen(start) : 0);
}
code = ParseExpr(interp, start, numBytes, &opTree, litList, funcList,
exprParsePtr, 1 /* parseOnly */);
Tcl_DecrRefCount(funcList);
Tcl_DecrRefCount(litList);
TclParseInit(interp, start, numBytes, parsePtr);
if (code == TCL_OK) {
ConvertTreeToTokens(start, numBytes,
opTree, exprParsePtr->tokenPtr, parsePtr);
|
| ︙ | ︙ | |||
2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 |
break;
}
TclNewObj(literal);
if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
if (end < start + numBytes && !TclIsBareword(*end)) {
number:
*lexemePtr = NUMBER;
if (literalPtr) {
| > | < < < | 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 |
break;
}
TclNewObj(literal);
if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
if (end < start + numBytes && !TclIsBareword(*end)) {
number:
*lexemePtr = NUMBER;
if (literalPtr) {
TclInitStringRep(literal, start, end-start);
*literalPtr = literal;
} else {
Tcl_DecrRefCount(literal);
}
return (end-start);
} else {
unsigned char lexeme;
|
| ︙ | ︙ | |||
2189 2190 2191 2192 2193 2194 2195 |
void
TclCompileExpr(
Tcl_Interp *interp, /* Used for error reporting. */
const char *script, /* The source script to compile. */
Tcl_Size numBytes, /* Number of bytes in script. */
CompileEnv *envPtr, /* Holds resulting instructions. */
| | | | 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 |
void
TclCompileExpr(
Tcl_Interp *interp, /* Used for error reporting. */
const char *script, /* The source script to compile. */
Tcl_Size numBytes, /* Number of bytes in script. */
CompileEnv *envPtr, /* Holds resulting instructions. */
int optimize) /* 0 for one-off expressions. */
{
OpNode *opTree = NULL; /* Will point to the tree of operators */
Tcl_Obj *litList; /* List to hold the literals */
Tcl_Obj *funcList; /* List to hold the functon names*/
Tcl_Parse *parsePtr = (Tcl_Parse *)TclStackAlloc(interp, sizeof(Tcl_Parse));
/* Holds the Tcl_Tokens of substitutions */
int code;
TclNewObj(litList);
TclNewObj(funcList);
code = ParseExpr(interp, script, numBytes, &opTree, litList,
funcList, parsePtr, 0 /* parseOnly */);
if (code == TCL_OK) {
/*
* Valid parse; compile the tree.
*/
Tcl_Size objc;
|
| ︙ | ︙ | |||
2235 2236 2237 2238 2239 2240 2241 |
Tcl_Free(opTree);
}
/*
*----------------------------------------------------------------------
*
* ExecConstantExprTree --
| < | | | | 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 |
Tcl_Free(opTree);
}
/*
*----------------------------------------------------------------------
*
* ExecConstantExprTree --
* Compiles and executes bytecode for the subexpression tree at index
* in the nodes array. This subexpression must be constant, made up
* of only constant operators (not functions) and literals.
*
* Results:
* A standard Tcl return code and result left in interp.
*
* Side effects:
* Consumes subtree of nodes rooted at index. Advances the pointer
* *litObjvPtr.
*
*----------------------------------------------------------------------
*/
static int
ExecConstantExprTree(
Tcl_Interp *interp,
OpNode *nodes,
int index,
Tcl_Obj *const **litObjvPtr)
{
CompileEnv *envPtr;
ByteCode *byteCodePtr;
int code;
NRE_callback *rootPtr = TOP_CB(interp);
/*
* Note we are compiling an expression with literal arguments. This means
* there can be no [info frame] calls when we execute the resulting
* bytecode, so there's no need to tend to TIP 280 issues.
*/
envPtr = (CompileEnv *)TclStackAlloc(interp, sizeof(CompileEnv));
TclInitCompileEnv(interp, envPtr, NULL, 0, NULL, 0);
CompileExprTree(interp, nodes, index, litObjvPtr, NULL, NULL, envPtr,
0 /* optimize */);
TclEmitOpcode(INST_DONE, envPtr);
byteCodePtr = TclInitByteCode(envPtr);
TclFreeCompileEnv(envPtr);
TclStackFree(interp, envPtr);
TclNRExecuteByteCode(interp, byteCodePtr);
code = TclNRRunCallbacks(interp, TCL_OK, rootPtr);
TclReleaseByteCode(byteCodePtr);
return code;
|
| ︙ | ︙ | |||
2309 2310 2311 2312 2313 2314 2315 |
*----------------------------------------------------------------------
*/
static void
CompileExprTree(
Tcl_Interp *interp,
OpNode *nodes,
| | | | | | > > > | | > > > | > | 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 |
*----------------------------------------------------------------------
*/
static void
CompileExprTree(
Tcl_Interp *interp,
OpNode *nodes,
int index,
Tcl_Obj *const **litObjvPtr,
Tcl_Obj *const *funcObjv,
Tcl_Token *tokenPtr,
CompileEnv *envPtr,
int optimize)
{
OpNode *nodePtr = nodes + index;
OpNode *rootPtr = nodePtr;
int numWords = 0;
JumpList *jumpPtr = NULL;
int convert = 1;
while (1) {
int next;
JumpList *freePtr, *newJump;
if (nodePtr->mark == MARK_LEFT) {
next = nodePtr->left;
if (nodePtr->lexeme == QUESTION) {
convert = 1;
}
} else if (nodePtr->mark == MARK_RIGHT) {
next = nodePtr->right;
switch (nodePtr->lexeme) {
case FUNCTION: {
Tcl_DString cmdName;
const char *p;
Tcl_Size length;
Tcl_DStringInit(&cmdName);
TclDStringAppendLiteral(&cmdName, "tcl::mathfunc::");
p = TclGetStringFromObj(*funcObjv, &length);
funcObjv++;
Tcl_DStringAppend(&cmdName, p, length);
TclEmitPush(TclRegisterLiteral(envPtr,
Tcl_DStringValue(&cmdName),
Tcl_DStringLength(&cmdName), LITERAL_CMD_NAME), envPtr);
Tcl_DStringFree(&cmdName);
/*
* Start a count of the number of words in this function
* command invocation. In case there's already a count in
* progress (nested functions), save it in our unused "left"
* field for restoring later.
*/
|
| ︙ | ︙ | |||
2367 2368 2369 2370 2371 2372 2373 | break; case COLON: newJump = (JumpList *)TclStackAlloc(interp, sizeof(JumpList)); newJump->next = jumpPtr; jumpPtr = newJump; TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpPtr->jump); | | | | < | | > > > > | | | | > > | > | < < | < > | > | | > | | > > > | > | | | | > | > > | | | 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 |
break;
case COLON:
newJump = (JumpList *)TclStackAlloc(interp, sizeof(JumpList));
newJump->next = jumpPtr;
jumpPtr = newJump;
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
&jumpPtr->jump);
TclAdjustStackDepth(-1, envPtr);
if (convert) {
jumpPtr->jump.jumpType = TCL_TRUE_JUMP;
}
convert = 1;
break;
case AND:
case OR:
newJump = (JumpList *)TclStackAlloc(interp, sizeof(JumpList));
newJump->next = jumpPtr;
jumpPtr = newJump;
TclEmitForwardJump(envPtr, (nodePtr->lexeme == AND)
? TCL_FALSE_JUMP : TCL_TRUE_JUMP, &jumpPtr->jump);
break;
}
} else {
int pc1, pc2, target;
switch (nodePtr->lexeme) {
case START:
case QUESTION:
if (convert && (nodePtr == rootPtr)) {
TclEmitOpcode(INST_TRY_CVT_TO_NUMERIC, envPtr);
}
break;
case OPEN_PAREN:
/* do nothing */
break;
case FUNCTION:
/*
* Use the numWords count we've kept to invoke the function
* command with the correct number of arguments.
*/
if (numWords < 255) {
TclEmitInvoke(envPtr, INST_INVOKE_STK1, numWords);
} else {
TclEmitInvoke(envPtr, INST_INVOKE_STK4, numWords);
}
/*
* Restore any saved numWords value.
*/
numWords = nodePtr->left;
convert = 1;
break;
case COMMA:
/*
* Each comma implies another function argument.
*/
numWords++;
break;
case COLON:
CLANG_ASSERT(jumpPtr);
if (jumpPtr->jump.jumpType == TCL_TRUE_JUMP) {
jumpPtr->jump.jumpType = TCL_UNCONDITIONAL_JUMP;
convert = 1;
}
target = jumpPtr->jump.codeOffset + 2;
if (TclFixupForwardJumpToHere(envPtr, &jumpPtr->jump, 127)) {
target += 3;
}
freePtr = jumpPtr;
jumpPtr = jumpPtr->next;
TclStackFree(interp, freePtr);
TclFixupForwardJump(envPtr, &jumpPtr->jump,
target - jumpPtr->jump.codeOffset, 127);
freePtr = jumpPtr;
jumpPtr = jumpPtr->next;
TclStackFree(interp, freePtr);
break;
case AND:
case OR:
CLANG_ASSERT(jumpPtr);
pc1 = CurrentOffset(envPtr);
TclEmitInstInt1((nodePtr->lexeme == AND) ? INST_JUMP_FALSE1
: INST_JUMP_TRUE1, 0, envPtr);
TclEmitPush(TclRegisterLiteral(envPtr,
(nodePtr->lexeme == AND) ? "1" : "0", 1, 0), envPtr);
pc2 = CurrentOffset(envPtr);
TclEmitInstInt1(INST_JUMP1, 0, envPtr);
TclAdjustStackDepth(-1, envPtr);
TclStoreInt1AtPtr(CurrentOffset(envPtr) - pc1,
envPtr->codeStart + pc1 + 1);
if (TclFixupForwardJumpToHere(envPtr, &jumpPtr->jump, 127)) {
pc2 += 3;
}
TclEmitPush(TclRegisterLiteral(envPtr,
(nodePtr->lexeme == AND) ? "0" : "1", 1, 0), envPtr);
TclStoreInt1AtPtr(CurrentOffset(envPtr) - pc2,
envPtr->codeStart + pc2 + 1);
convert = 0;
freePtr = jumpPtr;
jumpPtr = jumpPtr->next;
TclStackFree(interp, freePtr);
break;
default:
TclEmitOpcode(instruction[nodePtr->lexeme], envPtr);
convert = 0;
break;
}
if (nodePtr == rootPtr) {
/* We're done */
return;
}
nodePtr = nodes + nodePtr->p.parent;
continue;
}
nodePtr->mark++;
switch (next) {
case OT_EMPTY:
numWords = 1; /* No arguments, so just the command */
break;
case OT_LITERAL: {
Tcl_Obj *const *litObjv = *litObjvPtr;
Tcl_Obj *literal = *litObjv;
if (optimize) {
Tcl_Size length;
const char *bytes = TclGetStringFromObj(literal, &length);
int idx = TclRegisterLiteral(envPtr, bytes, length, 0);
Tcl_Obj *objPtr = TclFetchLiteral(envPtr, idx);
if ((objPtr->typePtr == NULL) && (literal->typePtr != NULL)) {
/*
* Would like to do this:
*
* lePtr->objPtr = literal;
* Tcl_IncrRefCount(literal);
* Tcl_DecrRefCount(objPtr);
*
* However, the design of the "global" and "local"
* LiteralTable does not permit the value of lePtr->objPtr
* to change. So rather than replace lePtr->objPtr, we do
* surgery to transfer our desired internalrep into it.
*/
objPtr->typePtr = literal->typePtr;
objPtr->internalRep = literal->internalRep;
literal->typePtr = NULL;
}
TclEmitPush(idx, envPtr);
} else {
/*
* When optimize==0, we know the expression is a one-off and
* there's nothing to be gained from sharing literals when
* they won't live long, and the copies we have already have
* an appropriate internalrep. In this case, skip literal
* registration that would enable sharing, and use the routine
* that preserves internalreps.
*/
TclEmitPush(TclAddLiteralObj(envPtr, literal, NULL), envPtr);
}
(*litObjvPtr)++;
break;
}
case OT_TOKENS:
CompileTokens(envPtr, tokenPtr, interp);
tokenPtr += tokenPtr->numComponents + 1;
|
| ︙ | ︙ | |||
2561 2562 2563 2564 2565 2566 2567 |
idx = TclAddLiteralObj(envPtr, objPtr, NULL);
}
TclEmitPush(idx, envPtr);
} else {
TclCompileSyntaxError(interp, envPtr);
}
Tcl_RestoreInterpState(interp, save);
| | | 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 |
idx = TclAddLiteralObj(envPtr, objPtr, NULL);
}
TclEmitPush(idx, envPtr);
} else {
TclCompileSyntaxError(interp, envPtr);
}
Tcl_RestoreInterpState(interp, save);
convert = 0;
} else {
nodePtr = nodes + next;
}
}
}
}
|
| ︙ | ︙ | |||
2592 2593 2594 2595 2596 2597 2598 |
*----------------------------------------------------------------------
*/
int
TclSingleOpCmd(
void *clientData,
Tcl_Interp *interp,
| | | | | < | | | < < | < | | | | | | | | | | | | | | | | | | | < | | | | | | | | < < | | | | | | < | | < | 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 |
*----------------------------------------------------------------------
*/
int
TclSingleOpCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData;
unsigned char lexeme;
OpNode nodes[2];
Tcl_Obj *const *litObjv = objv + 1;
if (objc != 1 + occdPtr->i.numArgs) {
Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected);
return TCL_ERROR;
}
ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL);
nodes[0].lexeme = START;
nodes[0].mark = MARK_RIGHT;
nodes[0].right = 1;
nodes[1].lexeme = lexeme;
if (objc == 2) {
nodes[1].mark = MARK_RIGHT;
} else {
nodes[1].mark = MARK_LEFT;
nodes[1].left = OT_LITERAL;
}
nodes[1].right = OT_LITERAL;
nodes[1].p.parent = 0;
return ExecConstantExprTree(interp, nodes, 0, &litObjv);
}
/*
*----------------------------------------------------------------------
*
* TclSortingOpCmd --
* Implements the commands:
* <, <=, >, >=, ==, eq, lt, le, gt, ge
* in the ::tcl::mathop namespace. These commands are defined for
* arbitrary number of arguments by computing the AND of the base
* operator applied to all neighbor argument pairs.
*
* Results:
* A standard Tcl return code and result left in interp.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclSortingOpCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int code = TCL_OK;
if (objc < 3) {
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(1));
} else {
TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData;
Tcl_Obj **litObjv = (Tcl_Obj **)TclStackAlloc(interp,
2 * (objc-2) * sizeof(Tcl_Obj *));
OpNode *nodes = (OpNode *)TclStackAlloc(interp, 2 * (objc-2) * sizeof(OpNode));
unsigned char lexeme;
int i, lastAnd = 1;
Tcl_Obj *const *litObjPtrPtr = litObjv;
ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL);
litObjv[0] = objv[1];
nodes[0].lexeme = START;
nodes[0].mark = MARK_RIGHT;
for (i=2; i<objc-1; i++) {
litObjv[2*(i-1)-1] = objv[i];
nodes[2*(i-1)-1].lexeme = lexeme;
nodes[2*(i-1)-1].mark = MARK_LEFT;
nodes[2*(i-1)-1].left = OT_LITERAL;
nodes[2*(i-1)-1].right = OT_LITERAL;
litObjv[2*(i-1)] = objv[i];
nodes[2*(i-1)].lexeme = AND;
nodes[2*(i-1)].mark = MARK_LEFT;
nodes[2*(i-1)].left = lastAnd;
nodes[lastAnd].p.parent = 2*(i-1);
nodes[2*(i-1)].right = 2*(i-1)+1;
nodes[2*(i-1)+1].p.parent= 2*(i-1);
lastAnd = 2*(i-1);
}
litObjv[2*(objc-2)-1] = objv[objc-1];
nodes[2*(objc-2)-1].lexeme = lexeme;
nodes[2*(objc-2)-1].mark = MARK_LEFT;
nodes[2*(objc-2)-1].left = OT_LITERAL;
nodes[2*(objc-2)-1].right = OT_LITERAL;
nodes[0].right = lastAnd;
nodes[lastAnd].p.parent = 0;
code = ExecConstantExprTree(interp, nodes, 0, &litObjPtrPtr);
TclStackFree(interp, nodes);
TclStackFree(interp, litObjv);
}
return code;
}
/*
*----------------------------------------------------------------------
*
* TclVariadicOpCmd --
* Implements the commands: +, *, &, |, ^, **
* in the ::tcl::mathop namespace. These commands are defined for
* arbitrary number of arguments by repeatedly applying the base
* operator with suitable associative rules. When fewer than two
* arguments are provided, suitable identity values are returned.
*
* Results:
* A standard Tcl return code and result left in interp.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclVariadicOpCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData;
unsigned char lexeme;
int code;
if (objc < 2) {
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(occdPtr->i.identity));
return TCL_OK;
}
ParseLexeme(occdPtr->op, strlen(occdPtr->op), &lexeme, NULL);
lexeme |= BINARY;
if (objc == 2) {
Tcl_Obj *litObjv[2];
OpNode nodes[2];
int decrMe = 0;
Tcl_Obj *const *litObjPtrPtr = litObjv;
if (lexeme == EXPON) {
TclNewIntObj(litObjv[1], occdPtr->i.identity);
Tcl_IncrRefCount(litObjv[1]);
decrMe = 1;
litObjv[0] = objv[1];
nodes[0].lexeme = START;
nodes[0].mark = MARK_RIGHT;
nodes[0].right = 1;
nodes[1].lexeme = lexeme;
nodes[1].mark = MARK_LEFT;
nodes[1].left = OT_LITERAL;
nodes[1].right = OT_LITERAL;
nodes[1].p.parent = 0;
} else {
if (lexeme == DIVIDE) {
TclNewDoubleObj(litObjv[0], 1.0);
} else {
TclNewIntObj(litObjv[0], occdPtr->i.identity);
}
Tcl_IncrRefCount(litObjv[0]);
litObjv[1] = objv[1];
nodes[0].lexeme = START;
nodes[0].mark = MARK_RIGHT;
nodes[0].right = 1;
nodes[1].lexeme = lexeme;
nodes[1].mark = MARK_LEFT;
nodes[1].left = OT_LITERAL;
nodes[1].right = OT_LITERAL;
nodes[1].p.parent = 0;
}
code = ExecConstantExprTree(interp, nodes, 0, &litObjPtrPtr);
Tcl_DecrRefCount(litObjv[decrMe]);
return code;
} else {
Tcl_Obj *const *litObjv = objv + 1;
OpNode *nodes = (OpNode *)TclStackAlloc(interp, (objc-1) * sizeof(OpNode));
int i, lastOp = OT_LITERAL;
nodes[0].lexeme = START;
nodes[0].mark = MARK_RIGHT;
if (lexeme == EXPON) {
for (i=objc-2; i>0; i--) {
nodes[i].lexeme = lexeme;
nodes[i].mark = MARK_LEFT;
nodes[i].left = OT_LITERAL;
nodes[i].right = lastOp;
if (lastOp >= 0) {
nodes[lastOp].p.parent = i;
}
lastOp = i;
}
} else {
for (i=1; i<objc-1; i++) {
nodes[i].lexeme = lexeme;
nodes[i].mark = MARK_LEFT;
nodes[i].left = lastOp;
if (lastOp >= 0) {
nodes[lastOp].p.parent = i;
}
nodes[i].right = OT_LITERAL;
lastOp = i;
}
}
nodes[0].right = lastOp;
nodes[lastOp].p.parent = 0;
code = ExecConstantExprTree(interp, nodes, 0, &litObjv);
TclStackFree(interp, nodes);
return code;
}
}
/*
*----------------------------------------------------------------------
*
* TclNoIdentOpCmd --
* Implements the commands: -, /
* in the ::tcl::mathop namespace. These commands are defined for
* arbitrary non-zero number of arguments by repeatedly applying the base
* operator with suitable associative rules. When no arguments are
* provided, an error is raised.
*
* Results:
* A standard Tcl return code and result left in interp.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclNoIdentOpCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected);
return TCL_ERROR;
}
return TclVariadicOpCmd(clientData, interp, objc, objv);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclCompile.c.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 | * Copyright © 2001 Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < | < < < < < < < < < < < < < < < < < < < < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | | > < | < | < | < | < | < | < | < | < | | < | | < | < | < | < | < | < | < | < | < | < | < | < | < | < < | < | < | < | < | < | < | < | < | < | < | < | | > < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | | | > < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | < | < | | | | | | | | | | | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 |
* Copyright © 2001 Kevin B. Kenny. All rights reserved.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
#include "tclCompile.h"
/*
* Variable that controls whether compilation tracing is enabled and, if so,
* what level of tracing is desired:
* 0: no compilation tracing
* 1: summarize compilation of top level cmds and proc bodies
* 2: display all instructions of each ByteCode compiled
* This variable is linked to the Tcl variable "tcl_traceCompile".
*/
#ifdef TCL_COMPILE_DEBUG
int tclTraceCompile = 0;
static int traceInitialized = 0;
#endif
/*
* A table describing the Tcl bytecode instructions. Entries in this table
* must correspond to the instruction opcode definitions in tclCompile.h. The
* names "op1" and "op4" refer to an instruction's one or four byte first
* operand. Similarly, "stktop" and "stknext" refer to the topmost and next to
* topmost stack elements.
*
* Note that the load, store, and incr instructions do not distinguish local
* from global variables; the bytecode interpreter at runtime uses the
* existence of a procedure call frame to distinguish these.
*/
InstructionDesc const tclInstructionTable[] = {
/* Name Bytes stackEffect #Opnds Operand types */
{"done", 1, -1, 0, {OPERAND_NONE}},
/* Finish ByteCode execution and return stktop (top stack item) */
{"push1", 2, +1, 1, {OPERAND_LIT1}},
/* Push object at ByteCode objArray[op1] */
{"push4", 5, +1, 1, {OPERAND_LIT4}},
/* Push object at ByteCode objArray[op4] */
{"pop", 1, -1, 0, {OPERAND_NONE}},
/* Pop the topmost stack object */
{"dup", 1, +1, 0, {OPERAND_NONE}},
/* Duplicate the topmost stack object and push the result */
{"strcat", 2, INT_MIN, 1, {OPERAND_UINT1}},
/* Concatenate the top op1 items and push result */
{"invokeStk1", 2, INT_MIN, 1, {OPERAND_UINT1}},
/* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
{"invokeStk4", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* Invoke command named objv[0]; <objc,objv> = <op4,top op4> */
{"evalStk", 1, 0, 0, {OPERAND_NONE}},
/* Evaluate command in stktop using Tcl_EvalObj. */
{"exprStk", 1, 0, 0, {OPERAND_NONE}},
/* Execute expression in stktop using Tcl_ExprStringObj. */
{"loadScalar1", 2, 1, 1, {OPERAND_LVT1}},
/* Load scalar variable at index op1 <= 255 in call frame */
{"loadScalar4", 5, 1, 1, {OPERAND_LVT4}},
/* Load scalar variable at index op1 >= 256 in call frame */
{"loadScalarStk", 1, 0, 0, {OPERAND_NONE}},
/* Load scalar variable; scalar's name is stktop */
{"loadArray1", 2, 0, 1, {OPERAND_LVT1}},
/* Load array element; array at slot op1<=255, element is stktop */
{"loadArray4", 5, 0, 1, {OPERAND_LVT4}},
/* Load array element; array at slot op1 > 255, element is stktop */
{"loadArrayStk", 1, -1, 0, {OPERAND_NONE}},
/* Load array element; element is stktop, array name is stknext */
{"loadStk", 1, 0, 0, {OPERAND_NONE}},
/* Load general variable; unparsed variable name is stktop */
{"storeScalar1", 2, 0, 1, {OPERAND_LVT1}},
/* Store scalar variable at op1<=255 in frame; value is stktop */
{"storeScalar4", 5, 0, 1, {OPERAND_LVT4}},
/* Store scalar variable at op1 > 255 in frame; value is stktop */
{"storeScalarStk", 1, -1, 0, {OPERAND_NONE}},
/* Store scalar; value is stktop, scalar name is stknext */
{"storeArray1", 2, -1, 1, {OPERAND_LVT1}},
/* Store array element; array at op1<=255, value is top then elem */
{"storeArray4", 5, -1, 1, {OPERAND_LVT4}},
/* Store array element; array at op1>=256, value is top then elem */
{"storeArrayStk", 1, -2, 0, {OPERAND_NONE}},
/* Store array element; value is stktop, then elem, array names */
{"storeStk", 1, -1, 0, {OPERAND_NONE}},
/* Store general variable; value is stktop, then unparsed name */
{"incrScalar1", 2, 0, 1, {OPERAND_LVT1}},
/* Incr scalar at index op1<=255 in frame; incr amount is stktop */
{"incrScalarStk", 1, -1, 0, {OPERAND_NONE}},
/* Incr scalar; incr amount is stktop, scalar's name is stknext */
{"incrArray1", 2, -1, 1, {OPERAND_LVT1}},
/* Incr array elem; arr at slot op1<=255, amount is top then elem */
{"incrArrayStk", 1, -2, 0, {OPERAND_NONE}},
/* Incr array element; amount is top then elem then array names */
{"incrStk", 1, -1, 0, {OPERAND_NONE}},
/* Incr general variable; amount is stktop then unparsed var name */
{"incrScalar1Imm", 3, +1, 2, {OPERAND_LVT1, OPERAND_INT1}},
/* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
{"incrScalarStkImm", 2, 0, 1, {OPERAND_INT1}},
/* Incr scalar; scalar name is stktop; incr amount is op1 */
{"incrArray1Imm", 3, 0, 2, {OPERAND_LVT1, OPERAND_INT1}},
/* Incr array elem; array at slot op1 <= 255, elem is stktop,
* amount is 2nd operand byte */
{"incrArrayStkImm", 2, -1, 1, {OPERAND_INT1}},
/* Incr array element; elem is top then array name, amount is op1 */
{"incrStkImm", 2, 0, 1, {OPERAND_INT1}},
/* Incr general variable; unparsed name is top, amount is op1 */
{"jump1", 2, 0, 1, {OPERAND_OFFSET1}},
/* Jump relative to (pc + op1) */
{"jump4", 5, 0, 1, {OPERAND_OFFSET4}},
/* Jump relative to (pc + op4) */
{"jumpTrue1", 2, -1, 1, {OPERAND_OFFSET1}},
/* Jump relative to (pc + op1) if stktop expr object is true */
{"jumpTrue4", 5, -1, 1, {OPERAND_OFFSET4}},
/* Jump relative to (pc + op4) if stktop expr object is true */
{"jumpFalse1", 2, -1, 1, {OPERAND_OFFSET1}},
/* Jump relative to (pc + op1) if stktop expr object is false */
{"jumpFalse4", 5, -1, 1, {OPERAND_OFFSET4}},
/* Jump relative to (pc + op4) if stktop expr object is false */
{"bitor", 1, -1, 0, {OPERAND_NONE}},
/* Bitwise or: push (stknext | stktop) */
{"bitxor", 1, -1, 0, {OPERAND_NONE}},
/* Bitwise xor push (stknext ^ stktop) */
{"bitand", 1, -1, 0, {OPERAND_NONE}},
/* Bitwise and: push (stknext & stktop) */
{"eq", 1, -1, 0, {OPERAND_NONE}},
/* Equal: push (stknext == stktop) */
{"neq", 1, -1, 0, {OPERAND_NONE}},
/* Not equal: push (stknext != stktop) */
{"lt", 1, -1, 0, {OPERAND_NONE}},
/* Less: push (stknext < stktop) */
{"gt", 1, -1, 0, {OPERAND_NONE}},
/* Greater: push (stknext > stktop) */
{"le", 1, -1, 0, {OPERAND_NONE}},
/* Less or equal: push (stknext <= stktop) */
{"ge", 1, -1, 0, {OPERAND_NONE}},
/* Greater or equal: push (stknext >= stktop) */
{"lshift", 1, -1, 0, {OPERAND_NONE}},
/* Left shift: push (stknext << stktop) */
{"rshift", 1, -1, 0, {OPERAND_NONE}},
/* Right shift: push (stknext >> stktop) */
{"add", 1, -1, 0, {OPERAND_NONE}},
/* Add: push (stknext + stktop) */
{"sub", 1, -1, 0, {OPERAND_NONE}},
/* Sub: push (stkext - stktop) */
{"mult", 1, -1, 0, {OPERAND_NONE}},
/* Multiply: push (stknext * stktop) */
{"div", 1, -1, 0, {OPERAND_NONE}},
/* Divide: push (stknext / stktop) */
{"mod", 1, -1, 0, {OPERAND_NONE}},
/* Mod: push (stknext % stktop) */
{"uplus", 1, 0, 0, {OPERAND_NONE}},
/* Unary plus: push +stktop */
{"uminus", 1, 0, 0, {OPERAND_NONE}},
/* Unary minus: push -stktop */
{"bitnot", 1, 0, 0, {OPERAND_NONE}},
/* Bitwise not: push ~stktop */
{"not", 1, 0, 0, {OPERAND_NONE}},
/* Logical not: push !stktop */
{"tryCvtToNumeric", 1, 0, 0, {OPERAND_NONE}},
/* Try converting stktop to first int then double if possible. */
{"break", 1, 0, 0, {OPERAND_NONE}},
/* Abort closest enclosing loop; if none, return TCL_BREAK code. */
{"continue", 1, 0, 0, {OPERAND_NONE}},
/* Skip to next iteration of closest enclosing loop; if none, return
* TCL_CONTINUE code. */
{"beginCatch4", 5, 0, 1, {OPERAND_UINT4}},
/* Record start of catch with the operand's exception index. Push the
* current stack depth onto a special catch stack. */
{"endCatch", 1, 0, 0, {OPERAND_NONE}},
/* End of last catch. Pop the bytecode interpreter's catch stack. */
{"pushResult", 1, +1, 0, {OPERAND_NONE}},
/* Push the interpreter's object result onto the stack. */
{"pushReturnCode", 1, +1, 0, {OPERAND_NONE}},
/* Push interpreter's return code (e.g. TCL_OK or TCL_ERROR) as a new
* object onto the stack. */
{"streq", 1, -1, 0, {OPERAND_NONE}},
/* Str Equal: push (stknext eq stktop) */
{"strneq", 1, -1, 0, {OPERAND_NONE}},
/* Str !Equal: push (stknext neq stktop) */
{"strcmp", 1, -1, 0, {OPERAND_NONE}},
/* Str Compare: push (stknext cmp stktop) */
{"strlen", 1, 0, 0, {OPERAND_NONE}},
/* Str Length: push (strlen stktop) */
{"strindex", 1, -1, 0, {OPERAND_NONE}},
/* Str Index: push (strindex stknext stktop) */
{"strmatch", 2, -1, 1, {OPERAND_INT1}},
/* Str Match: push (strmatch stknext stktop) opnd == nocase */
{"list", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* List: push (stk1 stk2 ... stktop) */
{"listIndex", 1, -1, 0, {OPERAND_NONE}},
/* List Index: push (listindex stknext stktop) */
{"listLength", 1, 0, 0, {OPERAND_NONE}},
/* List Len: push (listlength stktop) */
{"appendScalar1", 2, 0, 1, {OPERAND_LVT1}},
/* Append scalar variable at op1<=255 in frame; value is stktop */
{"appendScalar4", 5, 0, 1, {OPERAND_LVT4}},
/* Append scalar variable at op1 > 255 in frame; value is stktop */
{"appendArray1", 2, -1, 1, {OPERAND_LVT1}},
/* Append array element; array at op1<=255, value is top then elem */
{"appendArray4", 5, -1, 1, {OPERAND_LVT4}},
/* Append array element; array at op1>=256, value is top then elem */
{"appendArrayStk", 1, -2, 0, {OPERAND_NONE}},
/* Append array element; value is stktop, then elem, array names */
{"appendStk", 1, -1, 0, {OPERAND_NONE}},
/* Append general variable; value is stktop, then unparsed name */
{"lappendScalar1", 2, 0, 1, {OPERAND_LVT1}},
/* Lappend scalar variable at op1<=255 in frame; value is stktop */
{"lappendScalar4", 5, 0, 1, {OPERAND_LVT4}},
/* Lappend scalar variable at op1 > 255 in frame; value is stktop */
{"lappendArray1", 2, -1, 1, {OPERAND_LVT1}},
/* Lappend array element; array at op1<=255, value is top then elem */
{"lappendArray4", 5, -1, 1, {OPERAND_LVT4}},
/* Lappend array element; array at op1>=256, value is top then elem */
{"lappendArrayStk", 1, -2, 0, {OPERAND_NONE}},
/* Lappend array element; value is stktop, then elem, array names */
{"lappendStk", 1, -1, 0, {OPERAND_NONE}},
/* Lappend general variable; value is stktop, then unparsed name */
{"lindexMulti", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* Lindex with generalized args, operand is number of stacked objs
* used: (operand-1) entries from stktop are the indices; then list to
* process. */
{"over", 5, +1, 1, {OPERAND_UINT4}},
/* Duplicate the arg-th element from top of stack (TOS=0) */
{"lsetList", 1, -2, 0, {OPERAND_NONE}},
/* Four-arg version of 'lset'. stktop is old value; next is new
* element value, next is the index list; pushes new value */
{"lsetFlat", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* Three- or >=5-arg version of 'lset', operand is number of stacked
* objs: stktop is old value, next is new element value, next come
* (operand-2) indices; pushes the new value.
*/
{"returnImm", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},
/* Compiled [return], code, level are operands; options and result
* are on the stack. */
{"expon", 1, -1, 0, {OPERAND_NONE}},
/* Binary exponentiation operator: push (stknext ** stktop) */
/*
* NOTE: the stack effects of expandStkTop and invokeExpanded are wrong -
* but it cannot be done right at compile time, the stack effect is only
* known at run time. The value for invokeExpanded is estimated better at
* compile time.
* See the comments further down in this file, where INST_INVOKE_EXPANDED
* is emitted.
*/
{"expandStart", 1, 0, 0, {OPERAND_NONE}},
/* Start of command with {*} (expanded) arguments */
{"expandStkTop", 5, 0, 1, {OPERAND_UINT4}},
/* Expand the list at stacktop: push its elements on the stack */
{"invokeExpanded", 1, 0, 0, {OPERAND_NONE}},
/* Invoke the command marked by the last 'expandStart' */
{"listIndexImm", 5, 0, 1, {OPERAND_IDX4}},
/* List Index: push (lindex stktop op4) */
{"listRangeImm", 9, 0, 2, {OPERAND_IDX4, OPERAND_IDX4}},
/* List Range: push (lrange stktop op4 op4) */
{"startCommand", 9, 0, 2, {OPERAND_OFFSET4, OPERAND_UINT4}},
/* Start of bytecoded command: op is the length of the cmd's code, op2
* is number of commands here */
{"listIn", 1, -1, 0, {OPERAND_NONE}},
/* List containment: push [lsearch stktop stknext]>=0) */
{"listNotIn", 1, -1, 0, {OPERAND_NONE}},
/* List negated containment: push [lsearch stktop stknext]<0) */
{"pushReturnOpts", 1, +1, 0, {OPERAND_NONE}},
/* Push the interpreter's return option dictionary as an object on the
* stack. */
{"returnStk", 1, -1, 0, {OPERAND_NONE}},
/* Compiled [return]; options and result are on the stack, code and
* level are in the options. */
{"dictGet", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* The top op4 words (min 1) are a key path into the dictionary just
* below the keys on the stack, and all those values are replaced by
* the value read out of that key-path (like [dict get]).
* Stack: ... dict key1 ... keyN => ... value */
{"dictSet", 9, INT_MIN, 2, {OPERAND_UINT4, OPERAND_LVT4}},
/* Update a dictionary value such that the keys are a path pointing to
* the value. op4#1 = numKeys, op4#2 = LVTindex
* Stack: ... key1 ... keyN value => ... newDict */
{"dictUnset", 9, INT_MIN, 2, {OPERAND_UINT4, OPERAND_LVT4}},
/* Update a dictionary value such that the keys are not a path pointing
* to any value. op4#1 = numKeys, op4#2 = LVTindex
* Stack: ... key1 ... keyN => ... newDict */
{"dictIncrImm", 9, 0, 2, {OPERAND_INT4, OPERAND_LVT4}},
/* Update a dictionary value such that the value pointed to by key is
* incremented by some value (or set to it if the key isn't in the
* dictionary at all). op4#1 = incrAmount, op4#2 = LVTindex
* Stack: ... key => ... newDict */
{"dictAppend", 5, -1, 1, {OPERAND_LVT4}},
/* Update a dictionary value such that the value pointed to by key has
* some value string-concatenated onto it. op4 = LVTindex
* Stack: ... key valueToAppend => ... newDict */
{"dictLappend", 5, -1, 1, {OPERAND_LVT4}},
/* Update a dictionary value such that the value pointed to by key has
* some value list-appended onto it. op4 = LVTindex
* Stack: ... key valueToAppend => ... newDict */
{"dictFirst", 5, +2, 1, {OPERAND_LVT4}},
/* Begin iterating over the dictionary, using the local scalar
* indicated by op4 to hold the iterator state. The local scalar
* should not refer to a named variable as the value is not wholly
* managed correctly.
* Stack: ... dict => ... value key doneBool */
{"dictNext", 5, +3, 1, {OPERAND_LVT4}},
/* Get the next iteration from the iterator in op4's local scalar.
* Stack: ... => ... value key doneBool */
{"dictUpdateStart", 9, 0, 2, {OPERAND_LVT4, OPERAND_AUX4}},
/* Create the variables (described in the aux data referred to by the
* second immediate argument) to mirror the state of the dictionary in
* the variable referred to by the first immediate argument. The list
* of keys (top of the stack, not popped) must be the same length as
* the list of variables.
* Stack: ... keyList => ... keyList */
{"dictUpdateEnd", 9, -1, 2, {OPERAND_LVT4, OPERAND_AUX4}},
/* Reflect the state of local variables (described in the aux data
* referred to by the second immediate argument) back to the state of
* the dictionary in the variable referred to by the first immediate
* argument. The list of keys (popped from the stack) must be the same
* length as the list of variables.
* Stack: ... keyList => ... */
{"jumpTable", 5, -1, 1, {OPERAND_AUX4}},
/* Jump according to the jump-table (in AuxData as indicated by the
* operand) and the argument popped from the list. Always executes the
* next instruction if no match against the table's entries was found.
* Stack: ... value => ...
* Note that the jump table contains offsets relative to the PC when
* it points to this instruction; the code is relocatable. */
{"upvar", 5, -1, 1, {OPERAND_LVT4}},
/* finds level and otherName in stack, links to local variable at
* index op1. Leaves the level on stack. */
{"nsupvar", 5, -1, 1, {OPERAND_LVT4}},
/* finds namespace and otherName in stack, links to local variable at
* index op1. Leaves the namespace on stack. */
{"variable", 5, -1, 1, {OPERAND_LVT4}},
/* finds namespace and otherName in stack, links to local variable at
* index op1. Leaves the namespace on stack. */
{"syntax", 9, -1, 2, {OPERAND_INT4, OPERAND_UINT4}},
/* Compiled bytecodes to signal syntax error. Equivalent to returnImm
* except for the ERR_ALREADY_LOGGED flag in the interpreter. */
{"reverse", 5, 0, 1, {OPERAND_UINT4}},
/* Reverse the order of the arg elements at the top of stack */
{"regexp", 2, -1, 1, {OPERAND_INT1}},
/* Regexp: push (regexp stknext stktop) opnd == nocase */
{"existScalar", 5, 1, 1, {OPERAND_LVT4}},
/* Test if scalar variable at index op1 in call frame exists */
{"existArray", 5, 0, 1, {OPERAND_LVT4}},
/* Test if array element exists; array at slot op1, element is
* stktop */
{"existArrayStk", 1, -1, 0, {OPERAND_NONE}},
/* Test if array element exists; element is stktop, array name is
* stknext */
{"existStk", 1, 0, 0, {OPERAND_NONE}},
/* Test if general variable exists; unparsed variable name is stktop*/
{"nop", 1, 0, 0, {OPERAND_NONE}},
/* Do nothing */
{"returnCodeBranch", 1, -1, 0, {OPERAND_NONE}},
/* Jump to next instruction based on the return code on top of stack
* ERROR: +1; RETURN: +3; BREAK: +5; CONTINUE: +7;
* Other non-OK: +9
*/
{"unsetScalar", 6, 0, 2, {OPERAND_UINT1, OPERAND_LVT4}},
/* Make scalar variable at index op2 in call frame cease to exist;
* op1 is 1 for errors on problems, 0 otherwise */
{"unsetArray", 6, -1, 2, {OPERAND_UINT1, OPERAND_LVT4}},
/* Make array element cease to exist; array at slot op2, element is
* stktop; op1 is 1 for errors on problems, 0 otherwise */
{"unsetArrayStk", 2, -2, 1, {OPERAND_UINT1}},
/* Make array element cease to exist; element is stktop, array name is
* stknext; op1 is 1 for errors on problems, 0 otherwise */
{"unsetStk", 2, -1, 1, {OPERAND_UINT1}},
/* Make general variable cease to exist; unparsed variable name is
* stktop; op1 is 1 for errors on problems, 0 otherwise */
{"dictExpand", 1, -1, 0, {OPERAND_NONE}},
/* Probe into a dict and extract it (or a subdict of it) into
* variables with matched names. Produces list of keys bound as
* result. Part of [dict with].
* Stack: ... dict path => ... keyList */
{"dictRecombineStk", 1, -3, 0, {OPERAND_NONE}},
/* Map variable contents back into a dictionary in a variable. Part of
* [dict with].
* Stack: ... dictVarName path keyList => ... */
{"dictRecombineImm", 5, -2, 1, {OPERAND_LVT4}},
/* Map variable contents back into a dictionary in the local variable
* indicated by the LVT index. Part of [dict with].
* Stack: ... path keyList => ... */
{"dictExists", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* The top op4 words (min 1) are a key path into the dictionary just
* below the keys on the stack, and all those values are replaced by a
* boolean indicating whether it is possible to read out a value from
* that key-path (like [dict exists]).
* Stack: ... dict key1 ... keyN => ... boolean */
{"verifyDict", 1, -1, 0, {OPERAND_NONE}},
/* Verifies that the word on the top of the stack is a dictionary,
* popping it if it is and throwing an error if it is not.
* Stack: ... value => ... */
{"strmap", 1, -2, 0, {OPERAND_NONE}},
/* Simplified version of [string map] that only applies one change
* string, and only case-sensitively.
* Stack: ... from to string => ... changedString */
{"strfind", 1, -1, 0, {OPERAND_NONE}},
/* Find the first index of a needle string in a haystack string,
* producing the index (integer) or -1 if nothing found.
* Stack: ... needle haystack => ... index */
{"strrfind", 1, -1, 0, {OPERAND_NONE}},
/* Find the last index of a needle string in a haystack string,
* producing the index (integer) or -1 if nothing found.
* Stack: ... needle haystack => ... index */
{"strrangeImm", 9, 0, 2, {OPERAND_IDX4, OPERAND_IDX4}},
/* String Range: push (string range stktop op4 op4) */
{"strrange", 1, -2, 0, {OPERAND_NONE}},
/* String Range with non-constant arguments.
* Stack: ... string idxA idxB => ... substring */
{"yield", 1, 0, 0, {OPERAND_NONE}},
/* Makes the current coroutine yield the value at the top of the
* stack, and places the response back on top of the stack when it
* resumes.
* Stack: ... valueToYield => ... resumeValue */
{"coroName", 1, +1, 0, {OPERAND_NONE}},
/* Push the name of the interpreter's current coroutine as an object
* on the stack. */
{"tailcall", 2, INT_MIN, 1, {OPERAND_UINT1}},
/* Do a tailcall with the opnd items on the stack as the thing to
* tailcall to; opnd must be greater than 0 for the semantics to work
* right. */
{"currentNamespace", 1, +1, 0, {OPERAND_NONE}},
/* Push the name of the interpreter's current namespace as an object
* on the stack. */
{"infoLevelNumber", 1, +1, 0, {OPERAND_NONE}},
/* Push the stack depth (i.e., [info level]) of the interpreter as an
* object on the stack. */
{"infoLevelArgs", 1, 0, 0, {OPERAND_NONE}},
/* Push the argument words to a stack depth (i.e., [info level <n>])
* of the interpreter as an object on the stack.
* Stack: ... depth => ... argList */
{"resolveCmd", 1, 0, 0, {OPERAND_NONE}},
/* Resolves the command named on the top of the stack to its fully
* qualified version, or produces the empty string if no such command
* exists. Never generates errors.
* Stack: ... cmdName => ... fullCmdName */
{"tclooSelf", 1, +1, 0, {OPERAND_NONE}},
/* Push the identity of the current TclOO object (i.e., the name of
* its current public access command) on the stack. */
{"tclooClass", 1, 0, 0, {OPERAND_NONE}},
/* Push the class of the TclOO object named at the top of the stack
* onto the stack.
* Stack: ... object => ... class */
{"tclooNamespace", 1, 0, 0, {OPERAND_NONE}},
/* Push the namespace of the TclOO object named at the top of the
* stack onto the stack.
* Stack: ... object => ... namespace */
{"tclooIsObject", 1, 0, 0, {OPERAND_NONE}},
/* Push whether the value named at the top of the stack is a TclOO
* object (i.e., a boolean). Can corrupt the interpreter result
* despite not throwing, so not safe for use in a post-exception
* context.
* Stack: ... value => ... boolean */
{"arrayExistsStk", 1, 0, 0, {OPERAND_NONE}},
/* Looks up the element on the top of the stack and tests whether it
* is an array. Pushes a boolean describing whether this is the
* case. Also runs the whole-array trace on the named variable, so can
* throw anything.
* Stack: ... varName => ... boolean */
{"arrayExistsImm", 5, +1, 1, {OPERAND_LVT4}},
/* Looks up the variable indexed by opnd and tests whether it is an
* array. Pushes a boolean describing whether this is the case. Also
* runs the whole-array trace on the named variable, so can throw
* anything.
* Stack: ... => ... boolean */
{"arrayMakeStk", 1, -1, 0, {OPERAND_NONE}},
/* Forces the element on the top of the stack to be the name of an
* array.
* Stack: ... varName => ... */
{"arrayMakeImm", 5, 0, 1, {OPERAND_LVT4}},
/* Forces the variable indexed by opnd to be an array. Does not touch
* the stack. */
{"invokeReplace", 6, INT_MIN, 2, {OPERAND_UINT4,OPERAND_UINT1}},
/* Invoke command named objv[0], replacing the first two words with
* the word at the top of the stack;
* <objc,objv> = <op4,top op4 after popping 1> */
{"listConcat", 1, -1, 0, {OPERAND_NONE}},
/* Concatenates the two lists at the top of the stack into a single
* list and pushes that resulting list onto the stack.
* Stack: ... list1 list2 => ... [lconcat list1 list2] */
{"expandDrop", 1, 0, 0, {OPERAND_NONE}},
/* Drops an element from the auxiliary stack, popping stack elements
* until the matching stack depth is reached. */
/* New foreach implementation */
{"foreach_start", 5, +2, 1, {OPERAND_AUX4}},
/* Initialize execution of a foreach loop. Operand is aux data index
* of the ForeachInfo structure for the foreach command. It pushes 2
* elements which hold runtime params for foreach_step, they are later
* dropped by foreach_end together with the value lists. NOTE that the
* iterator-tracker and info reference must not be passed to bytecodes
* that handle normal Tcl values. NOTE that this instruction jumps to
* the foreach_step instruction paired with it; the stack info below
* is only nominal.
* Stack: ... listObjs... => ... listObjs... iterTracker info */
{"foreach_step", 1, 0, 0, {OPERAND_NONE}},
/* "Step" or begin next iteration of foreach loop. Assigns to foreach
* iteration variables. May jump to straight after the foreach_start
* that pushed the iterTracker and info values. MUST be followed
* immediately by a foreach_end.
* Stack: ... listObjs... iterTracker info =>
* ... listObjs... iterTracker info */
{"foreach_end", 1, 0, 0, {OPERAND_NONE}},
/* Clean up a foreach loop by dropping the info value, the tracker
* value and the lists that were being iterated over.
* Stack: ... listObjs... iterTracker info => ... */
{"lmap_collect", 1, -1, 0, {OPERAND_NONE}},
/* Appends the value at the top of the stack to the list located on
* the stack the "other side" of the foreach-related values.
* Stack: ... collector listObjs... iterTracker info value =>
* ... collector listObjs... iterTracker info */
{"strtrim", 1, -1, 0, {OPERAND_NONE}},
/* [string trim] core: removes the characters (designated by the value
* at the top of the stack) from both ends of the string and pushes
* the resulting string.
* Stack: ... string charset => ... trimmedString */
{"strtrimLeft", 1, -1, 0, {OPERAND_NONE}},
/* [string trimleft] core: removes the characters (designated by the
* value at the top of the stack) from the left of the string and
* pushes the resulting string.
* Stack: ... string charset => ... trimmedString */
{"strtrimRight", 1, -1, 0, {OPERAND_NONE}},
/* [string trimright] core: removes the characters (designated by the
* value at the top of the stack) from the right of the string and
* pushes the resulting string.
* Stack: ... string charset => ... trimmedString */
{"concatStk", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* Wrapper round Tcl_ConcatObj(), used for [concat] and [eval]. opnd
* is number of values to concatenate.
* Operation: push concat(stk1 stk2 ... stktop) */
{"strcaseUpper", 1, 0, 0, {OPERAND_NONE}},
/* [string toupper] core: converts whole string to upper case using
* the default (extended "C" locale) rules.
* Stack: ... string => ... newString */
{"strcaseLower", 1, 0, 0, {OPERAND_NONE}},
/* [string tolower] core: converts whole string to upper case using
* the default (extended "C" locale) rules.
* Stack: ... string => ... newString */
{"strcaseTitle", 1, 0, 0, {OPERAND_NONE}},
/* [string totitle] core: converts whole string to upper case using
* the default (extended "C" locale) rules.
* Stack: ... string => ... newString */
{"strreplace", 1, -3, 0, {OPERAND_NONE}},
/* [string replace] core: replaces a non-empty range of one string
* with the contents of another.
* Stack: ... string fromIdx toIdx replacement => ... newString */
{"originCmd", 1, 0, 0, {OPERAND_NONE}},
/* Reports which command was the origin (via namespace import chain)
* of the command named on the top of the stack.
* Stack: ... cmdName => ... fullOriginalCmdName */
{"tclooNext", 2, INT_MIN, 1, {OPERAND_UINT1}},
/* Call the next item on the TclOO call chain, passing opnd arguments
* (min 1, max 255, *includes* "next"). The result of the invoked
* method implementation will be pushed on the stack in place of the
* arguments (similar to invokeStk).
* Stack: ... "next" arg2 arg3 -- argN => ... result */
{"tclooNextClass", 2, INT_MIN, 1, {OPERAND_UINT1}},
/* Call the following item on the TclOO call chain defined by class
* className, passing opnd arguments (min 2, max 255, *includes*
* "nextto" and the class name). The result of the invoked method
* implementation will be pushed on the stack in place of the
* arguments (similar to invokeStk).
* Stack: ... "nextto" className arg3 arg4 -- argN => ... result */
{"yieldToInvoke", 1, 0, 0, {OPERAND_NONE}},
/* Makes the current coroutine yield the value at the top of the
* stack, invoking the given command/args with resolution in the given
* namespace (all packed into a list), and places the list of values
* that are the response back on top of the stack when it resumes.
* Stack: ... [list ns cmd arg1 ... argN] => ... resumeList */
{"numericType", 1, 0, 0, {OPERAND_NONE}},
/* Pushes the numeric type code of the word at the top of the stack.
* Stack: ... value => ... typeCode */
{"tryCvtToBoolean", 1, +1, 0, {OPERAND_NONE}},
/* Try converting stktop to boolean if possible. No errors.
* Stack: ... value => ... value isStrictBool */
{"strclass", 2, 0, 1, {OPERAND_SCLS1}},
/* See if all the characters of the given string are a member of the
* specified (by opnd) character class. Note that an empty string will
* satisfy the class check (standard definition of "all").
* Stack: ... stringValue => ... boolean */
{"lappendList", 5, 0, 1, {OPERAND_LVT4}},
/* Lappend list to scalar variable at op4 in frame.
* Stack: ... list => ... listVarContents */
{"lappendListArray", 5, -1, 1, {OPERAND_LVT4}},
/* Lappend list to array element; array at op4.
* Stack: ... elem list => ... listVarContents */
{"lappendListArrayStk", 1, -2, 0, {OPERAND_NONE}},
/* Lappend list to array element.
* Stack: ... arrayName elem list => ... listVarContents */
{"lappendListStk", 1, -1, 0, {OPERAND_NONE}},
/* Lappend list to general variable.
* Stack: ... varName list => ... listVarContents */
{"clockRead", 2, +1, 1, {OPERAND_UINT1}},
/* Read clock out to the stack. Operand is which clock to read
* 0=clicks, 1=microseconds, 2=milliseconds, 3=seconds.
* Stack: ... => ... time */
{"dictGetDef", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* The top word is the default, the next op4 words (min 1) are a key
* path into the dictionary just below the keys on the stack, and all
* those values are replaced by the value read out of that key-path
* (like [dict get]) except if there is no such key, when instead the
* default is pushed instead.
* Stack: ... dict key1 ... keyN default => ... value */
{"strlt", 1, -1, 0, {OPERAND_NONE}},
/* String Less: push (stknext < stktop) */
{"strgt", 1, -1, 0, {OPERAND_NONE}},
/* String Greater: push (stknext > stktop) */
{"strle", 1, -1, 0, {OPERAND_NONE}},
/* String Less or equal: push (stknext <= stktop) */
{"strge", 1, -1, 0, {OPERAND_NONE}},
/* String Greater or equal: push (stknext >= stktop) */
{"lreplace4", 6, INT_MIN, 2, {OPERAND_UINT4, OPERAND_UINT1}},
/* Operands: number of arguments, flags
* flags: Combination of TCL_LREPLACE4_* flags
* Stack: ... listobj index1 ?index2? new1 ... newN => ... newlistobj
* where index2 is present only if TCL_LREPLACE_SINGLE_INDEX is not
* set in flags.
*/
{"constImm", 5, -1, 1, {OPERAND_LVT4}},
/* Create constant. Index into LVT is immediate, value is on stack.
* Stack: ... value => ... */
{"constStk", 1, -2, 0, {OPERAND_NONE}},
/* Create constant. Variable name and value on stack.
* Stack: ... varName value => ... */
{NULL, 0, 0, 0, {OPERAND_NONE}}
};
/*
* Prototypes for procedures defined later in this file:
*/
static void CleanupByteCode(ByteCode *codePtr);
static ByteCode * CompileSubstObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
int flags);
static void DupByteCodeInternalRep(Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr);
static unsigned char * EncodeCmdLocMap(CompileEnv *envPtr,
ByteCode *codePtr, unsigned char *startPtr);
static void EnterCmdExtentData(CompileEnv *envPtr,
Tcl_Size cmdNumber, Tcl_Size numSrcBytes, Tcl_Size numCodeBytes);
static void EnterCmdStartData(CompileEnv *envPtr,
Tcl_Size cmdNumber, Tcl_Size srcOffset, Tcl_Size codeOffset);
static void FreeByteCodeInternalRep(Tcl_Obj *objPtr);
static void FreeSubstCodeInternalRep(Tcl_Obj *objPtr);
static int GetCmdLocEncodingSize(CompileEnv *envPtr);
static int IsCompactibleCompileEnv(CompileEnv *envPtr);
static void PreventCycle(Tcl_Obj *objPtr, CompileEnv *envPtr);
#ifdef TCL_COMPILE_STATS
static void RecordByteCodeStats(ByteCode *codePtr);
#endif /* TCL_COMPILE_STATS */
static int SetByteCodeFromAny(Tcl_Interp *interp,
Tcl_Obj *objPtr);
static void StartExpanding(CompileEnv *envPtr);
/*
* TIP #280: Helper for building the per-word line information of all compiled
* commands.
*/
static void EnterCmdWordData(ExtCmdLoc *eclPtr, Tcl_Size srcOffset,
Tcl_Token *tokenPtr, const char *cmd,
Tcl_Size numWords, Tcl_Size line,
Tcl_Size *clNext, Tcl_Size **lines,
CompileEnv *envPtr);
static void ReleaseCmdWordData(ExtCmdLoc *eclPtr);
/*
* tclByteCodeType provides the standard type management procedures for the
* bytecode type.
*/
const Tcl_ObjType tclByteCodeType = {
"bytecode", /* name */
FreeByteCodeInternalRep, /* freeIntRepProc */
DupByteCodeInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
SetByteCodeFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
/*
* substCodeType provides the standard type management procedures for the
* substcode type, which represents substitution within a Tcl value.
*/
static const Tcl_ObjType substCodeType = {
"substcode", /* name */
FreeSubstCodeInternalRep, /* freeIntRepProc */
DupByteCodeInternalRep, /* dupIntRepProc - shared with bytecode */
NULL, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define SubstFlags(objPtr) (objPtr)->internalRep.twoPtrValue.ptr2
/*
* Helper macros.
*/
|
| ︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 |
int
TclSetByteCodeFromAny(
Tcl_Interp *interp, /* The interpreter for which the code is being
* compiled. Must not be NULL. */
Tcl_Obj *objPtr, /* The object to make a ByteCode object. */
CompileHookProc *hookProc, /* Procedure to invoke after compilation. */
| | | < | | | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
int
TclSetByteCodeFromAny(
Tcl_Interp *interp, /* The interpreter for which the code is being
* compiled. Must not be NULL. */
Tcl_Obj *objPtr, /* The object to make a ByteCode object. */
CompileHookProc *hookProc, /* Procedure to invoke after compilation. */
void *clientData) /* Hook procedure private data. */
{
Interp *iPtr = (Interp *) interp;
CompileEnv compEnv; /* Compilation environment structure allocated
* in frame. */
Tcl_Size length;
int result = TCL_OK;
const char *stringPtr;
Proc *procPtr = iPtr->compiledProcPtr;
ContLineLoc *clLocPtr;
#ifdef TCL_COMPILE_DEBUG
if (!traceInitialized) {
if (Tcl_LinkVar(interp, "tcl_traceCompile",
&tclTraceCompile, TCL_LINK_INT) != TCL_OK) {
Tcl_Panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
}
traceInitialized = 1;
}
#endif
stringPtr = TclGetStringFromObj(objPtr, &length);
/*
* TIP #280: Pick up the CmdFrame in which the BC compiler was invoked, and
* use to initialize the tracking in the compiler. This information was
* stored by TclCompEvalObj and ProcCompileProc.
*/
TclInitCompileEnv(interp, &compEnv, stringPtr, length,
iPtr->invokeCmdFramePtr, iPtr->invokeWord);
/*
* Make available to the compilation environment any data about invisible
* continuation lines for the script.
*
* It is not clear if the script Tcl_Obj* can be free'd while the compiler
* is using it, leading to the release of the associated ContLineLoc
* structure as well. To ensure that the latter doesn't happen set a lock
* on it, which is released in TclFreeCompileEnv(). The "lineCLPtr"
* hashtable tclObj.c.
*/
clLocPtr = TclContinuationsGet(objPtr);
if (clLocPtr) {
compEnv.clNext = &clLocPtr->loc[0];
}
TclCompileScript(interp, stringPtr, length, &compEnv);
/*
* Compilation succeeded. Add a "done" instruction at the end.
*/
TclEmitOpcode(INST_DONE, &compEnv);
/*
* Check for optimizations!
*
* If the generated code is free of most hazards, recompile with generation
* of INST_START_CMD disabled to produce code that more compact in many
* cases, and also sometimes more performant.
|
| ︙ | ︙ | |||
1176 1177 1178 1179 1180 1181 1182 |
iPtr->invokeCmdFramePtr, iPtr->invokeWord);
if (clLocPtr) {
compEnv.clNext = &clLocPtr->loc[0];
}
compEnv.atCmdStart = 2; /* The disabling magic. */
TclCompileScript(interp, stringPtr, length, &compEnv);
assert (compEnv.atCmdStart > 1);
| | | 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 |
iPtr->invokeCmdFramePtr, iPtr->invokeWord);
if (clLocPtr) {
compEnv.clNext = &clLocPtr->loc[0];
}
compEnv.atCmdStart = 2; /* The disabling magic. */
TclCompileScript(interp, stringPtr, length, &compEnv);
assert (compEnv.atCmdStart > 1);
TclEmitOpcode(INST_DONE, &compEnv);
assert (compEnv.atCmdStart > 1);
}
/*
* Apply some peephole optimizations that can cross specific/generic
* instruction generator boundaries.
*/
|
| ︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 |
result = hookProc(interp, &compEnv, clientData);
}
/*
* After optimization is all done, check that byte code length limits
* are not exceeded. Bug [27b3ce2997].
*/
| | | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 |
result = hookProc(interp, &compEnv, clientData);
}
/*
* After optimization is all done, check that byte code length limits
* are not exceeded. Bug [27b3ce2997].
*/
if ((compEnv.codeNext - compEnv.codeStart) > INT_MAX) {
/*
* Cannot just return TCL_ERROR as callers ignore return value.
* TODO - May be use TclCompileSyntaxError here?
*/
Tcl_Panic("Maximum byte code length %d exceeded.", INT_MAX);
}
|
| ︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 | * delayed until the last execution of the code completes. * *---------------------------------------------------------------------- */ static void FreeByteCodeInternalRep( | | | 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 |
* delayed until the last execution of the code completes.
*
*----------------------------------------------------------------------
*/
static void
FreeByteCodeInternalRep(
Tcl_Obj *objPtr) /* Object whose internal rep to free. */
{
ByteCode *codePtr;
ByteCodeGetInternalRep(objPtr, &tclByteCodeType, codePtr);
assert(codePtr != NULL);
TclReleaseByteCode(codePtr);
|
| ︙ | ︙ | |||
1361 1362 1363 1364 1365 1366 1367 |
/* Just dropped to refcount==0. Clean up. */
CleanupByteCode(codePtr);
}
static void
CleanupByteCode(
| | > > > > > > | | 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 |
/* Just dropped to refcount==0. Clean up. */
CleanupByteCode(codePtr);
}
static void
CleanupByteCode(
ByteCode *codePtr) /* Points to the ByteCode to free. */
{
Tcl_Interp *interp = (Tcl_Interp *) *codePtr->interpHandle;
Interp *iPtr = (Interp *) interp;
Tcl_Size numLitObjects = codePtr->numLitObjects;
Tcl_Size numAuxDataItems = codePtr->numAuxDataItems;
Tcl_Obj **objArrayPtr, *objPtr;
const AuxData *auxDataPtr;
int i;
#ifdef TCL_COMPILE_STATS
if (interp != NULL) {
ByteCodeStats *statsPtr;
Tcl_Time destroyTime;
long long lifetimeSec, lifetimeMicroSec;
statsPtr = &iPtr->stats;
statsPtr->numByteCodesFreed++;
statsPtr->currentSrcBytes -= (double)codePtr->numSrcBytes;
statsPtr->currentByteCodeBytes -= (double) codePtr->structureSize;
statsPtr->currentInstBytes -= (double) codePtr->numCodeBytes;
statsPtr->currentLitBytes -= (double)
numLitObjects * sizeof(Tcl_Obj *);
statsPtr->currentExceptBytes -= (double)
codePtr->numExceptRanges * sizeof(ExceptionRange);
statsPtr->currentAuxBytes -= (double)
codePtr->numAuxDataItems * sizeof(AuxData);
statsPtr->currentCmdMapBytes -= (double) codePtr->numCmdLocBytes;
Tcl_GetTime(&destroyTime);
lifetimeSec = destroyTime.sec - codePtr->createTime.sec;
lifetimeMicroSec = 1000000 * lifetimeSec +
(destroyTime.usec - codePtr->createTime.usec);
statsPtr->lifetimeCount[TclLog2(lifetimeMicroSec)]++;
}
#endif /* TCL_COMPILE_STATS */
/*
* A single heap object holds the ByteCode structure and its code, object,
* command location, and auxiliary data arrays. This means we only need to
* 1) decrement the ref counts of each LiteralEntry in the literal array,
|
| ︙ | ︙ | |||
1492 1493 1494 1495 1496 1497 1498 |
/*
* Special: procedures in the '::tcl' namespace (or its children) are
* considered to be well-behaved, so compaction can be applied to them even
* if it would otherwise be invalid.
*/
| > | | | | | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 |
/*
* Special: procedures in the '::tcl' namespace (or its children) are
* considered to be well-behaved, so compaction can be applied to them even
* if it would otherwise be invalid.
*/
if (envPtr->procPtr != NULL && envPtr->procPtr->cmdPtr != NULL
&& envPtr->procPtr->cmdPtr->nsPtr != NULL) {
Namespace *nsPtr = envPtr->procPtr->cmdPtr->nsPtr;
if (strcmp(nsPtr->fullName, "::tcl") == 0
|| strncmp(nsPtr->fullName, "::tcl::", 7) == 0) {
return 1;
}
}
/*
* Go through and ensure that no operation involved can cause a desired
* change of bytecode sequence during its execution. This comes down to
* ensuring that there are no mapped variables (due to traces) or calls to
* external commands (traces, [uplevel] trickery). This is actually a very
* conservative check. It turns down a lot of code that is OK in practice.
*/
for (pc = envPtr->codeStart ; pc < envPtr->codeNext ; pc += size) {
switch (*pc) {
/* Invokes */
case INST_INVOKE_STK1:
case INST_INVOKE_STK4:
case INST_INVOKE_EXPANDED:
case INST_INVOKE_REPLACE:
return 0;
/* Runtime evals */
case INST_EVAL_STK:
case INST_EXPR_STK:
case INST_YIELD:
|
| ︙ | ︙ | |||
1552 1553 1554 1555 1556 1557 1558 | * * Tcl_SubstObj -- * * Performs substitutions on the given string as described in the user * documentation for "subst". * * Results: | | | 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 | * * Tcl_SubstObj -- * * Performs substitutions on the given string as described in the user * documentation for "subst". * * Results: * A Tcl_Obj* containing the substituted string, or NULL to indicate that * an error occurred. * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
1662 1663 1664 1665 1666 1667 1668 | const char *bytes = TclGetStringFromObj(objPtr, &numBytes); /* TODO: Check for more TIP 280 */ TclInitCompileEnv(interp, &compEnv, bytes, numBytes, NULL, 0); TclSubstCompile(interp, bytes, numBytes, flags, 1, &compEnv); | | | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 |
const char *bytes = TclGetStringFromObj(objPtr, &numBytes);
/* TODO: Check for more TIP 280 */
TclInitCompileEnv(interp, &compEnv, bytes, numBytes, NULL, 0);
TclSubstCompile(interp, bytes, numBytes, flags, 1, &compEnv);
TclEmitOpcode(INST_DONE, &compEnv);
codePtr = TclInitByteCodeObj(objPtr, &substCodeType, &compEnv);
TclFreeCompileEnv(&compEnv);
SubstFlags(objPtr) = INT2PTR(flags);
if (iPtr->varFramePtr->localCachePtr) {
codePtr->localCachePtr = iPtr->varFramePtr->localCachePtr;
codePtr->localCachePtr->refCount++;
|
| ︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 | * the cleanup is delayed until the last execution of the code completes. * *---------------------------------------------------------------------- */ static void FreeSubstCodeInternalRep( | | | 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 |
* the cleanup is delayed until the last execution of the code completes.
*
*----------------------------------------------------------------------
*/
static void
FreeSubstCodeInternalRep(
Tcl_Obj *objPtr) /* Object whose internal rep to free. */
{
ByteCode *codePtr;
ByteCodeGetInternalRep(objPtr, &substCodeType, codePtr);
assert(codePtr != NULL);
TclReleaseByteCode(codePtr);
|
| ︙ | ︙ | |||
1749 1750 1751 1752 1753 1754 1755 |
*----------------------------------------------------------------------
*/
void
TclInitCompileEnv(
Tcl_Interp *interp, /* The interpreter for which a CompileEnv
* structure is initialized. */
| | | | 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 |
*----------------------------------------------------------------------
*/
void
TclInitCompileEnv(
Tcl_Interp *interp, /* The interpreter for which a CompileEnv
* structure is initialized. */
CompileEnv *envPtr,/* Points to the CompileEnv structure to
* initialize. */
const char *stringPtr, /* The source string to be compiled. */
size_t numBytes, /* Number of bytes in source string. */
const CmdFrame *invoker, /* Location context invoking the bcc */
int word) /* Index of the word in that context getting
* compiled */
{
Interp *iPtr = (Interp *) interp;
assert(tclInstructionTable[LAST_INST_OPCODE].name == NULL);
envPtr->iPtr = iPtr;
|
| ︙ | ︙ | |||
1776 1777 1778 1779 1780 1781 1782 |
envPtr->maxStackDepth = 0;
envPtr->currStackDepth = 0;
TclInitLiteralTable(&envPtr->localLitTable);
envPtr->codeStart = envPtr->staticCodeSpace;
envPtr->codeNext = envPtr->codeStart;
envPtr->codeEnd = envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES;
| | | | | 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 |
envPtr->maxStackDepth = 0;
envPtr->currStackDepth = 0;
TclInitLiteralTable(&envPtr->localLitTable);
envPtr->codeStart = envPtr->staticCodeSpace;
envPtr->codeNext = envPtr->codeStart;
envPtr->codeEnd = envPtr->codeStart + COMPILEENV_INIT_CODE_BYTES;
envPtr->mallocedCodeArray = 0;
envPtr->literalArrayPtr = envPtr->staticLiteralSpace;
envPtr->literalArrayNext = 0;
envPtr->literalArrayEnd = COMPILEENV_INIT_NUM_OBJECTS;
envPtr->mallocedLiteralArray = 0;
envPtr->exceptArrayPtr = envPtr->staticExceptArraySpace;
envPtr->exceptAuxArrayPtr = envPtr->staticExAuxArraySpace;
envPtr->exceptArrayNext = 0;
envPtr->exceptArrayEnd = COMPILEENV_INIT_EXCEPT_RANGES;
envPtr->mallocedExceptArray = 0;
envPtr->cmdMapPtr = envPtr->staticCmdMapSpace;
envPtr->cmdMapEnd = COMPILEENV_INIT_CMD_MAP_SIZE;
envPtr->mallocedCmdMap = 0;
envPtr->atCmdStart = 1;
envPtr->expandCount = 0;
/*
* TIP #280: Set up the extended command location information, based on
* the context invoking the byte code compiler. This structure is used to
* keep the per-word line information for all compiled commands.
|
| ︙ | ︙ | |||
1850 1851 1852 1853 1854 1855 1856 |
} else {
TclNewLiteralStringObj(envPtr->extCmdMapPtr->path, "");
}
Tcl_IncrRefCount(envPtr->extCmdMapPtr->path);
} else {
envPtr->extCmdMapPtr->type =
| | | 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 |
} else {
TclNewLiteralStringObj(envPtr->extCmdMapPtr->path, "");
}
Tcl_IncrRefCount(envPtr->extCmdMapPtr->path);
} else {
envPtr->extCmdMapPtr->type =
(envPtr->procPtr ? TCL_LOCATION_PROC : TCL_LOCATION_BC);
}
} else {
/*
* Initialize the compiler using the context, making counting absolute
* to that context. Note that the context can be byte code execution.
* In that case we have to fill out the missing pieces (line, path,
* ...) which may make change the type as well.
|
| ︙ | ︙ | |||
1881 1882 1883 1884 1885 1886 1887 |
if ((ctxPtr->nline <= word) || (ctxPtr->line[word] < 0)) {
/*
* Word is not a literal, relative counting.
*/
envPtr->line = 1;
envPtr->extCmdMapPtr->type =
| | | 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 |
if ((ctxPtr->nline <= word) || (ctxPtr->line[word] < 0)) {
/*
* Word is not a literal, relative counting.
*/
envPtr->line = 1;
envPtr->extCmdMapPtr->type =
(envPtr->procPtr ? TCL_LOCATION_PROC : TCL_LOCATION_BC);
if (pc && (ctxPtr->type == TCL_LOCATION_SOURCE)) {
/*
* The reference made by 'TclGetSrcInfoForPc' is dead.
*/
Tcl_DecrRefCount(ctxPtr->data.eval.path);
|
| ︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 |
*/
envPtr->clNext = NULL;
envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;
envPtr->auxDataArrayNext = 0;
envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;
| | | 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 |
*/
envPtr->clNext = NULL;
envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace;
envPtr->auxDataArrayNext = 0;
envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE;
envPtr->mallocedAuxDataArray = 0;
}
/*
*----------------------------------------------------------------------
*
* TclFreeCompileEnv --
*
|
| ︙ | ︙ | |||
2030 2031 2032 2033 2034 2035 2036 | * instructions that perform that substitution. For several commands, * whether or not arguments are known at compile time determine whether * it is worthwhile to compile at all. * * Side effects: * When returning true, appends the known value of the word to the * unshared Tcl_Obj (*valuePtr), unless valuePtr is NULL. | < | | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 |
* instructions that perform that substitution. For several commands,
* whether or not arguments are known at compile time determine whether
* it is worthwhile to compile at all.
*
* Side effects:
* When returning true, appends the known value of the word to the
* unshared Tcl_Obj (*valuePtr), unless valuePtr is NULL.
*
*----------------------------------------------------------------------
*/
int
TclWordKnownAtCompileTime(
Tcl_Token *tokenPtr, /* Points to Tcl_Token we should check */
Tcl_Obj *valuePtr) /* If not NULL, points to an unshared Tcl_Obj
* to which we should append the known value
* of the word. */
{
int numComponents = tokenPtr->numComponents;
Tcl_Obj *tempPtr = NULL;
if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
if (valuePtr != NULL) {
Tcl_AppendToObj(valuePtr, tokenPtr[1].start, tokenPtr[1].size);
}
return 1;
|
| ︙ | ︙ | |||
2113 2114 2115 2116 2117 2118 2119 |
*
*----------------------------------------------------------------------
*/
static int
ExpandRequested(
Tcl_Token *tokenPtr,
| | > > > > | > | | > > | > > > > | | | > | | > > | | | > | | | | 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 |
*
*----------------------------------------------------------------------
*/
static int
ExpandRequested(
Tcl_Token *tokenPtr,
size_t numWords)
{
/* Determine whether any words of the command require expansion */
while (numWords--) {
if (tokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
return 1;
}
tokenPtr = TokenAfter(tokenPtr);
}
return 0;
}
static void
CompileCmdLiteral(
Tcl_Interp *interp,
Tcl_Obj *cmdObj,
CompileEnv *envPtr)
{
const char *bytes;
Command *cmdPtr;
int cmdLitIdx, extraLiteralFlags = LITERAL_CMD_NAME;
Tcl_Size length;
cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, cmdObj);
if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_VIA_RESOLVER)) {
extraLiteralFlags |= LITERAL_UNSHARED;
}
bytes = TclGetStringFromObj(cmdObj, &length);
cmdLitIdx = TclRegisterLiteral(envPtr, bytes, length, extraLiteralFlags);
if (cmdPtr && TclRoutineHasName(cmdPtr)) {
TclSetCmdNameObj(interp, TclFetchLiteral(envPtr, cmdLitIdx), cmdPtr);
}
TclEmitPush(cmdLitIdx, envPtr);
}
void
TclCompileInvocation(
Tcl_Interp *interp,
Tcl_Token *tokenPtr,
Tcl_Obj *cmdObj,
size_t numWords,
CompileEnv *envPtr)
{
DefineLineInformation;
size_t wordIdx = 0;
int depth = TclGetStackDepth(envPtr);
if (cmdObj) {
CompileCmdLiteral(interp, cmdObj, envPtr);
wordIdx = 1;
tokenPtr = TokenAfter(tokenPtr);
}
for (; wordIdx < numWords; wordIdx++, tokenPtr = TokenAfter(tokenPtr)) {
int objIdx;
SetLineInformation(wordIdx);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
CompileTokens(envPtr, tokenPtr, interp);
continue;
}
objIdx = TclRegisterLiteral(envPtr,
tokenPtr[1].start, tokenPtr[1].size, 0);
if (envPtr->clNext) {
TclContinuationsEnterDerived(TclFetchLiteral(envPtr, objIdx),
tokenPtr[1].start - envPtr->source, envPtr->clNext);
}
TclEmitPush(objIdx, envPtr);
}
if (wordIdx <= 255) {
TclEmitInvoke(envPtr, INST_INVOKE_STK1, wordIdx);
} else {
TclEmitInvoke(envPtr, INST_INVOKE_STK4, wordIdx);
}
TclCheckStackDepth(depth+1, envPtr);
}
static void
CompileExpanded(
Tcl_Interp *interp,
Tcl_Token *tokenPtr,
Tcl_Obj *cmdObj,
int numWords,
CompileEnv *envPtr)
{
DefineLineInformation;
int wordIdx = 0;
int depth = TclGetStackDepth(envPtr);
StartExpanding(envPtr);
if (cmdObj) {
CompileCmdLiteral(interp, cmdObj, envPtr);
wordIdx = 1;
tokenPtr = TokenAfter(tokenPtr);
}
for (; wordIdx < numWords; wordIdx++, tokenPtr = TokenAfter(tokenPtr)) {
int objIdx;
SetLineInformation(wordIdx);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
CompileTokens(envPtr, tokenPtr, interp);
if (tokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
TclEmitInstInt4(INST_EXPAND_STKTOP,
envPtr->currStackDepth, envPtr);
}
continue;
}
objIdx = TclRegisterLiteral(envPtr,
tokenPtr[1].start, tokenPtr[1].size, 0);
if (envPtr->clNext) {
TclContinuationsEnterDerived(TclFetchLiteral(envPtr, objIdx),
tokenPtr[1].start - envPtr->source, envPtr->clNext);
}
TclEmitPush(objIdx, envPtr);
}
/*
* The stack depth during argument expansion can only be managed at
* runtime, as the number of elements in the expanded lists is not known
* at compile time. Adjust the stack depth estimate here so that it is
* correct after the command with expanded arguments returns.
*
* The end effect of this command's invocation is that all the words of
* the command are popped from the stack and the result is pushed: The
* stack top changes by (1-wordIdx).
*
* The estimates are not correct while the command is being
* prepared and run, INST_EXPAND_STKTOP is not stack-neutral in general.
*/
TclEmitInvoke(envPtr, INST_INVOKE_EXPANDED, wordIdx);
TclCheckStackDepth(depth+1, envPtr);
}
static int
CompileCmdCompileProc(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
Command *cmdPtr,
CompileEnv *envPtr)
{
DefineLineInformation;
int unwind = 0;
Tcl_Size incrOffset = -1;
int depth = TclGetStackDepth(envPtr);
/*
* Emission of the INST_START_CMD instruction is controlled by the value of
* envPtr->atCmdStart:
*
* atCmdStart == 2 : Don't use the INST_START_CMD instruction.
* atCmdStart == 1 : INST_START_CMD was the last instruction emitted,
* : so no need to emit another. Instead
* : increment the number of cmds started at it, except
* : for the special case at the start of a script.
* atCmdStart == 0 : The last instruction was something else.
* : Emit INST_START_CMD here.
*/
switch (envPtr->atCmdStart) {
case 0:
unwind = tclInstructionTable[INST_START_CMD].numBytes;
TclEmitInstInt4(INST_START_CMD, 0, envPtr);
incrOffset = envPtr->codeNext - envPtr->codeStart;
TclEmitInt4(0, envPtr);
break;
case 1:
if (envPtr->codeNext > envPtr->codeStart) {
incrOffset = envPtr->codeNext - 4 - envPtr->codeStart;
}
break;
case 2:
/* Nothing to do */
;
}
|
| ︙ | ︙ | |||
2306 2307 2308 2309 2310 2311 2312 |
return TCL_OK;
}
envPtr->codeNext -= unwind; /* Unwind INST_START_CMD */
/*
* Throw out any line information generated by the failed compile attempt.
| < < < < < < < < < < < < < < < | | | | | > | | | | < | | | | | | | > | 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 |
return TCL_OK;
}
envPtr->codeNext -= unwind; /* Unwind INST_START_CMD */
/*
* Throw out any line information generated by the failed compile attempt.
*/
while (mapPtr->nuloc - 1 > eclIndex) {
mapPtr->nuloc--;
Tcl_Free(mapPtr->loc[mapPtr->nuloc].line);
mapPtr->loc[mapPtr->nuloc].line = NULL;
}
/*
* Reset the index of next command. Toss out any from failed nested
* partial compiles.
*/
envPtr->numCommands = mapPtr->nuloc;
return TCL_ERROR;
}
static int
CompileCommandTokens(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
CompileEnv *envPtr)
{
Interp *iPtr = (Interp *) interp;
Tcl_Token *tokenPtr = parsePtr->tokenPtr;
ExtCmdLoc *eclPtr = envPtr->extCmdMapPtr;
Tcl_Obj *cmdObj;
Command *cmdPtr = NULL;
int code = TCL_ERROR;
int cmdKnown, expand = -1;
Tcl_Size *wlines, wlineat;
Tcl_Size cmdLine = envPtr->line;
Tcl_Size *clNext = envPtr->clNext;
Tcl_Size cmdIdx = envPtr->numCommands;
Tcl_Size startCodeOffset = envPtr->codeNext - envPtr->codeStart;
int depth = TclGetStackDepth(envPtr);
assert ((int)parsePtr->numWords > 0);
/* Precompile */
TclNewObj(cmdObj);
envPtr->numCommands++;
EnterCmdStartData(envPtr, cmdIdx,
parsePtr->commandStart - envPtr->source, startCodeOffset);
/*
* TIP #280. Scan the words and compute the extended location information.
* At first the map first contains full per-word line information for use by the
* compiler. This is later replaced by a reduced form which signals
* non-literal words, stored in 'wlines'.
*/
EnterCmdWordData(eclPtr, parsePtr->commandStart - envPtr->source,
parsePtr->tokenPtr, parsePtr->commandStart,
parsePtr->numWords, cmdLine,
clNext, &wlines, envPtr);
wlineat = eclPtr->nuloc - 1;
envPtr->line = eclPtr->loc[wlineat].line[0];
envPtr->clNext = eclPtr->loc[wlineat].next[0];
/* Do we know the command word? */
|
| ︙ | ︙ | |||
2402 2403 2404 2405 2406 2407 2408 |
if ((cmdPtr->compileProc == NULL)
|| (cmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION)
|| (cmdPtr->flags & CMD_HAS_EXEC_TRACES)) {
cmdPtr = NULL;
}
}
if (cmdPtr && !(cmdPtr->flags & CMD_COMPILES_EXPANDED)) {
| | < < < < < | | | | | | 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 |
if ((cmdPtr->compileProc == NULL)
|| (cmdPtr->nsPtr->flags & NS_SUPPRESS_COMPILATION)
|| (cmdPtr->flags & CMD_HAS_EXEC_TRACES)) {
cmdPtr = NULL;
}
}
if (cmdPtr && !(cmdPtr->flags & CMD_COMPILES_EXPANDED)) {
expand = ExpandRequested(parsePtr->tokenPtr, (int)parsePtr->numWords);
if (expand) {
/* We need to expand, but compileProc cannot. */
cmdPtr = NULL;
}
}
}
/* If cmdPtr != NULL, try to call cmdPtr->compileProc */
if (cmdPtr) {
code = CompileCmdCompileProc(interp, parsePtr, cmdPtr, envPtr);
}
if (code == TCL_ERROR) {
if (expand < 0) {
expand = ExpandRequested(parsePtr->tokenPtr, (int)parsePtr->numWords);
}
if (expand) {
CompileExpanded(interp, parsePtr->tokenPtr,
cmdKnown ? cmdObj : NULL, (int)parsePtr->numWords, envPtr);
} else {
TclCompileInvocation(interp, parsePtr->tokenPtr,
cmdKnown ? cmdObj : NULL, (int)parsePtr->numWords, envPtr);
}
}
Tcl_DecrRefCount(cmdObj);
TclEmitOpcode(INST_POP, envPtr);
EnterCmdExtentData(envPtr, cmdIdx,
parsePtr->term - parsePtr->commandStart,
(envPtr->codeNext-envPtr->codeStart) - startCodeOffset);
/*
* TIP #280: Free the full form of per-word line data and insert the
* reduced form now.
*/
envPtr->line = cmdLine;
|
| ︙ | ︙ | |||
2468 2469 2470 2471 2472 2473 2474 |
* commands. May not be NULL. */
const char *script, /* The source script to compile. */
Tcl_Size numBytes, /* Number of bytes in script. If < 0, the
* script consists of all bytes up to the
* first null character. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
| < | | | < | | < | | 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 |
* commands. May not be NULL. */
const char *script, /* The source script to compile. */
Tcl_Size numBytes, /* Number of bytes in script. If < 0, the
* script consists of all bytes up to the
* first null character. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
int lastCmdIdx = -1; /* Index into envPtr->cmdMapPtr of the last
* command this routine compiles into bytecode.
* Initial value of -1 indicates this routine
* has not yet generated any bytecode. */
const char *p = script; /* Where we are in our compile. */
int depth = TclGetStackDepth(envPtr);
Interp *iPtr = (Interp *) interp;
if (envPtr->iPtr == NULL) {
Tcl_Panic("TclCompileScript() called on uninitialized CompileEnv");
}
/*
* Check depth to avoid overflow of the C execution stack by too many
* nested calls of TclCompileScript, considering interp recursionlimit.
* Use factor 5/4 (1.25) to avoid being too mistaken when recognizing the
* limit during "mixed" evaluation and compilation process (nested
* eval+compile) and is good enough for default recursionlimit (1000).
*/
if (iPtr->numLevels / 5 > iPtr->maxNestingDepth / 4) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"too many nested compilations (infinite loop?)", -1));
Tcl_SetErrorCode(interp, "TCL", "LIMIT", "STACK", (char *)NULL);
TclCompileSyntaxError(interp, envPtr);
return;
}
if (numBytes < 0) {
numBytes = strlen(script);
}
/* Each iteration compiles one command from the script. */
if (numBytes > 0) {
if (numBytes >= INT_MAX) {
/*
* Note this gets -errorline as 1. Not worth figuring out which line
* crosses the limit to get -errorline for this error case.
*/
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Script length %" TCL_SIZE_MODIFIER
"d exceeds max permitted length %d.",
numBytes, INT_MAX-1));
Tcl_SetErrorCode(interp, "TCL", "LIMIT", "SCRIPTLENGTH", (char *)NULL);
TclCompileSyntaxError(interp, envPtr);
return;
}
/*
* Don't use system stack (size of Tcl_Parse is ca. 400 bytes), so
* many nested compilations (body enclosed in body) can cause abnormal
|
| ︙ | ︙ | |||
2545 2546 2547 2548 2549 2550 2551 | #ifdef TCL_COMPILE_DEBUG /* * If tracing, print a line for each top level command compiled. * TODO: Suppress when numWords == 0 ? */ | | < | 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 |
#ifdef TCL_COMPILE_DEBUG
/*
* If tracing, print a line for each top level command compiled.
* TODO: Suppress when numWords == 0 ?
*/
if ((tclTraceCompile >= 1) && (envPtr->procPtr == NULL)) {
int commandLength = parsePtr->term - parsePtr->commandStart;
fprintf(stdout, " Compiling: ");
TclPrintSource(stdout, parsePtr->commandStart,
TclMin(commandLength, 55));
fprintf(stdout, "\n");
}
#endif
|
| ︙ | ︙ | |||
2586 2587 2588 2589 2590 2591 2592 | * either the end of script, or a command-terminating semi-colon. * In either case, the TclAdvance*() calls have nothing to do. * Finally, when no words are parsed, no tokens have been * allocated at parsePtr->tokenPtr so there's also nothing for * Tcl_FreeParse() to do. * * The advantage of this shortcut is that CompileCommandTokens() | | | 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 | * either the end of script, or a command-terminating semi-colon. * In either case, the TclAdvance*() calls have nothing to do. * Finally, when no words are parsed, no tokens have been * allocated at parsePtr->tokenPtr so there's also nothing for * Tcl_FreeParse() to do. * * The advantage of this shortcut is that CompileCommandTokens() * can be written with an assumption that (int)parsePtr->numWords > 0, with * the implication the CCT() always generates bytecode. */ continue; } /* * Avoid stack exhaustion by too many nested calls of TclCompileScript |
| ︙ | ︙ | |||
2615 2616 2617 2618 2619 2620 2621 |
p - envPtr->source);
Tcl_FreeParse(parsePtr);
} while (numBytes > 0);
Tcl_Free(parsePtr);
}
| | | | 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 |
p - envPtr->source);
Tcl_FreeParse(parsePtr);
} while (numBytes > 0);
Tcl_Free(parsePtr);
}
if (lastCmdIdx == -1) {
/*
* Compiling the script yielded no bytecode. The script must be all
* whitespace, comments, and empty commands. Such scripts are defined
* to successfully produce the empty string result, so we emit the
* simple bytecode that makes that happen.
*/
PushStringLiteral(envPtr, "");
} else {
/*
* We compiled at least one command to bytecode. The routine
* CompileCommandTokens() follows the bytecode of each compiled
* command with an INST_POP, so that stack balance is maintained when
* several commands are in sequence. (The result of each command is
* thrown away before moving on to the next command). For the last
|
| ︙ | ︙ | |||
2700 2701 2702 2703 2704 2705 2706 |
}
/*
* Either push the variable's name, or find its index in the array
* of local variables in a procedure frame.
*/
| | | | > > | | > > | | | | 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 |
}
/*
* Either push the variable's name, or find its index in the array
* of local variables in a procedure frame.
*/
localVar = -1;
if (localVarName != -1) {
localVar = TclFindCompiledLocal(name, nameBytes, localVarName, envPtr);
}
if (localVar < 0) {
PushLiteral(envPtr, name, nameBytes);
}
/*
* Emit instructions to load the variable.
*/
TclAdvanceLines(&envPtr->line, tokenPtr[1].start,
tokenPtr[1].start + tokenPtr[1].size);
if (tokenPtr->numComponents == 1) {
if (localVar < 0) {
TclEmitOpcode(INST_LOAD_STK, envPtr);
} else if (localVar <= 255) {
TclEmitInstInt1(INST_LOAD_SCALAR1, localVar, envPtr);
} else {
TclEmitInstInt4(INST_LOAD_SCALAR4, localVar, envPtr);
}
} else {
TclCompileTokens(interp, tokenPtr+2, tokenPtr->numComponents-1, envPtr);
if (localVar < 0) {
TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
} else if (localVar <= 255) {
TclEmitInstInt1(INST_LOAD_ARRAY1, localVar, envPtr);
} else {
TclEmitInstInt4(INST_LOAD_ARRAY4, localVar, envPtr);
}
}
}
void
TclCompileTokens(
Tcl_Interp *interp, /* Used for error and status reporting. */
Tcl_Token *tokenPtr, /* Pointer to first in an array of tokens to
* compile. */
Tcl_Size count, /* Number of tokens to consider at tokenPtr.
* Must be at least 1. */
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
Tcl_DString textBuffer; /* Holds concatenated chars from adjacent
* TCL_TOKEN_TEXT, TCL_TOKEN_BS tokens. */
char buffer[4] = "";
Tcl_Size i, numObjsToConcat, adjust;
int length;
unsigned char *entryCodeNext = envPtr->codeNext;
#define NUM_STATIC_POS 20
int isLiteral;
Tcl_Size maxNumCL, numCL;
Tcl_Size *clPosition = NULL;
int depth = TclGetStackDepth(envPtr);
/*
* If this is actually a literal, handle continuation lines by
* preallocating a small table to store the locations of any continuation
* lines found in this literal. The table is extended if needed.
*
* Note: In contrast with the analagous code in 'TclSubstTokens()' the
|
| ︙ | ︙ | |||
2814 2815 2816 2817 2818 2819 2820 |
* thing is a table of everything is not needed, just the number of
* lines to add as correction.
*/
if ((length == 1) && (buffer[0] == ' ') &&
(tokenPtr->start[1] == '\n')) {
if (isLiteral) {
| | | > > > > | > | 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 |
* thing is a table of everything is not needed, just the number of
* lines to add as correction.
*/
if ((length == 1) && (buffer[0] == ' ') &&
(tokenPtr->start[1] == '\n')) {
if (isLiteral) {
int clPos = Tcl_DStringLength(&textBuffer);
if (numCL >= maxNumCL) {
maxNumCL *= 2;
clPosition = (Tcl_Size *)Tcl_Realloc(clPosition,
maxNumCL * sizeof(Tcl_Size));
}
clPosition[numCL] = clPos;
numCL ++;
}
adjust++;
}
break;
case TCL_TOKEN_COMMAND:
/*
* Push any accumulated chars appearing before the command.
*/
if (Tcl_DStringLength(&textBuffer) > 0) {
int literal = TclRegisterDStringLiteral(envPtr, &textBuffer);
TclEmitPush(literal, envPtr);
numObjsToConcat++;
Tcl_DStringFree(&textBuffer);
if (numCL) {
TclContinuationsEnter(TclFetchLiteral(envPtr, literal),
numCL, clPosition);
}
numCL = 0;
}
envPtr->line += adjust;
TclCompileScript(interp, tokenPtr->start+1,
tokenPtr->size-2, envPtr);
envPtr->line -= adjust;
numObjsToConcat++;
break;
case TCL_TOKEN_VARIABLE:
/*
* Push any accumulated chars appearing before the $<var>.
*/
if (Tcl_DStringLength(&textBuffer) > 0) {
int literal;
literal = TclRegisterDStringLiteral(envPtr, &textBuffer);
TclEmitPush(literal, envPtr);
numObjsToConcat++;
Tcl_DStringFree(&textBuffer);
}
TclCompileVarSubst(interp, tokenPtr, envPtr);
numObjsToConcat++;
count -= tokenPtr->numComponents;
|
| ︙ | ︙ | |||
2880 2881 2882 2883 2884 2885 2886 |
}
/*
* Push any accumulated characters appearing at the end.
*/
if (Tcl_DStringLength(&textBuffer) > 0) {
| | > | | | | 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 |
}
/*
* Push any accumulated characters appearing at the end.
*/
if (Tcl_DStringLength(&textBuffer) > 0) {
int literal = TclRegisterDStringLiteral(envPtr, &textBuffer);
TclEmitPush(literal, envPtr);
numObjsToConcat++;
if (numCL) {
TclContinuationsEnter(TclFetchLiteral(envPtr, literal),
numCL, clPosition);
}
numCL = 0;
}
/*
* If necessary, concatenate the parts of the word.
*/
while (numObjsToConcat > 255) {
TclEmitInstInt1(INST_STR_CONCAT1, 255, envPtr);
numObjsToConcat -= 254; /* concat pushes 1 obj, the result */
}
if (numObjsToConcat > 1) {
TclEmitInstInt1(INST_STR_CONCAT1, numObjsToConcat, envPtr);
}
/*
* If the tokens yielded no instructions, push an empty string.
*/
if (envPtr->codeNext == entryCodeNext) {
PushStringLiteral(envPtr, "");
}
Tcl_DStringFree(&textBuffer);
/*
* Release the temp table we used to collect the locations of continuation
* lines, if any.
*/
|
| ︙ | ︙ | |||
2968 2969 2970 2971 2972 2973 2974 | /* * Either there are multiple tokens, or the single token involves * substitutions. Emit instructions to invoke the eval command * procedure at runtime on the result of evaluating the tokens. */ TclCompileTokens(interp, tokenPtr, count, envPtr); | | | 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 |
/*
* Either there are multiple tokens, or the single token involves
* substitutions. Emit instructions to invoke the eval command
* procedure at runtime on the result of evaluating the tokens.
*/
TclCompileTokens(interp, tokenPtr, count, envPtr);
TclEmitInvoke(envPtr, INST_EVAL_STK);
}
}
/*
*----------------------------------------------------------------------
*
* TclCompileExprWords --
|
| ︙ | ︙ | |||
2997 2998 2999 3000 3001 3002 3003 |
*/
void
TclCompileExprWords(
Tcl_Interp *interp, /* Used for error and status reporting. */
Tcl_Token *tokenPtr, /* Points to first in an array of word tokens
* for the expression to compile inline. */
| | | > | | | | | | | 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 |
*/
void
TclCompileExprWords(
Tcl_Interp *interp, /* Used for error and status reporting. */
Tcl_Token *tokenPtr, /* Points to first in an array of word tokens
* for the expression to compile inline. */
size_t numWords1, /* Number of word tokens starting at tokenPtr.
* Must be at least 1. Each word token
* contains one or more subtokens. */
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
Tcl_Token *wordPtr;
int i, concatItems;
int numWords = numWords1;
/*
* If the expression is a single word that doesn't require substitutions,
* just compile its string into inline instructions.
*/
if ((numWords == 1) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
TclCompileExpr(interp, tokenPtr[1].start,tokenPtr[1].size, envPtr, 1);
return;
}
/*
* Emit code to call the expr command proc at runtime. Concatenate the
* (already substituted once) expr tokens with a space between each.
*/
wordPtr = tokenPtr;
for (i = 0; i < numWords; i++) {
CompileTokens(envPtr, wordPtr, interp);
if (i < (numWords - 1)) {
PushStringLiteral(envPtr, " ");
}
wordPtr += wordPtr->numComponents + 1;
}
concatItems = 2*numWords - 1;
while (concatItems > 255) {
TclEmitInstInt1(INST_STR_CONCAT1, 255, envPtr);
concatItems -= 254;
}
if (concatItems > 1) {
TclEmitInstInt1(INST_STR_CONCAT1, concatItems, envPtr);
}
TclEmitOpcode(INST_EXPR_STK, envPtr);
}
/*
*----------------------------------------------------------------------
*
* TclCompileNoOp --
*
|
| ︙ | ︙ | |||
3074 3075 3076 3077 3078 3079 3080 |
tokenPtr = parsePtr->tokenPtr;
for (i = 1; i < parsePtr->numWords; i++) {
tokenPtr = tokenPtr + tokenPtr->numComponents + 1;
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
CompileTokens(envPtr, tokenPtr, interp);
| | | | 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 |
tokenPtr = parsePtr->tokenPtr;
for (i = 1; i < parsePtr->numWords; i++) {
tokenPtr = tokenPtr + tokenPtr->numComponents + 1;
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
CompileTokens(envPtr, tokenPtr, interp);
TclEmitOpcode(INST_POP, envPtr);
}
}
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclInitByteCodeObj --
|
| ︙ | ︙ | |||
3140 3141 3142 3143 3144 3145 3146 |
envPtr->literalArrayPtr[i].objPtr = copyPtr;
}
}
}
ByteCode *
TclInitByteCode(
| | > | | 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 |
envPtr->literalArrayPtr[i].objPtr = copyPtr;
}
}
}
ByteCode *
TclInitByteCode(
CompileEnv *envPtr)/* Points to the CompileEnv structure from
* which to create a ByteCode structure. */
{
ByteCode *codePtr;
size_t codeBytes, objArrayBytes, exceptArrayBytes, cmdLocBytes;
size_t auxDataArrayBytes, structureSize;
unsigned char *p;
#ifdef TCL_COMPILE_DEBUG
unsigned char *nextPtr;
#endif
Tcl_Size i, numLitObjects = envPtr->literalArrayNext;
Namespace *namespacePtr;
int isNew;
Interp *iPtr;
if (envPtr->iPtr == NULL) {
Tcl_Panic("TclInitByteCodeObj() called on uninitialized CompileEnv");
}
iPtr = envPtr->iPtr;
codeBytes = envPtr->codeNext - envPtr->codeStart;
objArrayBytes = envPtr->literalArrayNext * sizeof(Tcl_Obj *);
exceptArrayBytes = envPtr->exceptArrayNext * sizeof(ExceptionRange);
auxDataArrayBytes = envPtr->auxDataArrayNext * sizeof(AuxData);
cmdLocBytes = GetCmdLocEncodingSize(envPtr);
/*
* Compute the total number of bytes needed for this bytecode.
|
| ︙ | ︙ | |||
3245 3246 3247 3248 3249 3250 3251 |
p += auxDataArrayBytes;
#ifndef TCL_COMPILE_DEBUG
EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
#else
nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
if (((size_t)(nextPtr - p)) != cmdLocBytes) {
| < < | | | | | 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 |
p += auxDataArrayBytes;
#ifndef TCL_COMPILE_DEBUG
EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
#else
nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
if (((size_t)(nextPtr - p)) != cmdLocBytes) {
Tcl_Panic("TclInitByteCodeObj: encoded cmd location bytes %lu != expected size %lu", (unsigned long)(nextPtr - p), (unsigned long)cmdLocBytes);
}
#endif
/*
* Record various compilation-related statistics about the new ByteCode
* structure. Don't include overhead for statistics-related fields.
*/
#ifdef TCL_COMPILE_STATS
codePtr->structureSize = structureSize
- (sizeof(size_t) + sizeof(Tcl_Time));
Tcl_GetTime(&codePtr->createTime);
RecordByteCodeStats(codePtr);
#endif /* TCL_COMPILE_STATS */
/*
* TIP #280. Associate the extended per-word line information with the
* byte code object (internal rep), for use with the bc compiler.
*/
Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->lineBCPtr, codePtr,
&isNew), envPtr->extCmdMapPtr);
envPtr->extCmdMapPtr = NULL;
/* We've used up the CompileEnv. Mark as uninitialized. */
envPtr->iPtr = NULL;
codePtr->localCachePtr = NULL;
return codePtr;
}
ByteCode *
TclInitByteCodeObj(
Tcl_Obj *objPtr, /* Points object that should be initialized,
* and whose string rep contains the source
* code. */
const Tcl_ObjType *typePtr,
CompileEnv *envPtr)/* Points to the CompileEnv structure from
* which to create a ByteCode structure. */
{
ByteCode *codePtr;
PreventCycle(objPtr, envPtr);
codePtr = TclInitByteCode(envPtr);
|
| ︙ | ︙ | |||
3329 3330 3331 3332 3333 3334 3335 | * Side effects: * Creates and registers a new local variable if create is 1 and the * variable is unknown, or if the name is NULL. * *---------------------------------------------------------------------- */ | | | | | 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 |
* Side effects:
* Creates and registers a new local variable if create is 1 and the
* variable is unknown, or if the name is NULL.
*
*----------------------------------------------------------------------
*/
Tcl_Size
TclFindCompiledLocal(
const char *name, /* Points to first character of the name of a
* scalar or array variable. If NULL, a
* temporary var should be created. */
Tcl_Size nameBytes, /* Number of bytes in the name. */
int create, /* If 1, allocate a local frame entry for the
* variable if it is new. */
CompileEnv *envPtr) /* Points to the current compile environment*/
{
CompiledLocal *localPtr;
Tcl_Size localVar = TCL_INDEX_NONE;
Tcl_Size i;
Proc *procPtr;
|
| ︙ | ︙ | |||
3401 3402 3403 3404 3405 3406 3407 |
/*
* Create a new variable if appropriate.
*/
if (create || (name == NULL)) {
localVar = procPtr->numCompiledLocals;
| | < | 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 |
/*
* Create a new variable if appropriate.
*/
if (create || (name == NULL)) {
localVar = procPtr->numCompiledLocals;
localPtr = (CompiledLocal *)Tcl_Alloc(offsetof(CompiledLocal, name) + 1U + nameBytes);
if (procPtr->firstLocalPtr == NULL) {
procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
} else {
procPtr->lastLocalPtr->nextPtr = localPtr;
procPtr->lastLocalPtr = localPtr;
}
localPtr->nextPtr = NULL;
|
| ︙ | ︙ | |||
3461 3462 3463 3464 3465 3466 3467 |
/*
* envPtr->codeNext is equal to envPtr->codeEnd. The currently defined
* code bytes are stored between envPtr->codeStart and envPtr->codeNext-1
* [inclusive].
*/
| | | | 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 |
/*
* envPtr->codeNext is equal to envPtr->codeEnd. The currently defined
* code bytes are stored between envPtr->codeStart and envPtr->codeNext-1
* [inclusive].
*/
size_t currBytes = envPtr->codeNext - envPtr->codeStart;
size_t newBytes = 2 * (envPtr->codeEnd - envPtr->codeStart);
if (envPtr->mallocedCodeArray) {
envPtr->codeStart = (unsigned char *)Tcl_Realloc(envPtr->codeStart, newBytes);
} else {
/*
* envPtr->exceptArrayPtr isn't a Tcl_Alloc'd pointer, so
* perform the equivalent of Tcl_Realloc directly.
*/
unsigned char *newPtr = (unsigned char *)Tcl_Alloc(newBytes);
memcpy(newPtr, envPtr->codeStart, currBytes);
envPtr->codeStart = newPtr;
envPtr->mallocedCodeArray = 1;
}
envPtr->codeNext = envPtr->codeStart + currBytes;
envPtr->codeEnd = envPtr->codeStart + newBytes;
}
/*
|
| ︙ | ︙ | |||
3511 3512 3513 3514 3515 3516 3517 |
EnterCmdStartData(
CompileEnv *envPtr, /* Points to the compilation environment
* structure in which to enter command
* location information. */
Tcl_Size cmdIndex, /* Index of the command whose start data is
* being set. */
Tcl_Size srcOffset, /* Offset of first char of the command. */
| | | < | < | | | 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 |
EnterCmdStartData(
CompileEnv *envPtr, /* Points to the compilation environment
* structure in which to enter command
* location information. */
Tcl_Size cmdIndex, /* Index of the command whose start data is
* being set. */
Tcl_Size srcOffset, /* Offset of first char of the command. */
Tcl_Size codeOffset) /* Offset of first byte of command code. */
{
CmdLocation *cmdLocPtr;
if (cmdIndex < 0 || cmdIndex >= envPtr->numCommands) {
Tcl_Panic("EnterCmdStartData: bad command index %" TCL_Z_MODIFIER "u", cmdIndex);
}
if (cmdIndex >= envPtr->cmdMapEnd) {
/*
* Expand the command location array by allocating more storage from
* the heap. The currently allocated CmdLocation entries are stored
* from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).
*/
size_t currElems = envPtr->cmdMapEnd;
size_t newElems = 2 * currElems;
size_t currBytes = currElems * sizeof(CmdLocation);
size_t newBytes = newElems * sizeof(CmdLocation);
if (envPtr->mallocedCmdMap) {
envPtr->cmdMapPtr = (CmdLocation *)Tcl_Realloc(envPtr->cmdMapPtr, newBytes);
} else {
/*
* envPtr->cmdMapPtr isn't a Tcl_Alloc'd pointer, so we must code a
* Tcl_Realloc equivalent for ourselves.
*/
CmdLocation *newPtr = (CmdLocation *)Tcl_Alloc(newBytes);
memcpy(newPtr, envPtr->cmdMapPtr, currBytes);
envPtr->cmdMapPtr = newPtr;
envPtr->mallocedCmdMap = 1;
}
envPtr->cmdMapEnd = newElems;
}
if (cmdIndex > 0) {
if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
Tcl_Panic("EnterCmdStartData: cmd map not sorted by code offset");
}
}
cmdLocPtr = &envPtr->cmdMapPtr[cmdIndex];
cmdLocPtr->codeOffset = codeOffset;
cmdLocPtr->srcOffset = srcOffset;
|
| ︙ | ︙ | |||
3591 3592 3593 3594 3595 3596 3597 |
static void
EnterCmdExtentData(
CompileEnv *envPtr, /* Points to the compilation environment
* structure in which to enter command
* location information. */
Tcl_Size cmdIndex, /* Index of the command whose source and code
* length data is being set. */
| | | | < | < | 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 |
static void
EnterCmdExtentData(
CompileEnv *envPtr, /* Points to the compilation environment
* structure in which to enter command
* location information. */
Tcl_Size cmdIndex, /* Index of the command whose source and code
* length data is being set. */
Tcl_Size numSrcBytes, /* Number of command source chars. */
Tcl_Size numCodeBytes) /* Offset of last byte of command code. */
{
CmdLocation *cmdLocPtr;
if (cmdIndex < 0 || cmdIndex >= envPtr->numCommands) {
Tcl_Panic("EnterCmdExtentData: bad command index %" TCL_Z_MODIFIER "u", cmdIndex);
}
if (cmdIndex > envPtr->cmdMapEnd) {
Tcl_Panic("EnterCmdExtentData: missing start data for command %" TCL_Z_MODIFIER "u",
cmdIndex);
}
cmdLocPtr = &envPtr->cmdMapPtr[cmdIndex];
cmdLocPtr->numSrcBytes = numSrcBytes;
cmdLocPtr->numCodeBytes = numCodeBytes;
}
|
| ︙ | ︙ | |||
3641 3642 3643 3644 3645 3646 3647 |
ExtCmdLoc *eclPtr, /* Points to the map environment structure in
* which to enter command location
* information. */
Tcl_Size srcOffset, /* Offset of first char of the command. */
Tcl_Token *tokenPtr,
const char *cmd,
Tcl_Size numWords,
| | | | < < | | | | | 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 |
ExtCmdLoc *eclPtr, /* Points to the map environment structure in
* which to enter command location
* information. */
Tcl_Size srcOffset, /* Offset of first char of the command. */
Tcl_Token *tokenPtr,
const char *cmd,
Tcl_Size numWords,
Tcl_Size line,
Tcl_Size *clNext,
Tcl_Size **wlines,
CompileEnv *envPtr)
{
ECL *ePtr;
const char *last;
Tcl_Size wordIdx, wordLine;
Tcl_Size *wwlines, *wordNext;
if (eclPtr->nuloc >= eclPtr->nloc) {
/*
* Expand the ECL array by allocating more storage from the heap. The
* currently allocated ECL entries are stored from eclPtr->loc[0] up
* to eclPtr->loc[eclPtr->nuloc-1] (inclusive).
*/
size_t currElems = eclPtr->nloc;
size_t newElems = (currElems ? 2*currElems : 1);
size_t newBytes = newElems * sizeof(ECL);
eclPtr->loc = (ECL *)Tcl_Realloc(eclPtr->loc, newBytes);
eclPtr->nloc = newElems;
}
ePtr = &eclPtr->loc[eclPtr->nuloc];
ePtr->srcOffset = srcOffset;
ePtr->line = (Tcl_Size *)Tcl_Alloc(numWords * sizeof(Tcl_Size));
ePtr->next = (Tcl_Size **)Tcl_Alloc(numWords * sizeof(Tcl_Size *));
ePtr->nline = numWords;
wwlines = (Tcl_Size *)Tcl_Alloc(numWords * sizeof(Tcl_Size));
last = cmd;
wordLine = line;
wordNext = clNext;
for (wordIdx=0 ; wordIdx<numWords;
wordIdx++, tokenPtr += tokenPtr->numComponents + 1) {
TclAdvanceLines(&wordLine, last, tokenPtr->start);
|
| ︙ | ︙ | |||
3716 3717 3718 3719 3720 3721 3722 | * the array in expanded: a new array of double the size is allocated, if * envPtr->mallocedExceptArray is non-zero the old array is freed, and * ExceptionRange entries are copied from the old array to the new one. * *---------------------------------------------------------------------- */ | | | | 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 |
* the array in expanded: a new array of double the size is allocated, if
* envPtr->mallocedExceptArray is non-zero the old array is freed, and
* ExceptionRange entries are copied from the old array to the new one.
*
*----------------------------------------------------------------------
*/
Tcl_Size
TclCreateExceptRange(
ExceptionRangeType type, /* The kind of ExceptionRange desired. */
CompileEnv *envPtr)/* Points to CompileEnv for which to create a
* new ExceptionRange structure. */
{
ExceptionRange *rangePtr;
ExceptionAux *auxPtr;
Tcl_Size index = envPtr->exceptArrayNext;
if (index >= envPtr->exceptArrayEnd) {
|
| ︙ | ︙ | |||
3741 3742 3743 3744 3745 3746 3747 |
envPtr->exceptArrayNext * sizeof(ExceptionRange);
size_t currBytes2 = envPtr->exceptArrayNext * sizeof(ExceptionAux);
size_t newElems = 2*envPtr->exceptArrayEnd;
size_t newBytes = newElems * sizeof(ExceptionRange);
size_t newBytes2 = newElems * sizeof(ExceptionAux);
if (envPtr->mallocedExceptArray) {
| | | | | | | | 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 |
envPtr->exceptArrayNext * sizeof(ExceptionRange);
size_t currBytes2 = envPtr->exceptArrayNext * sizeof(ExceptionAux);
size_t newElems = 2*envPtr->exceptArrayEnd;
size_t newBytes = newElems * sizeof(ExceptionRange);
size_t newBytes2 = newElems * sizeof(ExceptionAux);
if (envPtr->mallocedExceptArray) {
envPtr->exceptArrayPtr =
(ExceptionRange *)Tcl_Realloc(envPtr->exceptArrayPtr, newBytes);
envPtr->exceptAuxArrayPtr =
(ExceptionAux *)Tcl_Realloc(envPtr->exceptAuxArrayPtr, newBytes2);
} else {
/*
* envPtr->exceptArrayPtr isn't a Tcl_Alloc'd pointer, so we must
* code a Tcl_Realloc equivalent for ourselves.
*/
ExceptionRange *newPtr = (ExceptionRange *)Tcl_Alloc(newBytes);
ExceptionAux *newPtr2 = (ExceptionAux *)Tcl_Alloc(newBytes2);
memcpy(newPtr, envPtr->exceptArrayPtr, currBytes);
memcpy(newPtr2, envPtr->exceptAuxArrayPtr, currBytes2);
envPtr->exceptArrayPtr = newPtr;
envPtr->exceptAuxArrayPtr = newPtr2;
envPtr->mallocedExceptArray = 1;
}
envPtr->exceptArrayEnd = newElems;
}
envPtr->exceptArrayNext++;
rangePtr = &envPtr->exceptArrayPtr[index];
rangePtr->type = type;
rangePtr->nestingLevel = envPtr->exceptDepth;
rangePtr->codeOffset = TCL_INDEX_NONE;
rangePtr->numCodeBytes = TCL_INDEX_NONE;
rangePtr->breakOffset = TCL_INDEX_NONE;
rangePtr->continueOffset = TCL_INDEX_NONE;
rangePtr->catchOffset = TCL_INDEX_NONE;
auxPtr = &envPtr->exceptAuxArrayPtr[index];
auxPtr->supportsContinue = 1;
auxPtr->stackDepth = envPtr->currStackDepth;
auxPtr->expandTarget = envPtr->expandCount;
auxPtr->expandTargetDepth = TCL_INDEX_NONE;
auxPtr->numBreakTargets = 0;
auxPtr->breakTargets = NULL;
auxPtr->allocBreakTargets = 0;
auxPtr->numContinueTargets = 0;
|
| ︙ | ︙ | |||
3813 3814 3815 3816 3817 3818 3819 |
size_t i = envPtr->exceptArrayNext;
ExceptionRange *rangePtr = envPtr->exceptArrayPtr + i;
while (i > 0) {
rangePtr--;
i--;
| | | | | | | | | | | | | | | > | | | | | | 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 |
size_t i = envPtr->exceptArrayNext;
ExceptionRange *rangePtr = envPtr->exceptArrayPtr + i;
while (i > 0) {
rangePtr--;
i--;
if (CurrentOffset(envPtr) >= (int)rangePtr->codeOffset &&
(rangePtr->numCodeBytes == TCL_INDEX_NONE || CurrentOffset(envPtr) <
(int)rangePtr->codeOffset+(int)rangePtr->numCodeBytes) &&
(returnCode != TCL_CONTINUE ||
envPtr->exceptAuxArrayPtr[i].supportsContinue)) {
if (auxPtrPtr) {
*auxPtrPtr = envPtr->exceptAuxArrayPtr + i;
}
return rangePtr;
}
}
return NULL;
}
/*
* ---------------------------------------------------------------------
*
* TclAddLoopBreakFixup, TclAddLoopContinueFixup --
*
* Adds a place that wants to break/continue to the loop exception range
* tracking that will be fixed up once the loop can be finalized. These
* functions generate an INST_JUMP4 that is fixed up during the
* loop finalization.
*
* ---------------------------------------------------------------------
*/
void
TclAddLoopBreakFixup(
CompileEnv *envPtr,
ExceptionAux *auxPtr)
{
int range = auxPtr - envPtr->exceptAuxArrayPtr;
if (envPtr->exceptArrayPtr[range].type != LOOP_EXCEPTION_RANGE) {
Tcl_Panic("trying to add 'break' fixup to full exception range");
}
if (++auxPtr->numBreakTargets > auxPtr->allocBreakTargets) {
auxPtr->allocBreakTargets *= 2;
auxPtr->allocBreakTargets += 2;
if (auxPtr->breakTargets) {
auxPtr->breakTargets = (size_t *)Tcl_Realloc(auxPtr->breakTargets,
sizeof(size_t) * auxPtr->allocBreakTargets);
} else {
auxPtr->breakTargets =
(size_t *)Tcl_Alloc(sizeof(size_t) * auxPtr->allocBreakTargets);
}
}
auxPtr->breakTargets[auxPtr->numBreakTargets - 1] = CurrentOffset(envPtr);
TclEmitInstInt4(INST_JUMP4, 0, envPtr);
}
void
TclAddLoopContinueFixup(
CompileEnv *envPtr,
ExceptionAux *auxPtr)
{
int range = auxPtr - envPtr->exceptAuxArrayPtr;
if (envPtr->exceptArrayPtr[range].type != LOOP_EXCEPTION_RANGE) {
Tcl_Panic("trying to add 'continue' fixup to full exception range");
}
if (++auxPtr->numContinueTargets > auxPtr->allocContinueTargets) {
auxPtr->allocContinueTargets *= 2;
auxPtr->allocContinueTargets += 2;
if (auxPtr->continueTargets) {
auxPtr->continueTargets = (size_t *)Tcl_Realloc(auxPtr->continueTargets,
sizeof(size_t) * auxPtr->allocContinueTargets);
} else {
auxPtr->continueTargets =
(size_t *)Tcl_Alloc(sizeof(size_t) * auxPtr->allocContinueTargets);
}
}
auxPtr->continueTargets[auxPtr->numContinueTargets - 1] =
CurrentOffset(envPtr);
TclEmitInstInt4(INST_JUMP4, 0, envPtr);
}
/*
* ---------------------------------------------------------------------
*
* TclCleanupStackForBreakContinue --
*
* Removes the extra elements from the auxiliary stack and the main stack.
* How this is done depends on whether there are any elements on
* the auxiliary stack to pop.
*
* ---------------------------------------------------------------------
*/
void
TclCleanupStackForBreakContinue(
CompileEnv *envPtr,
ExceptionAux *auxPtr)
{
size_t savedStackDepth = envPtr->currStackDepth;
int toPop = envPtr->expandCount - auxPtr->expandTarget;
if (toPop > 0) {
while (toPop --> 0) {
TclEmitOpcode(INST_EXPAND_DROP, envPtr);
}
TclAdjustStackDepth((int)(auxPtr->expandTargetDepth - envPtr->currStackDepth),
envPtr);
envPtr->currStackDepth = auxPtr->expandTargetDepth;
}
toPop = envPtr->currStackDepth - auxPtr->stackDepth;
while (toPop --> 0) {
TclEmitOpcode(INST_POP, envPtr);
}
envPtr->currStackDepth = savedStackDepth;
}
/*
* ---------------------------------------------------------------------
*
* StartExpanding --
*
* Pushes an INST_EXPAND_START and does some additional housekeeping so
* that the [break] and [continue] compilers can use an exception-free
* issue to discard it.
*
* ---------------------------------------------------------------------
*/
static void
StartExpanding(
CompileEnv *envPtr)
{
int i;
TclEmitOpcode(INST_EXPAND_START, envPtr);
/*
* Update inner exception ranges with information about the environment
* where this expansion started.
*/
for (i=0 ; i<(int)envPtr->exceptArrayNext ; i++) {
ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[i];
ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[i];
/*
* Ignore loops unless they're still being built.
*/
if ((int)rangePtr->codeOffset > CurrentOffset(envPtr)) {
continue;
}
if (rangePtr->numCodeBytes != TCL_INDEX_NONE) {
continue;
}
/*
|
| ︙ | ︙ | |||
4001 4002 4003 4004 4005 4006 4007 |
*
* ---------------------------------------------------------------------
*/
void
TclFinalizeLoopExceptionRange(
CompileEnv *envPtr,
| | | | | | | | 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 |
*
* ---------------------------------------------------------------------
*/
void
TclFinalizeLoopExceptionRange(
CompileEnv *envPtr,
int range)
{
ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[range];
ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[range];
int i, offset;
unsigned char *site;
if (rangePtr->type != LOOP_EXCEPTION_RANGE) {
Tcl_Panic("trying to finalize a loop exception range");
}
/*
* Do the jump fixups. Note that these are always issued as INST_JUMP4 so
* there is no need to fuss around with updating code offsets.
*/
for (i=0 ; i<(int)auxPtr->numBreakTargets ; i++) {
site = envPtr->codeStart + auxPtr->breakTargets[i];
offset = rangePtr->breakOffset - auxPtr->breakTargets[i];
TclUpdateInstInt4AtPc(INST_JUMP4, offset, site);
}
for (i=0 ; i<(int)auxPtr->numContinueTargets ; i++) {
site = envPtr->codeStart + auxPtr->continueTargets[i];
if (rangePtr->continueOffset == TCL_INDEX_NONE) {
int j;
/*
* WTF? Can't bind, so revert to an INST_CONTINUE. Not enough
* space to do anything else.
*/
*site = INST_CONTINUE;
for (j=0 ; j<4 ; j++) {
*++site = INST_NOP;
}
} else {
offset = rangePtr->continueOffset - auxPtr->continueTargets[i];
TclUpdateInstInt4AtPc(INST_JUMP4, offset, site);
}
}
/*
* Drop the arrays we were holding the only reference to.
*/
|
| ︙ | ︙ | |||
4077 4078 4079 4080 4081 4082 4083 | * * Side effects: * If there is not enough room in the CompileEnv's AuxData array, its size * is doubled. *---------------------------------------------------------------------- */ | | | | > | | 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 |
*
* Side effects:
* If there is not enough room in the CompileEnv's AuxData array, its size
* is doubled.
*----------------------------------------------------------------------
*/
Tcl_Size
TclCreateAuxData(
void *clientData, /* The compilation auxiliary data to store in
* the new aux data record. */
const AuxDataType *typePtr, /* Pointer to the type to attach to this
* AuxData */
CompileEnv *envPtr)/* Points to the CompileEnv for which a new
* aux data structure is to be allocated. */
{
Tcl_Size index; /* Index for the new AuxData structure. */
AuxData *auxDataPtr;
/* Points to the new AuxData structure */
index = envPtr->auxDataArrayNext;
if (index >= envPtr->auxDataArrayEnd) {
/*
* Expand the AuxData array. The currently allocated entries are
* stored between elements 0 and (envPtr->auxDataArrayNext - 1)
* [inclusive].
|
| ︙ | ︙ | |||
4114 4115 4116 4117 4118 4119 4120 | * code a Tcl_Realloc equivalent for ourselves. */ AuxData *newPtr = (AuxData *)Tcl_Alloc(newBytes); memcpy(newPtr, envPtr->auxDataArrayPtr, currBytes); envPtr->auxDataArrayPtr = newPtr; | | | 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 |
* code a Tcl_Realloc equivalent for ourselves.
*/
AuxData *newPtr = (AuxData *)Tcl_Alloc(newBytes);
memcpy(newPtr, envPtr->auxDataArrayPtr, currBytes);
envPtr->auxDataArrayPtr = newPtr;
envPtr->mallocedAuxDataArray = 1;
}
envPtr->auxDataArrayEnd = newElems;
}
envPtr->auxDataArrayNext++;
auxDataPtr = &envPtr->auxDataArrayPtr[index];
auxDataPtr->clientData = clientData;
|
| ︙ | ︙ | |||
4152 4153 4154 4155 4156 4157 4158 |
JumpFixupArray *fixupArrayPtr)
/* Points to the JumpFixupArray structure to
* initialize. */
{
fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;
fixupArrayPtr->next = 0;
fixupArrayPtr->end = JUMPFIXUP_INIT_ENTRIES - 1;
| | | 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 |
JumpFixupArray *fixupArrayPtr)
/* Points to the JumpFixupArray structure to
* initialize. */
{
fixupArrayPtr->fixup = fixupArrayPtr->staticFixupSpace;
fixupArrayPtr->next = 0;
fixupArrayPtr->end = JUMPFIXUP_INIT_ENTRIES - 1;
fixupArrayPtr->mallocedArray = 0;
}
/*
*----------------------------------------------------------------------
*
* TclExpandJumpFixupArray --
*
|
| ︙ | ︙ | |||
4191 4192 4193 4194 4195 4196 4197 |
*/
size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);
size_t newElems = 2*(fixupArrayPtr->end + 1);
size_t newBytes = newElems * sizeof(JumpFixup);
if (fixupArrayPtr->mallocedArray) {
| | < | | 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 |
*/
size_t currBytes = fixupArrayPtr->next * sizeof(JumpFixup);
size_t newElems = 2*(fixupArrayPtr->end + 1);
size_t newBytes = newElems * sizeof(JumpFixup);
if (fixupArrayPtr->mallocedArray) {
fixupArrayPtr->fixup = (JumpFixup *)Tcl_Realloc(fixupArrayPtr->fixup, newBytes);
} else {
/*
* fixupArrayPtr->fixup isn't a Tcl_Alloc'd pointer, so we must code a
* Tcl_Realloc equivalent for ourselves.
*/
JumpFixup *newPtr = (JumpFixup *)Tcl_Alloc(newBytes);
memcpy(newPtr, fixupArrayPtr->fixup, currBytes);
fixupArrayPtr->fixup = newPtr;
fixupArrayPtr->mallocedArray = 1;
}
fixupArrayPtr->end = newElems;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4240 4241 4242 4243 4244 4245 4246 | } /* *---------------------------------------------------------------------- * * TclEmitForwardJump -- * | | | > > > | | | 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 |
}
/*
*----------------------------------------------------------------------
*
* TclEmitForwardJump --
*
* Emits a two-byte forward jump of kind "jumpType". Also initializes a
* JumpFixup record with information about the jump. Since may later be
* necessary to increase the size of the jump instruction to five bytes if
* the jump target is more than, say, 127 bytes away.
*
*
* Results:
* None.
*
* Side effects:
* The JumpFixup record pointed to by "jumpFixupPtr" is initialized with
* information needed later if the jump is to be grown. Also, a two byte
* jump of the designated type is emitted at the current point in the
* bytecode stream.
*
*----------------------------------------------------------------------
*/
void
TclEmitForwardJump(
CompileEnv *envPtr, /* Points to the CompileEnv structure that
|
| ︙ | ︙ | |||
4274 4275 4276 4277 4278 4279 4280 |
* - codeOffset is offset of first byte of jump below
* - cmdIndex is index of the command after the current one
* - exceptIndex is the index of the first ExceptionRange after the
* current one.
*/
jumpFixupPtr->jumpType = jumpType;
| | | | | | > > > | | > > | < > > > > > | | > > > > > > > | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | | | < < < < < < | | | < < < < < < | 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 |
* - codeOffset is offset of first byte of jump below
* - cmdIndex is index of the command after the current one
* - exceptIndex is the index of the first ExceptionRange after the
* current one.
*/
jumpFixupPtr->jumpType = jumpType;
jumpFixupPtr->codeOffset = envPtr->codeNext - envPtr->codeStart;
jumpFixupPtr->cmdIndex = envPtr->numCommands;
jumpFixupPtr->exceptIndex = envPtr->exceptArrayNext;
switch (jumpType) {
case TCL_UNCONDITIONAL_JUMP:
TclEmitInstInt1(INST_JUMP1, 0, envPtr);
break;
case TCL_TRUE_JUMP:
TclEmitInstInt1(INST_JUMP_TRUE1, 0, envPtr);
break;
default:
TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr);
break;
}
}
/*
*----------------------------------------------------------------------
*
* TclFixupForwardJump --
*
* Modifies a previously-emitted forward jump to jump a specified number
* of bytes, "jumpDist". If necessary, the size of the jump instruction is
* increased from two to five bytes. This is done if the jump distance is
* greater than "distThreshold" (normally 127 bytes). The jump is
* described by a JumpFixup record previously initialized by
* TclEmitForwardJump.
*
* Results:
* 1 if the jump was grown and subsequent instructions had to be moved, or
* 0 otherwsie. This allows callers to update any additional code offsets
* they may hold.
*
* Side effects:
* The jump may be grown and subsequent instructions moved. If this
* happens, the code offsets for any commands and any ExceptionRange
* records between the jump and the current code address will be updated
* to reflect the moved code. Also, the bytecode instruction array in the
* CompileEnv structure may be grown and reallocated.
*
*----------------------------------------------------------------------
*/
int
TclFixupForwardJump(
CompileEnv *envPtr, /* Points to the CompileEnv structure that
* holds the resulting instruction. */
JumpFixup *jumpFixupPtr, /* Points to the JumpFixup structure that
* describes the forward jump. */
int jumpDist, /* Jump distance to set in jump instr. */
int distThreshold) /* Maximum distance before the two byte jump
* is grown to five bytes. */
{
unsigned char *jumpPc, *p;
int firstCmd, lastCmd, firstRange, lastRange, k;
size_t numBytes;
if (jumpDist <= distThreshold) {
jumpPc = envPtr->codeStart + jumpFixupPtr->codeOffset;
switch (jumpFixupPtr->jumpType) {
case TCL_UNCONDITIONAL_JUMP:
TclUpdateInstInt1AtPc(INST_JUMP1, jumpDist, jumpPc);
break;
case TCL_TRUE_JUMP:
TclUpdateInstInt1AtPc(INST_JUMP_TRUE1, jumpDist, jumpPc);
break;
default:
TclUpdateInstInt1AtPc(INST_JUMP_FALSE1, jumpDist, jumpPc);
break;
}
return 0;
}
/*
* Increase the size of the jump instruction, and then move subsequent
* instructions down. Expanding the space for generated instructions means
* that code addresses might change. Be careful about updating any of
* these addresses held in variables.
*/
if ((envPtr->codeNext + 3) > envPtr->codeEnd) {
TclExpandCodeArray(envPtr);
}
jumpPc = envPtr->codeStart + jumpFixupPtr->codeOffset;
numBytes = envPtr->codeNext-jumpPc-2;
p = jumpPc+2;
memmove(p+3, p, numBytes);
envPtr->codeNext += 3;
jumpDist += 3;
switch (jumpFixupPtr->jumpType) {
case TCL_UNCONDITIONAL_JUMP:
TclUpdateInstInt4AtPc(INST_JUMP4, jumpDist, jumpPc);
break;
case TCL_TRUE_JUMP:
TclUpdateInstInt4AtPc(INST_JUMP_TRUE4, jumpDist, jumpPc);
break;
default:
TclUpdateInstInt4AtPc(INST_JUMP_FALSE4, jumpDist, jumpPc);
break;
}
/*
* Adjust the code offsets for any commands and any ExceptionRange records
* between the jump and the current code address.
*/
firstCmd = jumpFixupPtr->cmdIndex;
lastCmd = envPtr->numCommands - 1;
if (firstCmd < lastCmd) {
for (k = firstCmd; k <= lastCmd; k++) {
envPtr->cmdMapPtr[k].codeOffset += 3;
}
}
firstRange = jumpFixupPtr->exceptIndex;
lastRange = envPtr->exceptArrayNext - 1;
for (k = firstRange; k <= lastRange; k++) {
ExceptionRange *rangePtr = &envPtr->exceptArrayPtr[k];
rangePtr->codeOffset += 3;
switch (rangePtr->type) {
case LOOP_EXCEPTION_RANGE:
rangePtr->breakOffset += 3;
if (rangePtr->continueOffset != TCL_INDEX_NONE) {
rangePtr->continueOffset += 3;
}
break;
case CATCH_EXCEPTION_RANGE:
rangePtr->catchOffset += 3;
break;
default:
Tcl_Panic("TclFixupForwardJump: bad ExceptionRange type %d",
rangePtr->type);
}
}
for (k = 0 ; k < (int)envPtr->exceptArrayNext ; k++) {
ExceptionAux *auxPtr = &envPtr->exceptAuxArrayPtr[k];
int i;
for (i=0 ; i<(int)auxPtr->numBreakTargets ; i++) {
if (jumpFixupPtr->codeOffset < auxPtr->breakTargets[i]) {
auxPtr->breakTargets[i] += 3;
}
}
for (i=0 ; i<(int)auxPtr->numContinueTargets ; i++) {
if (jumpFixupPtr->codeOffset < auxPtr->continueTargets[i]) {
auxPtr->continueTargets[i] += 3;
}
}
}
return 1; /* the jump was grown */
}
/*
*----------------------------------------------------------------------
*
* TclEmitInvoke --
*
* Emits one of the invoke-related instructions, wrapping it if necessary
* in code that ensures that any break or continue operation passing
* through it gets the stack unwinding correct, converting it into an
* internal jump if in an appropriate context.
*
* Results:
* None
*
* Side effects:
* Issues the jump with all correct stack management. May create another
* loop exception range. Pointers to ExceptionRange and ExceptionAux
* structures should not be held across this call.
*
*----------------------------------------------------------------------
*/
void
TclEmitInvoke(
CompileEnv *envPtr,
int opcode,
...)
{
va_list argList;
ExceptionRange *rangePtr;
ExceptionAux *auxBreakPtr, *auxContinuePtr;
int arg1, arg2, wordCount = 0, expandCount = 0;
int loopRange = 0, breakRange = 0, continueRange = 0;
int cleanup, depth = TclGetStackDepth(envPtr);
/*
* Parse the arguments.
*/
va_start(argList, opcode);
switch (opcode) {
case INST_INVOKE_STK1:
wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
break;
case INST_INVOKE_STK4:
wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
break;
case INST_INVOKE_REPLACE:
arg1 = va_arg(argList, int);
arg2 = va_arg(argList, int);
wordCount = arg1 + arg2 - 1;
cleanup = arg1 + 1;
break;
default:
Tcl_Panic("unexpected opcode");
case INST_EVAL_STK:
wordCount = cleanup = 1;
arg1 = arg2 = 0;
break;
case INST_RETURN_STK:
wordCount = cleanup = 2;
arg1 = arg2 = 0;
break;
case INST_INVOKE_EXPANDED:
wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
expandCount = 1;
break;
}
va_end(argList);
/*
* If the exceptions is for break or continue handle it with special
* handling exception range so the stack may be correctly unwound.
*
|
| ︙ | ︙ | |||
4449 4450 4451 4452 4453 4454 4455 |
&& auxBreakPtr->expandTarget+expandCount == envPtr->expandCount) {
auxBreakPtr = NULL;
} else {
breakRange = auxBreakPtr - envPtr->exceptAuxArrayPtr;
}
if (auxBreakPtr != NULL || auxContinuePtr != NULL) {
| | < | < | | | | | | | < < < < < < < < | < < > < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 |
&& auxBreakPtr->expandTarget+expandCount == envPtr->expandCount) {
auxBreakPtr = NULL;
} else {
breakRange = auxBreakPtr - envPtr->exceptAuxArrayPtr;
}
if (auxBreakPtr != NULL || auxContinuePtr != NULL) {
loopRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
ExceptionRangeStarts(envPtr, loopRange);
}
/*
* Issue the invoke itself.
*/
switch (opcode) {
case INST_INVOKE_STK1:
TclEmitInstInt1(INST_INVOKE_STK1, arg1, envPtr);
break;
case INST_INVOKE_STK4:
TclEmitInstInt4(INST_INVOKE_STK4, arg1, envPtr);
break;
case INST_INVOKE_EXPANDED:
TclEmitOpcode(INST_INVOKE_EXPANDED, envPtr);
envPtr->expandCount--;
TclAdjustStackDepth(1 - arg1, envPtr);
break;
case INST_EVAL_STK:
TclEmitOpcode(INST_EVAL_STK, envPtr);
break;
case INST_RETURN_STK:
TclEmitOpcode(INST_RETURN_STK, envPtr);
break;
case INST_INVOKE_REPLACE:
TclEmitInstInt4(INST_INVOKE_REPLACE, arg1, envPtr);
TclEmitInt1(arg2, envPtr);
TclAdjustStackDepth(-1, envPtr); /* Correction to stack depth calcs */
break;
}
/*
* If we're generating a special wrapper exception range, we need to
* finish that up now.
*/
if (auxBreakPtr != NULL || auxContinuePtr != NULL) {
size_t savedStackDepth = envPtr->currStackDepth;
size_t savedExpandCount = envPtr->expandCount;
JumpFixup nonTrapFixup;
if (auxBreakPtr != NULL) {
auxBreakPtr = envPtr->exceptAuxArrayPtr + breakRange;
}
if (auxContinuePtr != NULL) {
auxContinuePtr = envPtr->exceptAuxArrayPtr + continueRange;
}
ExceptionRangeEnds(envPtr, loopRange);
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &nonTrapFixup);
/*
* Careful! When generating these stack unwinding sequences, the depth
* of stack in the cases where they are taken is not the same as if
* the exception is not taken.
*/
if (auxBreakPtr != NULL) {
TclAdjustStackDepth(-1, envPtr);
ExceptionRangeTarget(envPtr, loopRange, breakOffset);
TclCleanupStackForBreakContinue(envPtr, auxBreakPtr);
TclAddLoopBreakFixup(envPtr, auxBreakPtr);
TclAdjustStackDepth(1, envPtr);
envPtr->currStackDepth = savedStackDepth;
envPtr->expandCount = savedExpandCount;
}
if (auxContinuePtr != NULL) {
TclAdjustStackDepth(-1, envPtr);
ExceptionRangeTarget(envPtr, loopRange, continueOffset);
TclCleanupStackForBreakContinue(envPtr, auxContinuePtr);
TclAddLoopContinueFixup(envPtr, auxContinuePtr);
TclAdjustStackDepth(1, envPtr);
envPtr->currStackDepth = savedStackDepth;
envPtr->expandCount = savedExpandCount;
}
TclFinalizeLoopExceptionRange(envPtr, loopRange);
TclFixupForwardJumpToHere(envPtr, &nonTrapFixup, 127);
}
TclCheckStackDepth(depth+1-cleanup, envPtr);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4619 4620 4621 4622 4623 4624 4625 |
static int
GetCmdLocEncodingSize(
CompileEnv *envPtr) /* Points to compilation environment structure
* containing the CmdLocation structure to
* encode. */
{
CmdLocation *mapPtr = envPtr->cmdMapPtr;
| | | | | 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 |
static int
GetCmdLocEncodingSize(
CompileEnv *envPtr) /* Points to compilation environment structure
* containing the CmdLocation structure to
* encode. */
{
CmdLocation *mapPtr = envPtr->cmdMapPtr;
int numCmds = envPtr->numCommands;
int codeDelta, codeLen, srcDelta, srcLen;
int codeDeltaNext, codeLengthNext, srcDeltaNext, srcLengthNext;
/* The offsets in their respective byte
* sequences where the next encoded offset or
* length should go. */
int prevCodeOffset, prevSrcOffset, i;
codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0;
prevCodeOffset = prevSrcOffset = 0;
for (i = 0; i < numCmds; i++) {
codeDelta = mapPtr[i].codeOffset - prevCodeOffset;
if (codeDelta < 0) {
Tcl_Panic("GetCmdLocEncodingSize: bad code offset");
|
| ︙ | ︙ | |||
4706 4707 4708 4709 4710 4711 4712 |
* memory block where the location information
* is to be stored. */
{
CmdLocation *mapPtr = envPtr->cmdMapPtr;
Tcl_Size i, codeDelta, codeLen, srcLen, prevOffset;
Tcl_Size numCmds = envPtr->numCommands;
unsigned char *p = startPtr;
| | | 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 |
* memory block where the location information
* is to be stored. */
{
CmdLocation *mapPtr = envPtr->cmdMapPtr;
Tcl_Size i, codeDelta, codeLen, srcLen, prevOffset;
Tcl_Size numCmds = envPtr->numCommands;
unsigned char *p = startPtr;
int srcDelta;
/*
* Encode the code offset for each command as a sequence of deltas.
*/
codePtr->codeDeltaStart = p;
prevOffset = 0;
|
| ︙ | ︙ | |||
4792 4793 4794 4795 4796 4797 4798 |
TclStoreInt4AtPtr(srcLen, p);
p += 4;
}
}
return p;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 |
TclStoreInt4AtPtr(srcLen, p);
p += 4;
}
}
return p;
}
#ifdef TCL_COMPILE_STATS
/*
*----------------------------------------------------------------------
*
* RecordByteCodeStats --
*
|
| ︙ | ︙ | |||
5133 5134 5135 5136 5137 5138 5139 | * Accumulates aggregate code-related statistics in the interpreter's * ByteCodeStats structure. Records statistics specific to a ByteCode in * its ByteCode structure. * *---------------------------------------------------------------------- */ | | | 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 |
* Accumulates aggregate code-related statistics in the interpreter's
* ByteCodeStats structure. Records statistics specific to a ByteCode in
* its ByteCode structure.
*
*----------------------------------------------------------------------
*/
void
RecordByteCodeStats(
ByteCode *codePtr) /* Points to ByteCode structure with info
* to add to accumulated statistics. */
{
Interp *iPtr = (Interp *) *codePtr->interpHandle;
ByteCodeStats *statsPtr;
|
| ︙ | ︙ |
Changes to generic/tclCompile.h.
1 2 3 | /* * tclCompile.h -- * | | | | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * tclCompile.h -- * * Copyright (c) 1996-1998 Sun Microsystems, Inc. * Copyright (c) 1998-2000 by Scriptics Corporation. * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. * Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net> * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLCOMPILATION #define _TCLCOMPILATION 1 |
| ︙ | ︙ | |||
33 34 35 36 37 38 39 | * 1: summarize compilation of top level cmds and proc bodies * 2: display all instructions of each ByteCode compiled * This variable is linked to the Tcl variable "tcl_traceCompile". */ MODULE_SCOPE int tclTraceCompile; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | * 1: summarize compilation of top level cmds and proc bodies * 2: display all instructions of each ByteCode compiled * This variable is linked to the Tcl variable "tcl_traceCompile". */ MODULE_SCOPE int tclTraceCompile; /* * Variable that controls whether execution tracing is enabled and, if so, * what level of tracing is desired: * 0: no execution tracing * 1: trace invocations of Tcl procs only * 2: trace invocations of all (not compiled away) commands * 3: display each instruction executed * This variable is linked to the Tcl variable "tcl_traceExec". */ MODULE_SCOPE int tclTraceExec; #endif /* * The type of lambda expressions. Note that every lambda will *always* have a * string representation. */ MODULE_SCOPE const Tcl_ObjType tclLambdaType; /* *------------------------------------------------------------------------ * Data structures related to compilation. *------------------------------------------------------------------------ */ /* * The structure used to implement Tcl "exceptions" (exceptional returns): for * example, those generated in loops by the break and continue commands, and * those generated by scripts and caught by the catch command. This * ExceptionRange structure describes a range of code (e.g., a loop body), the * kind of exceptions (e.g., a break or continue) that might occur, and the PC * offsets to jump to if a matching exception does occur. Exception ranges can |
| ︙ | ︙ | |||
149 150 151 152 153 154 155 |
* and continue "exceptions" cause jumps to
* appropriate PC offsets. */
CATCH_EXCEPTION_RANGE /* Exception's range is controlled by a catch
* command. Errors in the range cause a jump
* to a catch PC offset. */
} ExceptionRangeType;
| | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
* and continue "exceptions" cause jumps to
* appropriate PC offsets. */
CATCH_EXCEPTION_RANGE /* Exception's range is controlled by a catch
* command. Errors in the range cause a jump
* to a catch PC offset. */
} ExceptionRangeType;
typedef struct {
ExceptionRangeType type; /* The kind of ExceptionRange. */
Tcl_Size nestingLevel; /* Static depth of the exception range. Used
* to find the most deeply-nested range
* surrounding a PC at runtime. */
Tcl_Size codeOffset; /* Offset of the first instruction byte of the
* code range. */
Tcl_Size numCodeBytes; /* Number of bytes in the code range. */
|
| ︙ | ︙ | |||
174 175 176 177 178 179 180 |
/*
* Auxiliary data used when issuing (currently just loop) exception ranges,
* but which is not required during execution.
*/
typedef struct ExceptionAux {
| | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
/*
* Auxiliary data used when issuing (currently just loop) exception ranges,
* but which is not required during execution.
*/
typedef struct ExceptionAux {
int supportsContinue; /* Whether this exception range will have a
* continueOffset created for it; if it is a
* loop exception range that *doesn't* have
* one (see [for] next-clause) then we must
* not pick up the range when scanning for a
* target to continue to. */
Tcl_Size stackDepth; /* The stack depth at the point where the
* exception range was created. This is used
|
| ︙ | ︙ | |||
197 198 199 200 201 202 203 |
* expansion within the loop. Not meaningful
* if there are no open expansions between the
* looping level and the point of jump
* issue. */
Tcl_Size numBreakTargets; /* The number of [break]s that want to be
* targeted to the place where this loop
* exception will be bound to. */
| | > | | | | | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
* expansion within the loop. Not meaningful
* if there are no open expansions between the
* looping level and the point of jump
* issue. */
Tcl_Size numBreakTargets; /* The number of [break]s that want to be
* targeted to the place where this loop
* exception will be bound to. */
TCL_HASH_TYPE *breakTargets;/* The offsets of the INST_JUMP4 instructions
* issued by the [break]s that we must
* update. Note that resizing a jump (via
* TclFixupForwardJump) can cause the contents
* of this array to be updated. When
* numBreakTargets==0, this is NULL. */
Tcl_Size allocBreakTargets; /* The size of the breakTargets array. */
Tcl_Size numContinueTargets;/* The number of [continue]s that want to be
* targeted to the place where this loop
* exception will be bound to. */
TCL_HASH_TYPE *continueTargets;
/* The offsets of the INST_JUMP4 instructions
* issued by the [continue]s that we must
* update. Note that resizing a jump (via
* TclFixupForwardJump) can cause the contents
* of this array to be updated. When
* numContinueTargets==0, this is NULL. */
Tcl_Size allocContinueTargets;
/* The size of the continueTargets array. */
} ExceptionAux;
/*
* Structure used to map between instruction pc and source locations. It
* defines for each compiled Tcl command its code's starting offset and its
* source's starting offset and length. Note that the code offset increases
* monotonically: that is, the table is sorted in code offset order. The
* source offset is not monotonic.
*/
typedef struct {
Tcl_Size codeOffset; /* Offset of first byte of command code. */
Tcl_Size numCodeBytes; /* Number of bytes for command's code. */
Tcl_Size srcOffset; /* Offset of first char of the command. */
Tcl_Size numSrcBytes; /* Number of command source chars. */
} CmdLocation;
/*
* TIP #280
* Structure to record additional location information for byte code. This
* information is internal and not saved. i.e. tbcload'ed code will not have
* this information. It records the lines for all words of all commands found
* in the byte code. The association with a ByteCode structure BC is done
* through the 'lineBCPtr' HashTable in Interp, keyed by the address of BC.
* Also recorded is information coming from the context, i.e. type of the
* frame and associated information, like the path of a sourced file.
*/
typedef struct {
Tcl_Size srcOffset; /* Command location to find the entry. */
Tcl_Size nline; /* Number of words in the command */
Tcl_Size *line; /* Line information for all words in the
* command. */
Tcl_Size **next; /* Transient information used by the compiler
* for tracking of hidden continuation
* lines. */
} ECL;
typedef struct {
int type; /* Context type. */
Tcl_Size start; /* Starting line for compiled script. Needed
* for the extended recompile check in
* tclCompileObj. */
Tcl_Obj *path; /* Path of the sourced file the command is
* in. */
ECL *loc; /* Command word locations (lines). */
|
| ︙ | ︙ | |||
284 285 286 287 288 289 290 | * the AuxData structure. */ typedef void * (AuxDataDupProc) (void *clientData); typedef void (AuxDataFreeProc) (void *clientData); typedef void (AuxDataPrintProc) (void *clientData, Tcl_Obj *appendObj, struct ByteCode *codePtr, | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | * the AuxData structure. */ typedef void * (AuxDataDupProc) (void *clientData); typedef void (AuxDataFreeProc) (void *clientData); typedef void (AuxDataPrintProc) (void *clientData, Tcl_Obj *appendObj, struct ByteCode *codePtr, TCL_HASH_TYPE pcOffset); /* * We define a separate AuxDataType struct to hold type-related information * for the AuxData structure. This separation makes it possible for clients * outside of the TCL core to manipulate (in a limited fashion!) AuxData; for * example, it makes it possible to pickle and unpickle AuxData structs. */ |
| ︙ | ︙ | |||
379 380 381 382 383 384 385 |
* Indexed by the string representations of
* the literals. Used to avoid creating
* duplicate objects. */
unsigned char *codeStart; /* Points to the first byte of the code. */
unsigned char *codeNext; /* Points to next code array byte to use. */
unsigned char *codeEnd; /* Points just after the last allocated code
* array byte. */
| | > | < | > > > > > | > | > > > > | < < < < < < < < < < < < < < < < < < < < < | | | | > | | | | | > | < < < < < | < | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 |
* Indexed by the string representations of
* the literals. Used to avoid creating
* duplicate objects. */
unsigned char *codeStart; /* Points to the first byte of the code. */
unsigned char *codeNext; /* Points to next code array byte to use. */
unsigned char *codeEnd; /* Points just after the last allocated code
* array byte. */
int mallocedCodeArray; /* Set 1 if code array was expanded and
* codeStart points into the heap.*/
#if TCL_MAJOR_VERSION > 8
int mallocedExceptArray; /* 1 if ExceptionRange array was expanded and
* exceptArrayPtr points in heap, else 0. */
#endif
LiteralEntry *literalArrayPtr;
/* Points to start of LiteralEntry array. */
Tcl_Size literalArrayNext; /* Index of next free object array entry. */
Tcl_Size literalArrayEnd; /* Index just after last obj array entry. */
int mallocedLiteralArray; /* 1 if object array was expanded and objArray
* points into the heap, else 0. */
ExceptionRange *exceptArrayPtr;
/* Points to start of the ExceptionRange
* array. */
Tcl_Size exceptArrayNext; /* Next free ExceptionRange array index.
* exceptArrayNext is the number of ranges and
* (exceptArrayNext-1) is the index of the
* current range's array entry. */
Tcl_Size exceptArrayEnd; /* Index after the last ExceptionRange array
* entry. */
#if TCL_MAJOR_VERSION < 9
int mallocedExceptArray;
#endif
ExceptionAux *exceptAuxArrayPtr;
/* Array of information used to restore the
* state when processing BREAK/CONTINUE
* exceptions. Must be the same size as the
* exceptArrayPtr. */
CmdLocation *cmdMapPtr; /* Points to start of CmdLocation array.
* numCommands is the index of the next entry
* to use; (numCommands-1) is the entry index
* for the last command. */
Tcl_Size cmdMapEnd; /* Index after last CmdLocation entry. */
int mallocedCmdMap; /* 1 if command map array was expanded and
* cmdMapPtr points in the heap, else 0. */
#if TCL_MAJOR_VERSION > 8
int mallocedAuxDataArray; /* 1 if aux data array was expanded and
* auxDataArrayPtr points in heap else 0. */
#endif
AuxData *auxDataArrayPtr; /* Points to auxiliary data array start. */
Tcl_Size auxDataArrayNext; /* Next free compile aux data array index.
* auxDataArrayNext is the number of aux data
* items and (auxDataArrayNext-1) is index of
* current aux data array entry. */
Tcl_Size auxDataArrayEnd; /* Index after last aux data array entry. */
#if TCL_MAJOR_VERSION < 9
int mallocedAuxDataArray;
#endif
unsigned char staticCodeSpace[COMPILEENV_INIT_CODE_BYTES];
/* Initial storage for code. */
LiteralEntry staticLiteralSpace[COMPILEENV_INIT_NUM_OBJECTS];
/* Initial storage of LiteralEntry array. */
ExceptionRange staticExceptArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
/* Initial ExceptionRange array storage. */
ExceptionAux staticExAuxArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
/* Initial static except auxiliary info array
* storage. */
CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE];
/* Initial storage for cmd location map. */
AuxData staticAuxDataArraySpace[COMPILEENV_INIT_AUX_DATA_SIZE];
/* Initial storage for aux data array. */
/* TIP #280 */
ExtCmdLoc *extCmdMapPtr; /* Extended command location information for
* 'info frame'. */
Tcl_Size line; /* First line of the script, based on the
* invoking context, then the line of the
* command currently compiled. */
int atCmdStart; /* Flag to say whether an INST_START_CMD
* should be issued; they should never be
* issued repeatedly, as that is significantly
* inefficient. If set to 2, that instruction
* should not be issued at all (by the generic
* part of the command compiler). */
Tcl_Size expandCount; /* Number of INST_EXPAND_START instructions
* encountered that have not yet been paired
* with a corresponding
* INST_INVOKE_EXPANDED. */
Tcl_Size *clNext; /* If not NULL, it refers to the next slot in
* clLoc to check for an invisible
* continuation line. */
} CompileEnv;
/*
* The structure defining the bytecode instructions resulting from compiling a
* Tcl script. Note that this structure is variable length: a single heap
* object is allocated to hold the ByteCode structure immediately followed by
* the code bytes, the literal object array, the ExceptionRange array, the
* CmdLocation map, and the compilation AuxData array.
*/
/*
* A PRECOMPILED bytecode struct is one that was generated from a compiled
* image rather than implicitly compiled from source
*/
#define TCL_BYTECODE_PRECOMPILED 0x0001
/*
* When a bytecode is compiled, interp or namespace resolvers have not been
* applied yet: this is indicated by the TCL_BYTECODE_RESOLVE_VARS flag.
*/
#define TCL_BYTECODE_RESOLVE_VARS 0x0002
#define TCL_BYTECODE_RECOMPILE 0x0004
typedef struct ByteCode {
TclHandle interpHandle; /* Handle for interpreter containing the
* compiled code. Commands and their compile
* procs are specific to an interpreter so the
* code emitted will depend on the
* interpreter. */
|
| ︙ | ︙ | |||
600 601 602 603 604 605 606 |
* code deltas. Source lengths are always
* positive. This sequence is just after the
* last byte in the source delta sequence. */
LocalCache *localCachePtr; /* Pointer to the start of the cached variable
* names and initialisation data for local
* variables. */
#ifdef TCL_COMPILE_STATS
| | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
* code deltas. Source lengths are always
* positive. This sequence is just after the
* last byte in the source delta sequence. */
LocalCache *localCachePtr; /* Pointer to the start of the cached variable
* names and initialisation data for local
* variables. */
#ifdef TCL_COMPILE_STATS
Tcl_Time createTime; /* Absolute time when the ByteCode was
* created. */
#endif /* TCL_COMPILE_STATS */
} ByteCode;
#define ByteCodeSetInternalRep(objPtr, typePtr, codePtr) \
do { \
Tcl_ObjInternalRep ir; \
ir.twoPtrValue.ptr1 = (codePtr); \
ir.twoPtrValue.ptr2 = NULL; \
Tcl_StoreInternalRep((objPtr), (typePtr), &ir); \
} while (0)
#define ByteCodeGetInternalRep(objPtr, typePtr, codePtr) \
do { \
const Tcl_ObjInternalRep *irPtr; \
irPtr = TclFetchInternalRep((objPtr), (typePtr)); \
(codePtr) = irPtr ? (ByteCode*)irPtr->twoPtrValue.ptr1 : NULL; \
} while (0)
/*
* Opcodes for the Tcl bytecode instructions. These must correspond to the
* entries in the table of instruction descriptions, tclInstructionTable, in
* tclCompile.c. Also, the order and number of the expression opcodes (e.g.,
* INST_BITOR) must match the entries in the array operatorStrings in
* tclExecute.c.
*/
enum TclInstruction {
/* Opcodes 0 to 9 */
INST_DONE = 0,
INST_PUSH1,
INST_PUSH4,
INST_POP,
INST_DUP,
INST_STR_CONCAT1,
INST_INVOKE_STK1,
INST_INVOKE_STK4,
INST_EVAL_STK,
INST_EXPR_STK,
/* Opcodes 10 to 23 */
INST_LOAD_SCALAR1,
INST_LOAD_SCALAR4,
INST_LOAD_SCALAR_STK,
INST_LOAD_ARRAY1,
INST_LOAD_ARRAY4,
INST_LOAD_ARRAY_STK,
INST_LOAD_STK,
INST_STORE_SCALAR1,
INST_STORE_SCALAR4,
INST_STORE_SCALAR_STK,
INST_STORE_ARRAY1,
INST_STORE_ARRAY4,
INST_STORE_ARRAY_STK,
INST_STORE_STK,
/* Opcodes 24 to 33 */
INST_INCR_SCALAR1,
INST_INCR_SCALAR_STK,
INST_INCR_ARRAY1,
INST_INCR_ARRAY_STK,
INST_INCR_STK,
INST_INCR_SCALAR1_IMM,
INST_INCR_SCALAR_STK_IMM,
INST_INCR_ARRAY1_IMM,
INST_INCR_ARRAY_STK_IMM,
INST_INCR_STK_IMM,
/* Opcodes 34 to 39 */
INST_JUMP1,
INST_JUMP4,
INST_JUMP_TRUE1,
INST_JUMP_TRUE4,
INST_JUMP_FALSE1,
INST_JUMP_FALSE4,
/* Opcodes 42 to 64 */
INST_BITOR,
INST_BITXOR,
INST_BITAND,
INST_EQ,
INST_NEQ,
INST_LT,
INST_GT,
|
| ︙ | ︙ | |||
728 729 730 731 732 733 734 |
INST_MOD,
INST_UPLUS,
INST_UMINUS,
INST_BITNOT,
INST_LNOT,
INST_TRY_CVT_TO_NUMERIC,
| | | | | | | | | | | | | | | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
INST_MOD,
INST_UPLUS,
INST_UMINUS,
INST_BITNOT,
INST_LNOT,
INST_TRY_CVT_TO_NUMERIC,
/* Opcodes 65 to 66 */
INST_BREAK,
INST_CONTINUE,
/* Opcodes 69 to 72 */
INST_BEGIN_CATCH4,
INST_END_CATCH,
INST_PUSH_RESULT,
INST_PUSH_RETURN_CODE,
/* Opcodes 73 to 78 */
INST_STR_EQ,
INST_STR_NEQ,
INST_STR_CMP,
INST_STR_LEN,
INST_STR_INDEX,
INST_STR_MATCH,
/* Opcodes 79 to 81 */
INST_LIST,
INST_LIST_INDEX,
INST_LIST_LENGTH,
/* Opcodes 82 to 87 */
INST_APPEND_SCALAR1,
INST_APPEND_SCALAR4,
INST_APPEND_ARRAY1,
INST_APPEND_ARRAY4,
INST_APPEND_ARRAY_STK,
INST_APPEND_STK,
/* Opcodes 88 to 93 */
INST_LAPPEND_SCALAR1,
INST_LAPPEND_SCALAR4,
INST_LAPPEND_ARRAY1,
INST_LAPPEND_ARRAY4,
INST_LAPPEND_ARRAY_STK,
INST_LAPPEND_STK,
/* TIP #22 - LINDEX operator with flat arg list */
INST_LIST_INDEX_MULTI,
/*
|
| ︙ | ︙ | |||
846 847 848 849 850 851 852 |
INST_EXIST_SCALAR,
INST_EXIST_ARRAY,
INST_EXIST_ARRAY_STK,
INST_EXIST_STK,
/* For [subst] compilation */
INST_NOP,
| | | | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 |
INST_EXIST_SCALAR,
INST_EXIST_ARRAY,
INST_EXIST_ARRAY_STK,
INST_EXIST_STK,
/* For [subst] compilation */
INST_NOP,
INST_RETURN_CODE_BRANCH,
/* For [unset] compilation */
INST_UNSET_SCALAR,
INST_UNSET_ARRAY,
INST_UNSET_ARRAY_STK,
INST_UNSET_STK,
/* For [dict with], [dict exists], [dict create] and [dict merge] */
INST_DICT_EXPAND,
INST_DICT_RECOMBINE_STK,
|
| ︙ | ︙ | |||
871 872 873 874 875 876 877 |
INST_STR_FIND_LAST,
INST_STR_RANGE_IMM,
INST_STR_RANGE,
/* For operations to do with coroutines and other NRE-manipulators */
INST_YIELD,
INST_COROUTINE_NAME,
| | | | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
INST_STR_FIND_LAST,
INST_STR_RANGE_IMM,
INST_STR_RANGE,
/* For operations to do with coroutines and other NRE-manipulators */
INST_YIELD,
INST_COROUTINE_NAME,
INST_TAILCALL,
/* For compilation of basic information operations */
INST_NS_CURRENT,
INST_INFO_LEVEL_NUM,
INST_INFO_LEVEL_ARGS,
INST_RESOLVE_COMMAND,
/* For compilation relating to TclOO */
INST_TCLOO_SELF,
INST_TCLOO_CLASS,
|
| ︙ | ︙ | |||
917 918 919 920 921 922 923 |
INST_STR_UPPER,
INST_STR_LOWER,
INST_STR_TITLE,
INST_STR_REPLACE,
INST_ORIGIN_COMMAND,
| | | | | < < < < < < < < < < < < < < < < < < < < < < < < | 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 |
INST_STR_UPPER,
INST_STR_LOWER,
INST_STR_TITLE,
INST_STR_REPLACE,
INST_ORIGIN_COMMAND,
INST_TCLOO_NEXT,
INST_TCLOO_NEXT_CLASS,
INST_YIELD_TO_INVOKE,
INST_NUM_TYPE,
INST_TRY_CVT_TO_BOOLEAN,
INST_STR_CLASS,
INST_LAPPEND_LIST,
INST_LAPPEND_LIST_ARRAY,
INST_LAPPEND_LIST_ARRAY_STK,
INST_LAPPEND_LIST_STK,
INST_CLOCK_READ,
INST_DICT_GET_DEF,
/* TIP 461 */
INST_STR_LT,
INST_STR_GT,
INST_STR_LE,
INST_STR_GE,
INST_LREPLACE4,
/* TIP 667: const */
INST_CONST_IMM,
INST_CONST_STK,
/* The last opcode */
LAST_INST_OPCODE
};
/*
* Table describing the Tcl bytecode instructions: their name (for displaying
* code), total number of code bytes required (including operand bytes), and a
|
| ︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 |
* table. */
OPERAND_OFFSET1, /* One byte signed jump offset. */
OPERAND_OFFSET4, /* Four byte signed jump offset. */
OPERAND_LIT1, /* One byte unsigned index into table of
* literals. */
OPERAND_LIT4, /* Four byte unsigned index into table of
* literals. */
| | < < < | 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 |
* table. */
OPERAND_OFFSET1, /* One byte signed jump offset. */
OPERAND_OFFSET4, /* Four byte signed jump offset. */
OPERAND_LIT1, /* One byte unsigned index into table of
* literals. */
OPERAND_LIT4, /* Four byte unsigned index into table of
* literals. */
OPERAND_SCLS1 /* Index into tclStringClassTable. */
} InstOperandType;
typedef struct InstructionDesc {
const char *name; /* Name of instruction. */
int numBytes; /* Total number of bytes for instruction. */
int stackEffect; /* The worst-case balance stack effect of the
* instruction, used for stack requirements
|
| ︙ | ︙ | |||
1103 1104 1105 1106 1107 1108 1109 |
#define JUMPFIXUP_INIT_ENTRIES 10
typedef struct JumpFixupArray {
JumpFixup *fixup; /* Points to start of jump fixup array. */
Tcl_Size next; /* Index of next free array entry. */
Tcl_Size end; /* Index of last usable entry in array. */
| | | | | | | < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | > | | < < | | | > > | | | | > | < | | | | < < | | | | | > < < < | < < | < < | < | < < < | | | 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 |
#define JUMPFIXUP_INIT_ENTRIES 10
typedef struct JumpFixupArray {
JumpFixup *fixup; /* Points to start of jump fixup array. */
Tcl_Size next; /* Index of next free array entry. */
Tcl_Size end; /* Index of last usable entry in array. */
int mallocedArray; /* 1 if array was expanded and fixups points
* into the heap, else 0. */
JumpFixup staticFixupSpace[JUMPFIXUP_INIT_ENTRIES];
/* Initial storage for jump fixup array. */
} JumpFixupArray;
/*
* The structure describing one variable list of a foreach command. Note that
* only foreach commands inside procedure bodies are compiled inline so a
* ForeachVarList structure always describes local variables. Furthermore,
* only scalar variables are supported for inline-compiled foreach loops.
*/
typedef struct ForeachVarList {
Tcl_Size numVars; /* The number of variables in the list. */
Tcl_Size varIndexes[TCLFLEXARRAY];
/* An array of the indexes ("slot numbers")
* for each variable in the procedure's array
* of local variables. Only scalar variables
* are supported. The actual size of this
* field will be large enough to numVars
* indexes. THIS MUST BE THE LAST FIELD IN THE
* STRUCTURE! */
} ForeachVarList;
/*
* Structure used to hold information about a foreach command that is needed
* during program execution. These structures are stored in CompileEnv and
* ByteCode structures as auxiliary data.
*/
typedef struct ForeachInfo {
Tcl_Size numLists; /* The number of both the variable and value
* lists of the foreach command. */
Tcl_Size firstValueTemp; /* Index of the first temp var in a proc frame
* used to point to a value list. */
Tcl_Size loopCtTemp; /* Index of temp var in a proc frame holding
* the loop's iteration count. Used to
* determine next value list element to assign
* each loop var. */
ForeachVarList *varLists[TCLFLEXARRAY];
/* An array of pointers to ForeachVarList
* structures describing each var list. The
* actual size of this field will be large
* enough to numVars indexes. THIS MUST BE THE
* LAST FIELD IN THE STRUCTURE! */
} ForeachInfo;
/*
* Structure used to hold information about a switch command that is needed
* during program execution. These structures are stored in CompileEnv and
* ByteCode structures as auxiliary data.
*/
typedef struct JumptableInfo {
Tcl_HashTable hashTable; /* Hash that maps strings to signed ints (PC
* offsets). */
} JumptableInfo;
MODULE_SCOPE const AuxDataType tclJumptableInfoType;
#define JUMPTABLEINFO(envPtr, index) \
((JumptableInfo*)((envPtr)->auxDataArrayPtr[TclGetUInt4AtPtr(index)].clientData))
/*
* Structure used to hold information about a [dict update] command that is
* needed during program execution. These structures are stored in CompileEnv
* and ByteCode structures as auxiliary data.
*/
typedef struct {
Tcl_Size length; /* Size of array */
Tcl_Size varIndices[TCLFLEXARRAY];
/* Array of variable indices to manage when
* processing the start and end of a [dict
* update]. There is really more than one
* entry, and the structure is allocated to
* take account of this. MUST BE LAST FIELD IN
* STRUCTURE. */
} DictUpdateInfo;
/*
* ClientData type used by the math operator commands.
*/
typedef struct {
const char *op; /* Do not call it 'operator': C++ reserved */
const char *expected;
union {
int numArgs;
int identity;
} i;
} TclOpCmdClientData;
/*
*----------------------------------------------------------------
* Procedures exported by tclBasic.c to be used within the engine.
*----------------------------------------------------------------
*/
#if TCL_MAJOR_VERSION > 8
MODULE_SCOPE Tcl_ObjCmdProc TclNRInterpCoroutine;
/*
*----------------------------------------------------------------
* Procedures exported by the engine to be used by tclBasic.c
*----------------------------------------------------------------
*/
MODULE_SCOPE ByteCode * TclCompileObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
const CmdFrame *invoker, int word);
/*
*----------------------------------------------------------------
* Procedures shared among Tcl bytecode compilation and execution modules but
* not used outside:
*----------------------------------------------------------------
*/
MODULE_SCOPE int TclAttemptCompileProc(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Tcl_Size depth, Command *cmdPtr,
CompileEnv *envPtr);
MODULE_SCOPE void TclCleanupStackForBreakContinue(CompileEnv *envPtr,
ExceptionAux *auxPtr);
MODULE_SCOPE void TclCompileCmdWord(Tcl_Interp *interp,
Tcl_Token *tokenPtr, Tcl_Size count,
CompileEnv *envPtr);
MODULE_SCOPE void TclCompileExpr(Tcl_Interp *interp, const char *script,
Tcl_Size numBytes, CompileEnv *envPtr, int optimize);
MODULE_SCOPE void TclCompileExprWords(Tcl_Interp *interp,
Tcl_Token *tokenPtr, size_t numWords,
CompileEnv *envPtr);
MODULE_SCOPE void TclCompileInvocation(Tcl_Interp *interp,
Tcl_Token *tokenPtr, Tcl_Obj *cmdObj, size_t numWords,
CompileEnv *envPtr);
MODULE_SCOPE void TclCompileScript(Tcl_Interp *interp,
const char *script, Tcl_Size numBytes,
CompileEnv *envPtr);
MODULE_SCOPE void TclCompileSyntaxError(Tcl_Interp *interp,
CompileEnv *envPtr);
MODULE_SCOPE void TclCompileTokens(Tcl_Interp *interp,
Tcl_Token *tokenPtr, Tcl_Size count,
CompileEnv *envPtr);
MODULE_SCOPE void TclCompileVarSubst(Tcl_Interp *interp,
Tcl_Token *tokenPtr, CompileEnv *envPtr);
MODULE_SCOPE Tcl_Size TclCreateAuxData(void *clientData,
const AuxDataType *typePtr, CompileEnv *envPtr);
MODULE_SCOPE Tcl_Size TclCreateExceptRange(ExceptionRangeType type,
CompileEnv *envPtr);
MODULE_SCOPE ExecEnv * TclCreateExecEnv(Tcl_Interp *interp, size_t size);
MODULE_SCOPE Tcl_Obj * TclCreateLiteral(Interp *iPtr, const char *bytes,
Tcl_Size length, size_t hash, int *newPtr,
Namespace *nsPtr, int flags,
LiteralEntry **globalPtrPtr);
MODULE_SCOPE void TclDeleteExecEnv(ExecEnv *eePtr);
MODULE_SCOPE void TclDeleteLiteralTable(Tcl_Interp *interp,
LiteralTable *tablePtr);
MODULE_SCOPE void TclEmitForwardJump(CompileEnv *envPtr,
TclJumpType jumpType, JumpFixup *jumpFixupPtr);
MODULE_SCOPE void TclEmitInvoke(CompileEnv *envPtr, int opcode, ...);
MODULE_SCOPE ExceptionRange * TclGetExceptionRangeForPc(unsigned char *pc,
int catchOnly, ByteCode *codePtr);
MODULE_SCOPE void TclExpandJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE int TclNRExecuteByteCode(Tcl_Interp *interp,
ByteCode *codePtr);
MODULE_SCOPE Tcl_Obj * TclFetchLiteral(CompileEnv *envPtr, Tcl_Size index);
MODULE_SCOPE Tcl_Size TclFindCompiledLocal(const char *name, Tcl_Size nameChars,
int create, CompileEnv *envPtr);
MODULE_SCOPE int TclFixupForwardJump(CompileEnv *envPtr,
JumpFixup *jumpFixupPtr, int jumpDist,
int distThreshold);
MODULE_SCOPE void TclFreeCompileEnv(CompileEnv *envPtr);
MODULE_SCOPE void TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE int TclGetIndexFromToken(Tcl_Token *tokenPtr,
size_t before, size_t after, int *indexPtr);
MODULE_SCOPE ByteCode * TclInitByteCode(CompileEnv *envPtr);
MODULE_SCOPE ByteCode * TclInitByteCodeObj(Tcl_Obj *objPtr,
const Tcl_ObjType *typePtr, CompileEnv *envPtr);
MODULE_SCOPE void TclInitCompileEnv(Tcl_Interp *interp,
CompileEnv *envPtr, const char *string,
size_t numBytes, const CmdFrame *invoker, int word);
MODULE_SCOPE void TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE void TclInitLiteralTable(LiteralTable *tablePtr);
MODULE_SCOPE ExceptionRange *TclGetInnermostExceptionRange(CompileEnv *envPtr,
int returnCode, ExceptionAux **auxPtrPtr);
MODULE_SCOPE void TclAddLoopBreakFixup(CompileEnv *envPtr,
ExceptionAux *auxPtr);
MODULE_SCOPE void TclAddLoopContinueFixup(CompileEnv *envPtr,
ExceptionAux *auxPtr);
MODULE_SCOPE void TclFinalizeLoopExceptionRange(CompileEnv *envPtr,
int range);
#ifdef TCL_COMPILE_STATS
MODULE_SCOPE char * TclLiteralStats(LiteralTable *tablePtr);
MODULE_SCOPE int TclLog2(long long value);
#endif
MODULE_SCOPE size_t TclLocalScalar(const char *bytes, size_t numBytes,
CompileEnv *envPtr);
MODULE_SCOPE size_t TclLocalScalarFromToken(Tcl_Token *tokenPtr,
CompileEnv *envPtr);
MODULE_SCOPE void TclOptimizeBytecode(void *envPtr);
#ifdef TCL_COMPILE_DEBUG
MODULE_SCOPE void TclDebugPrintByteCodeObj(Tcl_Obj *objPtr);
#else
#define TclDebugPrintByteCodeObj(objPtr) (void)(objPtr)
#endif
MODULE_SCOPE int TclPrintInstruction(ByteCode *codePtr,
const unsigned char *pc);
MODULE_SCOPE void TclPrintObject(FILE *outFile,
Tcl_Obj *objPtr, Tcl_Size maxChars);
MODULE_SCOPE void TclPrintSource(FILE *outFile,
const char *string, Tcl_Size maxChars);
MODULE_SCOPE void TclPushVarName(Tcl_Interp *interp,
Tcl_Token *varTokenPtr, CompileEnv *envPtr,
int flags, int *localIndexPtr,
int *isScalarPtr);
MODULE_SCOPE void TclPreserveByteCode(ByteCode *codePtr);
MODULE_SCOPE void TclReleaseByteCode(ByteCode *codePtr);
MODULE_SCOPE void TclReleaseLiteral(Tcl_Interp *interp, Tcl_Obj *objPtr);
MODULE_SCOPE void TclInvalidateCmdLiteral(Tcl_Interp *interp,
const char *name, Namespace *nsPtr);
MODULE_SCOPE Tcl_ObjCmdProc TclSingleOpCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclSortingOpCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclVariadicOpCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNoIdentOpCmd;
#ifdef TCL_COMPILE_DEBUG
MODULE_SCOPE void TclVerifyGlobalLiteralTable(Interp *iPtr);
MODULE_SCOPE void TclVerifyLocalLiteralTable(CompileEnv *envPtr);
#endif
MODULE_SCOPE int TclWordKnownAtCompileTime(Tcl_Token *tokenPtr,
Tcl_Obj *valuePtr);
MODULE_SCOPE void TclLogCommandInfo(Tcl_Interp *interp,
const char *script, const char *command,
Tcl_Size length, const unsigned char *pc,
Tcl_Obj **tosPtr);
MODULE_SCOPE Tcl_Obj * TclGetInnerContext(Tcl_Interp *interp,
const unsigned char *pc, Tcl_Obj **tosPtr);
MODULE_SCOPE Tcl_Obj * TclNewInstNameObj(unsigned char inst);
MODULE_SCOPE int TclPushProcCallFrame(void *clientData,
Tcl_Interp *interp, Tcl_Size objc,
Tcl_Obj *const objv[], int isLambda);
#endif /* TCL_MAJOR_VERSION > 8 */
/*
*----------------------------------------------------------------
* Macros and flag values used by Tcl bytecode compilation and execution
* modules inside the Tcl core but not used outside.
*----------------------------------------------------------------
*/
/*
* Simplified form to access AuxData.
*
* void *TclFetchAuxData(CompileEng *envPtr, int index);
*/
#define TclFetchAuxData(envPtr, index) \
(envPtr)->auxDataArrayPtr[(index)].clientData
#define LITERAL_ON_HEAP 0x01
#define LITERAL_CMD_NAME 0x02
#define LITERAL_UNSHARED 0x04
/*
* Adjust the stack requirements. Manually used in cases where the stack
* effect cannot be computed from the opcode and its operands, but is still
* known at compile time.
*/
static inline void
TclAdjustStackDepth(
int delta,
CompileEnv *envPtr)
{
if (delta < 0) {
if ((int) envPtr->maxStackDepth < (int) envPtr->currStackDepth) {
envPtr->maxStackDepth = envPtr->currStackDepth;
}
}
envPtr->currStackDepth += delta;
}
#define TclGetStackDepth(envPtr) \
|
| ︙ | ︙ | |||
1482 1483 1484 1485 1486 1487 1488 |
"is %" TCL_Z_MODIFIER "u, should be %" TCL_Z_MODIFIER "u",
(size_t) envPtr->currStackDepth, depth);
}
}
/*
* Update the stack requirements based on the instruction definition. It is
| | | | < < < | > | < < > > > | | < < < < < < < < < < < < < < < < < < < < < | < < < | | | < | > > > < | < < | | | < | | < | | | | < | | < | < | < < < < | < | < | < < < < < | | < | | < < < > | > > | > > > > > > > > > > | | < < | < < < < < < < < < | < < < < < < < < < < < < < < | > > | > > | | < | | < < < < < | | | > | < | < < < < < < < | | < | | < | < > | | | > | | | | > | > > > > > | < < < < < | > | < | < | < < < < < < < < | < < < | < | < < < < < < < < | | < < < < < < < < < < | < < | < > > | < < | < | > > < < | < < < < < < < < < < | < | | < < | < | < < | | < < < | < < < | > | | | | | | < | > | < | > | | < > | | < < < < | | > | | < < < < < < < < < | < < < | | | | | | | | < < < | | | | < | | > > > > > > > > > > > > < | | | > > > > | | > > | | | | < > > > > > > | > > | < | < < < < < | | | | < < < < < | < < < | | | < < < < < | < < | | < | | | < < < < < < | | < | < | | | < > > > > | > | > > > | > > > > < < < | | | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 |
"is %" TCL_Z_MODIFIER "u, should be %" TCL_Z_MODIFIER "u",
(size_t) envPtr->currStackDepth, depth);
}
}
/*
* Update the stack requirements based on the instruction definition. It is
* called by the macros TclEmitOpCode, TclEmitInst1 and TclEmitInst4.
* Remark that the very last instruction of a bytecode always reduces the
* stack level: INST_DONE or INST_POP, so that the maxStackdepth is always
* updated.
*/
static inline void
TclUpdateStackReqs(
unsigned char op,
int i,
CompileEnv *envPtr)
{
int delta = tclInstructionTable[op].stackEffect;
if (delta) {
if (delta == INT_MIN) {
delta = 1 - i;
}
TclAdjustStackDepth(delta, envPtr);
}
}
/*
* Macros used to update the flag that indicates if we are at the start of a
* command, based on whether the opcode is INST_START_COMMAND.
*
* void TclUpdateAtCmdStart(unsigned char op, CompileEnv *envPtr);
*/
#define TclUpdateAtCmdStart(op, envPtr) \
if ((envPtr)->atCmdStart < 2) { \
(envPtr)->atCmdStart = ((op) == INST_START_CMD ? 1 : 0); \
}
/*
* Macro to emit an opcode byte into a CompileEnv's code array. The ANSI C
* "prototype" for this macro is:
*
* void TclEmitOpcode(unsigned char op, CompileEnv *envPtr);
*/
#define TclEmitOpcode(op, envPtr) \
do { \
if ((envPtr)->codeNext == (envPtr)->codeEnd) { \
TclExpandCodeArray(envPtr); \
} \
*(envPtr)->codeNext++ = (unsigned char) (op); \
TclUpdateAtCmdStart(op, envPtr); \
TclUpdateStackReqs(op, 0, envPtr); \
} while (0)
/*
* Macros to emit an integer operand. The ANSI C "prototype" for these macros
* are:
*
* void TclEmitInt1(int i, CompileEnv *envPtr);
* void TclEmitInt4(int i, CompileEnv *envPtr);
*/
#define TclEmitInt1(i, envPtr) \
do { \
if ((envPtr)->codeNext == (envPtr)->codeEnd) { \
TclExpandCodeArray(envPtr); \
} \
*(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i)); \
} while (0)
#define TclEmitInt4(i, envPtr) \
do { \
if (((envPtr)->codeNext + 4) > (envPtr)->codeEnd) { \
TclExpandCodeArray(envPtr); \
} \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) >> 24); \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) >> 16); \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) >> 8); \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) ); \
} while (0)
/*
* Macros to emit an instruction with signed or unsigned integer operands.
* Four byte integers are stored in "big-endian" order with the high order
* byte stored at the lowest address. The ANSI C "prototypes" for these macros
* are:
*
* void TclEmitInstInt1(unsigned char op, int i, CompileEnv *envPtr);
* void TclEmitInstInt4(unsigned char op, int i, CompileEnv *envPtr);
*/
#define TclEmitInstInt1(op, i, envPtr) \
do { \
if (((envPtr)->codeNext + 2) > (envPtr)->codeEnd) { \
TclExpandCodeArray(envPtr); \
} \
*(envPtr)->codeNext++ = (unsigned char) (op); \
*(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i)); \
TclUpdateAtCmdStart(op, envPtr); \
TclUpdateStackReqs(op, i, envPtr); \
} while (0)
#define TclEmitInstInt4(op, i, envPtr) \
do { \
if (((envPtr)->codeNext + 5) > (envPtr)->codeEnd) { \
TclExpandCodeArray(envPtr); \
} \
*(envPtr)->codeNext++ = (unsigned char) (op); \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) >> 24); \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) >> 16); \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) >> 8); \
*(envPtr)->codeNext++ = \
(unsigned char) ((unsigned int) (i) ); \
TclUpdateAtCmdStart(op, envPtr); \
TclUpdateStackReqs(op, i, envPtr); \
} while (0)
/*
* Macro to push a Tcl object onto the Tcl evaluation stack. It emits the
* object's one or four byte array index into the CompileEnv's code array.
* These support, respectively, a maximum of 256 (2**8) and 2**32 objects in a
* CompileEnv. The ANSI C "prototype" for this macro is:
*
* void TclEmitPush(int objIndex, CompileEnv *envPtr);
*/
#define TclEmitPush(objIndex, envPtr) \
do { \
int _objIndexCopy = (objIndex); \
if (_objIndexCopy <= 255) { \
TclEmitInstInt1(INST_PUSH1, _objIndexCopy, (envPtr)); \
} else { \
TclEmitInstInt4(INST_PUSH4, _objIndexCopy, (envPtr)); \
} \
} while (0)
/*
* Macros to update a (signed or unsigned) integer starting at a pointer. The
* two variants depend on the number of bytes. The ANSI C "prototypes" for
* these macros are:
*
* void TclStoreInt1AtPtr(int i, unsigned char *p);
* void TclStoreInt4AtPtr(int i, unsigned char *p);
*/
#define TclStoreInt1AtPtr(i, p) \
*(p) = (unsigned char) ((unsigned int) (i))
#define TclStoreInt4AtPtr(i, p) \
do { \
*(p) = (unsigned char) ((unsigned int) (i) >> 24); \
*(p+1) = (unsigned char) ((unsigned int) (i) >> 16); \
*(p+2) = (unsigned char) ((unsigned int) (i) >> 8); \
*(p+3) = (unsigned char) ((unsigned int) (i) ); \
} while (0)
/*
* Macros to update instructions at a particular pc with a new op code and a
* (signed or unsigned) int operand. The ANSI C "prototypes" for these macros
* are:
*
* void TclUpdateInstInt1AtPc(unsigned char op, int i, unsigned char *pc);
* void TclUpdateInstInt4AtPc(unsigned char op, int i, unsigned char *pc);
*/
#define TclUpdateInstInt1AtPc(op, i, pc) \
do { \
*(pc) = (unsigned char) (op); \
TclStoreInt1AtPtr((i), ((pc)+1)); \
} while (0)
#define TclUpdateInstInt4AtPc(op, i, pc) \
do { \
*(pc) = (unsigned char) (op); \
TclStoreInt4AtPtr((i), ((pc)+1)); \
} while (0)
/*
* Macro to fix up a forward jump to point to the current code-generation
* position in the bytecode being created (the most common case). The ANSI C
* "prototypes" for this macro is:
*
* int TclFixupForwardJumpToHere(CompileEnv *envPtr, JumpFixup *fixupPtr,
* int threshold);
*/
#define TclFixupForwardJumpToHere(envPtr, fixupPtr, threshold) \
TclFixupForwardJump((envPtr), (fixupPtr), \
(envPtr)->codeNext-(envPtr)->codeStart-(int)(fixupPtr)->codeOffset, \
(threshold))
/*
* Macros to get a signed integer (GET_INT{1,2}) or an unsigned int
* (GET_UINT{1,2}) from a pointer. There are two variants for each return type
* that depend on the number of bytes fetched. The ANSI C "prototypes" for
* these macros are:
*
* int TclGetInt1AtPtr(unsigned char *p);
* int TclGetInt4AtPtr(unsigned char *p);
* unsigned int TclGetUInt1AtPtr(unsigned char *p);
* unsigned int TclGetUInt4AtPtr(unsigned char *p);
*/
/*
* The TclGetInt1AtPtr macro is tricky because we want to do sign extension on
* the 1-byte value. Unfortunately the "char" type isn't signed on all
* platforms so sign-extension doesn't always happen automatically. Sometimes
* we can explicitly declare the pointer to be signed, but other times we have
* to explicitly sign-extend the value in software.
*/
#ifndef __CHAR_UNSIGNED__
# define TclGetInt1AtPtr(p) ((int) *((char *) p))
#elif defined(HAVE_SIGNED_CHAR)
# define TclGetInt1AtPtr(p) ((int) *((signed char *) p))
#else
# define TclGetInt1AtPtr(p) \
((int) ((*((char *) p)) | ((*(p) & 0200) ? (-256) : 0)))
#endif
#define TclGetInt4AtPtr(p) \
((int) ((TclGetUInt1AtPtr(p) << 24) | \
(*((p)+1) << 16) | \
(*((p)+2) << 8) | \
(*((p)+3))))
#define TclGetUInt1AtPtr(p) \
((unsigned int) *(p))
#define TclGetUInt4AtPtr(p) \
((unsigned int) ((*(p) << 24) | \
(*((p)+1) << 16) | \
(*((p)+2) << 8) | \
(*((p)+3))))
/*
* Macros used to compute the minimum and maximum of two values. The ANSI C
* "prototypes" for these macros are:
*
* size_t TclMin(size_t i, size_t j);
* size_t TclMax(size_t i, size_t j);
*/
#define TclMin(i, j) ((((size_t) i) + 1 < ((size_t) j) + 1 )? (i) : (j))
#define TclMax(i, j) ((((size_t) i) + 1 > ((size_t) j) + 1 )? (i) : (j))
/*
* Convenience macros for use when compiling bodies of commands. The ANSI C
* "prototype" for these macros are:
*
* static void BODY(Tcl_Token *tokenPtr, int word);
*/
#define BODY(tokenPtr, word) \
SetLineInformation((word)); \
TclCompileCmdWord(interp, (tokenPtr)+1, (tokenPtr)->numComponents, \
envPtr)
/*
* Convenience macro for use when compiling tokens to be pushed. The ANSI C
* "prototype" for this macro is:
*
* static void CompileTokens(CompileEnv *envPtr, Tcl_Token *tokenPtr,
* Tcl_Interp *interp);
*/
#define CompileTokens(envPtr, tokenPtr, interp) \
TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \
(envPtr));
/*
* Convenience macros for use when pushing literals. The ANSI C "prototype" for
* these macros are:
*
* static void PushLiteral(CompileEnv *envPtr,
* const char *string, Tcl_Size length);
* static void PushStringLiteral(CompileEnv *envPtr,
* const char *string);
*/
#define PushLiteral(envPtr, string, length) \
TclEmitPush(TclRegisterLiteral((envPtr), (string), (length), 0), (envPtr))
#define PushStringLiteral(envPtr, string) \
PushLiteral((envPtr), (string), sizeof(string "") - 1)
/*
* Macro to advance to the next token; it is more mnemonic than the address
* arithmetic that it replaces. The ANSI C "prototype" for this macro is:
*
* static Tcl_Token * TokenAfter(Tcl_Token *tokenPtr);
*/
#define TokenAfter(tokenPtr) \
((tokenPtr) + ((tokenPtr)->numComponents + 1))
/*
* Macro to get the offset to the next instruction to be issued. The ANSI C
* "prototype" for this macro is:
*
* static ptrdiff_t CurrentOffset(CompileEnv *envPtr);
*/
#define CurrentOffset(envPtr) \
((envPtr)->codeNext - (envPtr)->codeStart)
/*
* Note: the exceptDepth is a bit of a misnomer: TEBC only needs the
* maximal depth of nested CATCH ranges in order to alloc runtime
* memory. These macros should compute precisely that? OTOH, the nesting depth
* of LOOP ranges is an interesting datum for debugging purposes, and that is
* what we compute now.
*
* static int ExceptionRangeStarts(CompileEnv *envPtr, Tcl_Size index);
* static void ExceptionRangeEnds(CompileEnv *envPtr, Tcl_Size index);
* static void ExceptionRangeTarget(CompileEnv *envPtr, Tcl_Size index, LABEL);
*/
#define ExceptionRangeStarts(envPtr, index) \
(((envPtr)->exceptDepth++), \
((envPtr)->maxExceptDepth = \
TclMax((envPtr)->exceptDepth, (envPtr)->maxExceptDepth)), \
((envPtr)->exceptArrayPtr[(index)].codeOffset = CurrentOffset(envPtr)))
#define ExceptionRangeEnds(envPtr, index) \
(((envPtr)->exceptDepth--), \
((envPtr)->exceptArrayPtr[(index)].numCodeBytes = \
CurrentOffset(envPtr) - (int)(envPtr)->exceptArrayPtr[(index)].codeOffset))
#define ExceptionRangeTarget(envPtr, index, targetType) \
((envPtr)->exceptArrayPtr[(index)].targetType = CurrentOffset(envPtr))
/*
* Check if there is an LVT for compiled locals
*/
#define EnvHasLVT(envPtr) \
(envPtr->procPtr || envPtr->iPtr->varFramePtr->localCachePtr)
/*
* Macros for making it easier to deal with tokens and DStrings.
*/
#define TclDStringAppendToken(dsPtr, tokenPtr) \
Tcl_DStringAppend((dsPtr), (tokenPtr)->start, (tokenPtr)->size)
#define TclRegisterDStringLiteral(envPtr, dsPtr) \
TclRegisterLiteral(envPtr, Tcl_DStringValue(dsPtr), \
Tcl_DStringLength(dsPtr), /*flags*/ 0)
/*
* Macro that encapsulates an efficiency trick that avoids a function call for
* the simplest of compiles. The ANSI C "prototype" for this macro is:
*
* static void CompileWord(CompileEnv *envPtr, Tcl_Token *tokenPtr,
* Tcl_Interp *interp, int word);
*/
#define CompileWord(envPtr, tokenPtr, interp, word) \
if ((tokenPtr)->type == TCL_TOKEN_SIMPLE_WORD) { \
PushLiteral((envPtr), (tokenPtr)[1].start, (tokenPtr)[1].size); \
} else { \
SetLineInformation((word)); \
CompileTokens((envPtr), (tokenPtr), (interp)); \
}
/*
* TIP #280: Remember the per-word line information of the current command. An
* index is used instead of a pointer as recursive compilation may reallocate,
* i.e. move, the array. This is also the reason to save the nuloc now, it may
* change during the course of the function.
*
* Macro to encapsulate the variable definition and setup.
*/
#define DefineLineInformation \
ExtCmdLoc *mapPtr = envPtr->extCmdMapPtr; \
Tcl_Size eclIndex = mapPtr->nuloc - 1
#define SetLineInformation(word) \
envPtr->line = mapPtr->loc[eclIndex].line[(word)]; \
envPtr->clNext = mapPtr->loc[eclIndex].next[(word)]
#define PushVarNameWord(i,v,e,f,l,sc,word) \
SetLineInformation(word); \
TclPushVarName(i,v,e,f,l,sc)
/*
* Often want to issue one of two versions of an instruction based on whether
* the argument will fit in a single byte or not. This makes it much clearer.
*/
#define Emit14Inst(nm,idx,envPtr) \
if (idx <= 255) { \
TclEmitInstInt1(nm##1,idx,envPtr); \
} else { \
TclEmitInstInt4(nm##4,idx,envPtr); \
}
/*
* How to get an anonymous local variable (used for holding temporary values
* off the stack) or a local simple scalar.
*/
#define AnonymousLocal(envPtr) \
(TclFindCompiledLocal(NULL, /*nameChars*/ 0, /*create*/ 1, (envPtr)))
#define LocalScalar(chars,len,envPtr) \
TclLocalScalar(chars, len, envPtr)
#define LocalScalarFromToken(tokenPtr,envPtr) \
TclLocalScalarFromToken(tokenPtr, envPtr)
/*
* Flags bits used by TclPushVarName.
*/
#define TCL_NO_LARGE_INDEX 1 /* Do not return localIndex value > 255 */
#define TCL_NO_ELEMENT 2 /* Do not push the array element. */
/*
* Flags bits used by lreplace4 instruction
*/
#define TCL_LREPLACE4_END_IS_LAST 1 /* "end" refers to last element */
#define TCL_LREPLACE4_SINGLE_INDEX 2 /* Second index absent (pure insert) */
/*
* DTrace probe macros (NOPs if DTrace support is not enabled).
*/
/*
* Define the following macros to enable debug logging of the DTrace proc,
* cmd, and inst probes. Note that this does _not_ require a platform with
|
| ︙ | ︙ | |||
2366 2367 2368 2369 2370 2371 2372 |
tclDTraceDebugLog = fopen(n, "a"); \
}
#define TclDTraceDbgMsg(p, m, ...) \
do { \
if (tclDTraceDebugEnabled) { \
int _l, _t = 0; \
| | < < | 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 |
tclDTraceDebugLog = fopen(n, "a"); \
}
#define TclDTraceDbgMsg(p, m, ...) \
do { \
if (tclDTraceDebugEnabled) { \
int _l, _t = 0; \
if (!tclDTraceDebugLog) { TclDTraceOpenDebugLog(); } \
fprintf(tclDTraceDebugLog, "%.12s:%.4d:%n", \
strrchr(__FILE__, '/')+1, __LINE__, &_l); _t += _l; \
fprintf(tclDTraceDebugLog, " %.*s():%n", \
(_t < 18 ? 18 - _t : 0) + 18, __func__, &_l); _t += _l; \
fprintf(tclDTraceDebugLog, "%*s" p "%n", \
(_t < 40 ? 40 - _t : 0) + 2 * tclDTraceDebugIndent, \
"", &_l); _t += _l; \
|
| ︙ | ︙ |
Changes to generic/tclConfig.c.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 |
char *encoding;
} QCCD;
/*
* Static functions in this file:
*/
| | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
char *encoding;
} QCCD;
/*
* Static functions in this file:
*/
static Tcl_ObjCmdProc QueryConfigObjCmd;
static Tcl_CmdDeleteProc QueryConfigDelete;
static Tcl_InterpDeleteProc ConfigDictDeleteProc;
static Tcl_Obj * GetConfigDict(Tcl_Interp *interp);
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
159 160 161 162 163 164 165 |
Tcl_GetStringResult(interp), "Tcl_RegisterConfig",
"Unable to create namespace for package configuration.");
}
}
TclDStringAppendLiteral(&cmdName, "::pkgconfig");
| | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
Tcl_GetStringResult(interp), "Tcl_RegisterConfig",
"Unable to create namespace for package configuration.");
}
}
TclDStringAppendLiteral(&cmdName, "::pkgconfig");
if (Tcl_CreateObjCommand(interp, Tcl_DStringValue(&cmdName),
QueryConfigObjCmd, cdPtr, QueryConfigDelete) == NULL) {
Tcl_Panic("%s: %s", "Tcl_RegisterConfig",
"Unable to create query command for package configuration");
}
Tcl_DStringFree(&cmdName);
}
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
*----------------------------------------------------------------------
*/
static int
QueryConfigObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
*----------------------------------------------------------------------
*/
static int
QueryConfigObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
QCCD *cdPtr = (QCCD *)clientData;
Tcl_Obj *pkgName = cdPtr->pkg;
Tcl_Obj *pDB, *pkgDict, *val, *listPtr;
Tcl_Size m, n = 0;
static const char *const subcmdStrings[] = {
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 | * The package metadata database is freed. * *---------------------------------------------------------------------- */ static void ConfigDictDeleteProc( | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
* The package metadata database is freed.
*
*----------------------------------------------------------------------
*/
static void
ConfigDictDeleteProc(
void *clientData, /* Pointer to Tcl_Obj. */
TCL_UNUSED(Tcl_Interp *))
{
Tcl_DecrRefCount((Tcl_Obj *)clientData);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclDTrace.d.
1 2 3 4 5 | /* * tclDTrace.d -- * * Tcl DTrace provider. * | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
/*
* tclDTrace.d --
*
* Tcl DTrace provider.
*
* Copyright (c) 2007-2008 Daniel A. Steffen <das@users.sourceforge.net>
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
typedef struct Tcl_Obj Tcl_Obj;
typedef ptrdiff_t Tcl_Size;
/*
* Tcl DTrace probes
*/
provider tcl {
/***************************** proc probes *****************************/
/*
* tcl*:::proc-entry probe
* triggered immediately before proc bytecode execution
* arg0: proc name (string)
* arg1: number of arguments (Tcl_Size)
* arg2: array of proc argument objects (Tcl_Obj**)
*/
probe proc__entry(const char *name, Tcl_Size objc, struct Tcl_Obj **objv);
/*
* tcl*:::proc-return probe
* triggered immediately after proc bytecode execution
* arg0: proc name (string)
* arg1: return code (int)
*/
probe proc__return(const char *name, int code);
/*
* tcl*:::proc-result probe
* triggered after proc-return probe and result processing
* arg0: proc name (string)
* arg1: return code (int)
* arg2: proc result (string)
* arg3: proc result object (Tcl_Obj*)
*/
probe proc__result(const char *name, int code, const char *result,
struct Tcl_Obj *resultobj);
/*
* tcl*:::proc-args probe
* triggered before proc-entry probe, gives access to string
* representation of proc arguments
|
| ︙ | ︙ | |||
74 75 76 77 78 79 80 |
/***************************** cmd probes ******************************/
/*
* tcl*:::cmd-entry probe
* triggered immediately before commmand execution
* arg0: command name (string)
* arg1: number of arguments (Tcl_Size)
| | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
/***************************** cmd probes ******************************/
/*
* tcl*:::cmd-entry probe
* triggered immediately before commmand execution
* arg0: command name (string)
* arg1: number of arguments (Tcl_Size)
* arg2: array of command argument objects (Tcl_Obj**)
*/
probe cmd__entry(const char *name, Tcl_Size objc, struct Tcl_Obj **objv);
/*
* tcl*:::cmd-return probe
* triggered immediately after commmand execution
* arg0: command name (string)
* arg1: return code (int)
*/
probe cmd__return(const char *name, int code);
/*
* tcl*:::cmd-result probe
* triggered after cmd-return probe and result processing
* arg0: command name (string)
* arg1: return code (int)
* arg2: command result (string)
* arg3: command result object (Tcl_Obj*)
*/
probe cmd__result(const char *name, int code, const char *result,
struct Tcl_Obj *resultobj);
/*
* tcl*:::cmd-args probe
* triggered before cmd-entry probe, gives access to string
* representation of command arguments
|
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
/***************************** inst probes *****************************/
/*
* tcl*:::inst-start probe
* triggered immediately before execution of a bytecode
* arg0: bytecode name (string)
* arg1: depth of stack (Tcl_Size)
| | | | | | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
/***************************** inst probes *****************************/
/*
* tcl*:::inst-start probe
* triggered immediately before execution of a bytecode
* arg0: bytecode name (string)
* arg1: depth of stack (Tcl_Size)
* arg2: top of stack (Tcl_Obj**)
*/
probe inst__start(const char *name, Tcl_Size depth, struct Tcl_Obj **stack);
/*
* tcl*:::inst-done probe
* triggered immediately after execution of a bytecode
* arg0: bytecode name (string)
* arg1: depth of stack (Tcl_Size)
* arg2: top of stack (Tcl_Obj**)
*/
probe inst__done(const char *name, Tcl_Size depth, struct Tcl_Obj **stack);
/***************************** obj probes ******************************/
/*
* tcl*:::obj-create probe
* triggered immediately after a new Tcl_Obj has been created
* arg0: object created (Tcl_Obj*)
*/
probe obj__create(struct Tcl_Obj* obj);
/*
* tcl*:::obj-free probe
* triggered immediately before a Tcl_Obj is freed
* arg0: object to be freed (Tcl_Obj*)
*/
probe obj__free(struct Tcl_Obj* obj);
/***************************** tcl probes ******************************/
/*
* tcl*:::tcl-probe probe
* triggered when the ::tcl::dtrace command is called
* arg0-arg9: command arguments (strings)
*/
|
| ︙ | ︙ |
Changes to generic/tclDate.c.
| ︙ | ︙ | |||
110 111 112 113 114 115 116 | * yyparse will accept a 'struct DateInfo' as its parameter; that's where the * parsed fields will be returned. */ #include "tclDate.h" #define YYMALLOC Tcl_Alloc | | | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | * yyparse will accept a 'struct DateInfo' as its parameter; that's where the * parsed fields will be returned. */ #include "tclDate.h" #define YYMALLOC Tcl_Alloc #define YYFREE(x) (Tcl_Free((void*) (x))) #define EPOCH 1970 #define START_OF_TIME 1902 #define END_OF_TIME 2037 /* * The offset of tm_year of struct tm returned by localtime, gmtime, etc. |
| ︙ | ︙ | |||
251 252 253 254 255 256 257 | # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# define YYLTYPE_IS_DECLARED 1
# define YYLTYPE_IS_TRIVIAL 1
#endif
int TclDateparse (DateInfo* info);
/* Symbol kind. */
enum yysymbol_kind_t
{
YYSYMBOL_YYEMPTY = -2,
|
| ︙ | ︙ | |||
329 330 331 332 333 334 335 | /* Second part of user prologue. */ /* * Prototypes of internal functions. */ | | | | | | | | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | /* Second part of user prologue. */ /* * Prototypes of internal functions. */ static int LookupWord(YYSTYPE* yylvalPtr, char *buff); static void TclDateerror(YYLTYPE* location, DateInfo* info, const char *s); static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location, DateInfo* info); MODULE_SCOPE int yyparse(DateInfo*); #ifdef short # undef short #endif |
| ︙ | ︙ | |||
1056 1057 1058 1059 1060 1061 1062 | /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, | | | | 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
/*-----------------------------------.
| Print this symbol's value on YYO. |
`-----------------------------------*/
static void
yy_symbol_value_print (FILE *yyo,
yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info)
{
FILE *yyoutput = yyo;
YY_USE (yyoutput);
YY_USE (yylocationp);
YY_USE (info);
if (!yyvaluep)
return;
YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
YY_USE (yykind);
YY_IGNORE_MAYBE_UNINITIALIZED_END
}
/*---------------------------.
| Print this symbol on YYO. |
`---------------------------*/
static void
yy_symbol_print (FILE *yyo,
yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info)
{
YYFPRINTF (yyo, "%s %s (",
yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
YYLOCATION_PRINT (yyo, yylocationp);
YYFPRINTF (yyo, ": ");
yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp, info);
|
| ︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 | /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, | | | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 |
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
static void
yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp,
int yyrule, DateInfo* info)
{
int yylno = yyrline[yyrule];
int yynrhs = yyr2[yyrule];
int yyi;
YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
yyrule - 1, yylno);
/* The symbols being reduced. */
|
| ︙ | ︙ | |||
1180 1181 1182 1183 1184 1185 1186 | /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, | | | 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 |
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
static void
yydestruct (const char *yymsg,
yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, DateInfo* info)
{
YY_USE (yyvaluep);
YY_USE (yylocationp);
YY_USE (info);
if (!yymsg)
yymsg = "Deleting";
YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
|
| ︙ | ︙ | |||
1204 1205 1206 1207 1208 1209 1210 | /*----------. | yyparse. | `----------*/ int | | | 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 |
/*----------.
| yyparse. |
`----------*/
int
yyparse (DateInfo* info)
{
/* Lookahead token kind. */
int yychar;
/* The semantic value of the lookahead symbol. */
/* Default value used for initialization, for pacifying older GCCs
|
| ︙ | ︙ | |||
1596 1597 1598 1599 1600 1601 1602 |
yyTimezone = (yyvsp[0].Number);
yyDSTmode = DSTon;
}
break;
case 21: /* zone: tZONEwO4 sign INTNUM */
{ /* GMT+0100, GMT-1000, etc. */
| | | | | | 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 |
yyTimezone = (yyvsp[0].Number);
yyDSTmode = DSTon;
}
break;
case 21: /* zone: tZONEwO4 sign INTNUM */
{ /* GMT+0100, GMT-1000, etc. */
yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) % 100 + ((yyvsp[0].Number) / 100) * 60);
yyDSTmode = DSToff;
}
break;
case 22: /* zone: tZONEwO2 sign INTNUM */
{ /* GMT+1, GMT-10, etc. */
yyTimezone = (yyvsp[-2].Number) - (yyvsp[-1].Number)*((yyvsp[0].Number) * 60);
yyDSTmode = DSToff;
}
break;
case 23:
if (! (
yyDigitCount == 4 || yyDigitCount <= 2 )) YYERROR;
break;
case 24: /* nmzone: sign tUNUMBER $@1 */
{
if (yyDigitCount == 4) { /* +0100, -0100 */
yyTimezone = -(yyvsp[-2].Number)*((yyvsp[-1].Number) % 100 + ((yyvsp[-1].Number) / 100) * 60);
} else { /* +01, -01, +1, -1 */
yyTimezone = -(yyvsp[-2].Number)*((yyvsp[-1].Number) * 60);
}
yyDSTmode = DSToff;
}
break;
case 27: /* day: tDAY */
{
|
| ︙ | ︙ | |||
2361 2362 2363 2364 2365 2366 2367 | /* * Dump error messages in the bit bucket. */ static void TclDateerror( | | | | | 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 |
/*
* Dump error messages in the bit bucket.
*/
static void
TclDateerror(
YYLTYPE* location,
DateInfo* infoPtr,
const char *s)
{
Tcl_Obj* t;
if (!infoPtr->messages) {
TclNewObj(infoPtr->messages);
}
Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1);
Tcl_AppendToObj(infoPtr->messages, s, -1);
Tcl_AppendToObj(infoPtr->messages, " (characters ", -1);
TclNewIntObj(t, location->first_column);
|
| ︙ | ︙ | |||
2405 2406 2407 2408 2409 2410 2411 |
return (((Hours / 24) * 24 + (Hours % 12) + 12) * 60 + Minutes) * 60 + Seconds;
}
return -1; /* Should never be reached */
}
static int
LookupWord(
| | | 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 |
return (((Hours / 24) * 24 + (Hours % 12) + 12) * 60 + Minutes) * 60 + Seconds;
}
return -1; /* Should never be reached */
}
static int
LookupWord(
YYSTYPE* yylvalPtr,
char *buff)
{
char *p;
char *q;
const TABLE *tp;
int i, abbrev;
|
| ︙ | ︙ | |||
2529 2530 2531 2532 2533 2534 2535 |
}
return tID;
}
static int
TclDatelex(
| | | | 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 |
}
return tID;
}
static int
TclDatelex(
YYSTYPE* yylvalPtr,
YYLTYPE* location,
DateInfo *info)
{
char c;
char *p;
char buff[20];
int Count;
const char *tokStart;
|
| ︙ | ︙ | |||
2569 2570 2571 2572 2573 2574 2575 |
*/
if (yyDigitCount == 14 || yyDigitCount == 12) {
/* long form of ISO 8601 (without separator), either
* YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date
* (8 chars is isodate) */
p = (char *)yyInput+8;
if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) {
| | | | 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 |
*/
if (yyDigitCount == 14 || yyDigitCount == 12) {
/* long form of ISO 8601 (without separator), either
* YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date
* (8 chars is isodate) */
p = (char *)yyInput+8;
if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) {
return tID; /* overflow*/
}
yyDigitCount = 8;
yyInput = p;
location->last_column = yyInput - info->dateStart - 1;
return tISOBASL;
}
/*
* Convert the string into a number
*/
if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) {
return tID; /* overflow*/
}
yyInput = p;
/*
* A number with 6 or more digits is considered an ISO 8601 base.
*/
location->last_column = yyInput - info->dateStart - 1;
if (yyDigitCount >= 6) {
|
| ︙ | ︙ |
Changes to generic/tclDate.h.
1 2 3 4 5 6 | /* * tclDate.h -- * * This header file handles common usage of clock primitives * between tclDate.c (yacc), tclClock.c and tclClockFmt.c. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * tclDate.h -- * * This header file handles common usage of clock primitives * between tclDate.c (yacc), tclClock.c and tclClockFmt.c. * * Copyright (c) 2014 Serg G. Brester (aka sebres) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLCLOCK_H #define _TCLCLOCK_H |
| ︙ | ︙ | |||
292 293 294 295 296 297 298 |
/* Last-period cache for fast UTC to local and backwards conversion */
typedef struct ClockLastTZOffs {
/* keys */
Tcl_Obj *timezoneObj;
int changeover;
Tcl_WideInt localSeconds;
| | | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
/* Last-period cache for fast UTC to local and backwards conversion */
typedef struct ClockLastTZOffs {
/* keys */
Tcl_Obj *timezoneObj;
int changeover;
Tcl_WideInt localSeconds;
Tcl_WideInt rangesVal[2]; /* Bounds for cached time zone offset */
/* values */
int tzOffset;
Tcl_Obj *tzName; /* Name (abbreviation) of this area in TZ */
} ClockLastTZOffs;
/*
* Structure containing the client data for [clock]
|
| ︙ | ︙ | |||
352 353 354 355 356 357 358 |
Tcl_Obj *timezoneObj;
TclDateFields date;
} lastBase;
/* Last-period cache for fast UTC to Local and backwards conversion */
ClockLastTZOffs lastTZOffsCache[2];
| | | | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
Tcl_Obj *timezoneObj;
TclDateFields date;
} lastBase;
/* Last-period cache for fast UTC to Local and backwards conversion */
ClockLastTZOffs lastTZOffsCache[2];
int defFlags; /* Default flags (from configure), ATM
* only CLF_VALIDATE supported */
} ClockClientData;
typedef struct ClockFmtScnCmdArgs {
ClockClientData *dataPtr; /* Pointer to literal pool, etc. */
Tcl_Interp *interp; /* Tcl interpreter */
Tcl_Obj *formatObj; /* Format */
Tcl_Obj *localeObj; /* Name of the locale where the time will be expressed. */
|
| ︙ | ︙ | |||
461 462 463 464 465 466 467 |
const ClockFormatTokenMap *map;
struct {
const char *start;
const char *end;
} tokWord;
};
| | > > | | > | | < > > | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
const ClockFormatTokenMap *map;
struct {
const char *start;
const char *end;
} tokWord;
};
typedef struct ClockFmtScnStorage ClockFmtScnStorage;
struct ClockFmtScnStorage {
int objRefCount; /* Reference count shared across threads */
ClockScanToken *scnTok;
unsigned scnTokC;
unsigned scnSpaceCount; /* Count of mandatory spaces used in format */
ClockFormatToken *fmtTok;
unsigned fmtTokC;
#if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0
ClockFmtScnStorage *nextPtr;
ClockFmtScnStorage *prevPtr;
#endif
size_t fmtMinAlloc;
#if 0
Tcl_HashEntry hashEntry /* ClockFmtScnStorage is a derivate of Tcl_HashEntry,
* stored by offset +sizeof(self) */
#endif
};
/*
* Clock macros.
*/
/*
* Extracts Julian day and seconds of the day from posix seconds (tm).
|
| ︙ | ︙ |
Changes to generic/tclDecls.h.
1 2 3 4 5 | /* * tclDecls.h -- * * Declarations of functions in the platform independent public Tcl API. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * tclDecls.h -- * * Declarations of functions in the platform independent public Tcl API. * * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLDECLS #define _TCLDECLS |
| ︙ | ︙ | |||
29 30 31 32 33 34 35 | # define TCL_DEPRECATED(msg) EXTERN TCL_DEPRECATED_API(msg) #elif defined(TCL_NO_DEPRECATED) # define TCL_DEPRECATED(msg) MODULE_SCOPE #else # define TCL_DEPRECATED(msg) EXTERN #endif | < < < < < < < < < | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # define TCL_DEPRECATED(msg) EXTERN TCL_DEPRECATED_API(msg) #elif defined(TCL_NO_DEPRECATED) # define TCL_DEPRECATED(msg) MODULE_SCOPE #else # define TCL_DEPRECATED(msg) EXTERN #endif /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the generic/tcl.decls script. */ |
| ︙ | ︙ | |||
66 67 68 69 70 71 72 | /* 1 */ EXTERN const char * Tcl_PkgRequireEx(Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 2 */ EXTERN TCL_NORETURN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 3 */ | | | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /* 1 */ EXTERN const char * Tcl_PkgRequireEx(Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 2 */ EXTERN TCL_NORETURN void Tcl_Panic(const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 3 */ EXTERN void * Tcl_Alloc(TCL_HASH_TYPE size); /* 4 */ EXTERN void Tcl_Free(void *ptr); /* 5 */ EXTERN void * Tcl_Realloc(void *ptr, TCL_HASH_TYPE size); /* 6 */ EXTERN void * Tcl_DbCkalloc(TCL_HASH_TYPE size, const char *file, int line); /* 7 */ EXTERN void Tcl_DbCkfree(void *ptr, const char *file, int line); /* 8 */ EXTERN void * Tcl_DbCkrealloc(void *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 9 */ EXTERN void Tcl_CreateFileHandler(int fd, int mask, Tcl_FileProc *proc, void *clientData); /* 10 */ EXTERN void Tcl_DeleteFileHandler(int fd); /* 11 */ |
| ︙ | ︙ | |||
123 124 125 126 127 128 129 | int line); /* 24 */ EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue, const char *file, int line); /* 25 */ EXTERN Tcl_Obj * Tcl_DbNewListObj(Tcl_Size objc, Tcl_Obj *const *objv, const char *file, int line); | | < | > > | > > | > > | < | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | int line); /* 24 */ EXTERN Tcl_Obj * Tcl_DbNewDoubleObj(double doubleValue, const char *file, int line); /* 25 */ EXTERN Tcl_Obj * Tcl_DbNewListObj(Tcl_Size objc, Tcl_Obj *const *objv, const char *file, int line); /* Slot 26 is reserved */ /* 27 */ EXTERN Tcl_Obj * Tcl_DbNewObj(const char *file, int line); /* 28 */ EXTERN Tcl_Obj * Tcl_DbNewStringObj(const char *bytes, Tcl_Size length, const char *file, int line); /* 29 */ EXTERN Tcl_Obj * Tcl_DuplicateObj(Tcl_Obj *objPtr); /* 30 */ EXTERN void TclFreeObj(Tcl_Obj *objPtr); /* 31 */ EXTERN int Tcl_GetBoolean(Tcl_Interp *interp, const char *src, int *intPtr); /* 32 */ EXTERN int Tcl_GetBooleanFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 33 */ EXTERN unsigned char * Tcl_GetByteArrayFromObj(Tcl_Obj *objPtr, Tcl_Size *numBytesPtr); /* 34 */ EXTERN int Tcl_GetDouble(Tcl_Interp *interp, const char *src, double *doublePtr); /* 35 */ EXTERN int Tcl_GetDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, double *doublePtr); /* Slot 36 is reserved */ /* 37 */ EXTERN int Tcl_GetInt(Tcl_Interp *interp, const char *src, int *intPtr); /* 38 */ EXTERN int Tcl_GetIntFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 39 */ |
| ︙ | ︙ | |||
182 183 184 185 186 187 188 | EXTERN int TclListObjLength(Tcl_Interp *interp, Tcl_Obj *listPtr, void *lengthPtr); /* 48 */ EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size first, Tcl_Size count, Tcl_Size objc, Tcl_Obj *const objv[]); | | < | < < | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | EXTERN int TclListObjLength(Tcl_Interp *interp, Tcl_Obj *listPtr, void *lengthPtr); /* 48 */ EXTERN int Tcl_ListObjReplace(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size first, Tcl_Size count, Tcl_Size objc, Tcl_Obj *const objv[]); /* Slot 49 is reserved */ /* 50 */ EXTERN Tcl_Obj * Tcl_NewByteArrayObj(const unsigned char *bytes, Tcl_Size numBytes); /* 51 */ EXTERN Tcl_Obj * Tcl_NewDoubleObj(double doubleValue); /* Slot 52 is reserved */ /* 53 */ EXTERN Tcl_Obj * Tcl_NewListObj(Tcl_Size objc, Tcl_Obj *const objv[]); /* Slot 54 is reserved */ /* 55 */ EXTERN Tcl_Obj * Tcl_NewObj(void); /* 56 */ EXTERN Tcl_Obj * Tcl_NewStringObj(const char *bytes, Tcl_Size length); |
| ︙ | ︙ | |||
213 214 215 216 217 218 219 | Tcl_Size numBytes); /* 60 */ EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue); /* Slot 61 is reserved */ /* 62 */ EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, Tcl_Size objc, Tcl_Obj *const objv[]); | | < < | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | Tcl_Size numBytes); /* 60 */ EXTERN void Tcl_SetDoubleObj(Tcl_Obj *objPtr, double doubleValue); /* Slot 61 is reserved */ /* 62 */ EXTERN void Tcl_SetListObj(Tcl_Obj *objPtr, Tcl_Size objc, Tcl_Obj *const objv[]); /* Slot 63 is reserved */ /* 64 */ EXTERN void Tcl_SetObjLength(Tcl_Obj *objPtr, Tcl_Size length); /* 65 */ EXTERN void Tcl_SetStringObj(Tcl_Obj *objPtr, const char *bytes, Tcl_Size length); /* Slot 66 is reserved */ /* Slot 67 is reserved */ |
| ︙ | ︙ | |||
241 242 243 244 245 246 247 | EXTERN void Tcl_AsyncDelete(Tcl_AsyncHandler async); /* 73 */ EXTERN int Tcl_AsyncInvoke(Tcl_Interp *interp, int code); /* 74 */ EXTERN void Tcl_AsyncMark(Tcl_AsyncHandler async); /* 75 */ EXTERN int Tcl_AsyncReady(void); | | < | < | > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | EXTERN void Tcl_AsyncDelete(Tcl_AsyncHandler async); /* 73 */ EXTERN int Tcl_AsyncInvoke(Tcl_Interp *interp, int code); /* 74 */ EXTERN void Tcl_AsyncMark(Tcl_AsyncHandler async); /* 75 */ EXTERN int Tcl_AsyncReady(void); /* Slot 76 is reserved */ /* Slot 77 is reserved */ /* 78 */ EXTERN int Tcl_BadChannelOption(Tcl_Interp *interp, const char *optionName, const char *optionList); /* 79 */ EXTERN void Tcl_CallWhenDeleted(Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, void *clientData); /* 80 */ EXTERN void Tcl_CancelIdleCall(Tcl_IdleProc *idleProc, void *clientData); /* 81 */ EXTERN int Tcl_Close(Tcl_Interp *interp, Tcl_Channel chan); /* 82 */ EXTERN int Tcl_CommandComplete(const char *cmd); /* 83 */ EXTERN char * Tcl_Concat(Tcl_Size argc, const char *const *argv); /* 84 */ EXTERN Tcl_Size Tcl_ConvertElement(const char *src, char *dst, int flags); |
| ︙ | ︙ | |||
909 910 911 912 913 914 915 | EXTERN Tcl_Size Tcl_UtfToUpper(char *src); /* 338 */ EXTERN Tcl_Size Tcl_WriteChars(Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 339 */ EXTERN Tcl_Size Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr); /* 340 */ | | | < < < | < | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 | EXTERN Tcl_Size Tcl_UtfToUpper(char *src); /* 338 */ EXTERN Tcl_Size Tcl_WriteChars(Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 339 */ EXTERN Tcl_Size Tcl_WriteObj(Tcl_Channel chan, Tcl_Obj *objPtr); /* 340 */ EXTERN char * Tcl_GetString(Tcl_Obj *objPtr); /* Slot 341 is reserved */ /* Slot 342 is reserved */ /* 343 */ EXTERN void Tcl_AlertNotifier(void *clientData); /* 344 */ EXTERN void Tcl_ServiceModeHook(int mode); /* 345 */ EXTERN int Tcl_UniCharIsAlnum(int ch); /* 346 */ |
| ︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 | /* 391 */ EXTERN void Tcl_ConditionFinalize(Tcl_Condition *condPtr); /* 392 */ EXTERN void Tcl_MutexFinalize(Tcl_Mutex *mutex); /* 393 */ EXTERN int Tcl_CreateThread(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, void *clientData, | | | 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 | /* 391 */ EXTERN void Tcl_ConditionFinalize(Tcl_Condition *condPtr); /* 392 */ EXTERN void Tcl_MutexFinalize(Tcl_Mutex *mutex); /* 393 */ EXTERN int Tcl_CreateThread(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, void *clientData, TCL_HASH_TYPE stackSize, int flags); /* 394 */ EXTERN Tcl_Size Tcl_ReadRaw(Tcl_Channel chan, char *dst, Tcl_Size bytesToRead); /* 395 */ EXTERN Tcl_Size Tcl_WriteRaw(Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 396 */ |
| ︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | EXTERN void Tcl_SpliceChannel(Tcl_Channel channel); /* 417 */ EXTERN void Tcl_ClearChannelHandlers(Tcl_Channel channel); /* 418 */ EXTERN int Tcl_IsChannelExisting(const char *channelName); /* Slot 419 is reserved */ /* Slot 420 is reserved */ | | < < < | 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | EXTERN void Tcl_SpliceChannel(Tcl_Channel channel); /* 417 */ EXTERN void Tcl_ClearChannelHandlers(Tcl_Channel channel); /* 418 */ EXTERN int Tcl_IsChannelExisting(const char *channelName); /* Slot 419 is reserved */ /* Slot 420 is reserved */ /* Slot 421 is reserved */ /* 422 */ EXTERN Tcl_HashEntry * Tcl_CreateHashEntry(Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 423 */ EXTERN void Tcl_InitCustomHashTable(Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 424 */ |
| ︙ | ︙ | |||
1138 1139 1140 1141 1142 1143 1144 | const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 427 */ EXTERN void Tcl_UntraceCommand(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 428 */ | | | | | | | 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 427 */ EXTERN void Tcl_UntraceCommand(Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 428 */ EXTERN void * Tcl_AttemptAlloc(TCL_HASH_TYPE size); /* 429 */ EXTERN void * Tcl_AttemptDbCkalloc(TCL_HASH_TYPE size, const char *file, int line); /* 430 */ EXTERN void * Tcl_AttemptRealloc(void *ptr, TCL_HASH_TYPE size); /* 431 */ EXTERN void * Tcl_AttemptDbCkrealloc(void *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 432 */ EXTERN int Tcl_AttemptSetObjLength(Tcl_Obj *objPtr, Tcl_Size length); /* 433 */ EXTERN Tcl_ThreadId Tcl_GetChannelThread(Tcl_Channel channel); /* 434 */ |
| ︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | EXTERN int Tcl_GetEnsembleFlags(Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 551 */ EXTERN int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 552 */ | < | < | | 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 | EXTERN int Tcl_GetEnsembleFlags(Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 551 */ EXTERN int Tcl_GetEnsembleNamespace(Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 552 */ EXTERN void Tcl_SetTimeProc(Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, void *clientData); /* 553 */ EXTERN void Tcl_QueryTimeProc(Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, void **clientData); /* 554 */ EXTERN Tcl_DriverThreadActionProc * Tcl_ChannelThreadActionProc( const Tcl_ChannelType *chanTypePtr); /* 555 */ EXTERN Tcl_Obj * Tcl_NewBignumObj(void *value); |
| ︙ | ︙ | |||
1729 1730 1731 1732 1733 1734 1735 | EXTERN int TclZipfs_MountBuffer(Tcl_Interp *interp, const void *data, size_t datalen, const char *mountPoint, int copy); /* 636 */ EXTERN void Tcl_FreeInternalRep(Tcl_Obj *objPtr); /* 637 */ EXTERN char * Tcl_InitStringRep(Tcl_Obj *objPtr, const char *bytes, | | | 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 | EXTERN int TclZipfs_MountBuffer(Tcl_Interp *interp, const void *data, size_t datalen, const char *mountPoint, int copy); /* 636 */ EXTERN void Tcl_FreeInternalRep(Tcl_Obj *objPtr); /* 637 */ EXTERN char * Tcl_InitStringRep(Tcl_Obj *objPtr, const char *bytes, TCL_HASH_TYPE numBytes); /* 638 */ EXTERN Tcl_ObjInternalRep * Tcl_FetchInternalRep(Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 639 */ EXTERN void Tcl_StoreInternalRep(Tcl_Obj *objPtr, const Tcl_ObjType *typePtr, const Tcl_ObjInternalRep *irPtr); |
| ︙ | ︙ | |||
1892 1893 1894 1895 1896 1897 1898 | size_t n); /* 688 */ EXTERN Tcl_Obj * Tcl_NewWideUIntObj(Tcl_WideUInt wideValue); /* 689 */ EXTERN void Tcl_SetWideUIntObj(Tcl_Obj *objPtr, Tcl_WideUInt uwideValue); /* 690 */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 |
size_t n);
/* 688 */
EXTERN Tcl_Obj * Tcl_NewWideUIntObj(Tcl_WideUInt wideValue);
/* 689 */
EXTERN void Tcl_SetWideUIntObj(Tcl_Obj *objPtr,
Tcl_WideUInt uwideValue);
/* 690 */
EXTERN void TclUnusedStubEntry(void);
typedef struct {
const struct TclPlatStubs *tclPlatStubs;
const struct TclIntStubs *tclIntStubs;
const struct TclIntPlatStubs *tclIntPlatStubs;
} TclStubHooks;
typedef struct TclStubs {
int magic;
const TclStubHooks *hooks;
int (*tcl_PkgProvideEx) (Tcl_Interp *interp, const char *name, const char *version, const void *clientData); /* 0 */
const char * (*tcl_PkgRequireEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 1 */
TCL_NORETURN1 void (*tcl_Panic) (const char *format, ...) TCL_FORMAT_PRINTF(1, 2); /* 2 */
void * (*tcl_Alloc) (TCL_HASH_TYPE size); /* 3 */
void (*tcl_Free) (void *ptr); /* 4 */
void * (*tcl_Realloc) (void *ptr, TCL_HASH_TYPE size); /* 5 */
void * (*tcl_DbCkalloc) (TCL_HASH_TYPE size, const char *file, int line); /* 6 */
void (*tcl_DbCkfree) (void *ptr, const char *file, int line); /* 7 */
void * (*tcl_DbCkrealloc) (void *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 8 */
void (*tcl_CreateFileHandler) (int fd, int mask, Tcl_FileProc *proc, void *clientData); /* 9 */
void (*tcl_DeleteFileHandler) (int fd); /* 10 */
void (*tcl_SetTimer) (const Tcl_Time *timePtr); /* 11 */
void (*tcl_Sleep) (int ms); /* 12 */
int (*tcl_WaitForEvent) (const Tcl_Time *timePtr); /* 13 */
int (*tcl_AppendAllObjTypes) (Tcl_Interp *interp, Tcl_Obj *objPtr); /* 14 */
void (*tcl_AppendStringsToObj) (Tcl_Obj *objPtr, ...); /* 15 */
void (*tcl_AppendToObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length); /* 16 */
Tcl_Obj * (*tcl_ConcatObj) (Tcl_Size objc, Tcl_Obj *const objv[]); /* 17 */
int (*tcl_ConvertToType) (Tcl_Interp *interp, Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 18 */
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 */
void (*reserved22)(void);
Tcl_Obj * (*tcl_DbNewByteArrayObj) (const unsigned char *bytes, Tcl_Size numBytes, const char *file, int line); /* 23 */
Tcl_Obj * (*tcl_DbNewDoubleObj) (double doubleValue, const char *file, int line); /* 24 */
Tcl_Obj * (*tcl_DbNewListObj) (Tcl_Size objc, Tcl_Obj *const *objv, const char *file, int line); /* 25 */
void (*reserved26)(void);
Tcl_Obj * (*tcl_DbNewObj) (const char *file, int line); /* 27 */
Tcl_Obj * (*tcl_DbNewStringObj) (const char *bytes, Tcl_Size length, const char *file, int line); /* 28 */
Tcl_Obj * (*tcl_DuplicateObj) (Tcl_Obj *objPtr); /* 29 */
void (*tclFreeObj) (Tcl_Obj *objPtr); /* 30 */
int (*tcl_GetBoolean) (Tcl_Interp *interp, const char *src, int *intPtr); /* 31 */
int (*tcl_GetBooleanFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int *intPtr); /* 32 */
unsigned char * (*tcl_GetByteArrayFromObj) (Tcl_Obj *objPtr, Tcl_Size *numBytesPtr); /* 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 */
void (*reserved36)(void);
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 */
const Tcl_ObjType * (*tcl_GetObjType) (const char *typeName); /* 40 */
char * (*tclGetStringFromObj) (Tcl_Obj *objPtr, void *lengthPtr); /* 41 */
void (*tcl_InvalidateStringRep) (Tcl_Obj *objPtr); /* 42 */
int (*tcl_ListObjAppendList) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *elemListPtr); /* 43 */
int (*tcl_ListObjAppendElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *objPtr); /* 44 */
int (*tclListObjGetElements) (Tcl_Interp *interp, Tcl_Obj *listPtr, void *objcPtr, Tcl_Obj ***objvPtr); /* 45 */
int (*tcl_ListObjIndex) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size index, Tcl_Obj **objPtrPtr); /* 46 */
int (*tclListObjLength) (Tcl_Interp *interp, Tcl_Obj *listPtr, void *lengthPtr); /* 47 */
int (*tcl_ListObjReplace) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size first, Tcl_Size count, Tcl_Size objc, Tcl_Obj *const objv[]); /* 48 */
void (*reserved49)(void);
Tcl_Obj * (*tcl_NewByteArrayObj) (const unsigned char *bytes, Tcl_Size numBytes); /* 50 */
Tcl_Obj * (*tcl_NewDoubleObj) (double doubleValue); /* 51 */
void (*reserved52)(void);
Tcl_Obj * (*tcl_NewListObj) (Tcl_Size objc, Tcl_Obj *const objv[]); /* 53 */
void (*reserved54)(void);
Tcl_Obj * (*tcl_NewObj) (void); /* 55 */
Tcl_Obj * (*tcl_NewStringObj) (const char *bytes, Tcl_Size length); /* 56 */
void (*reserved57)(void);
unsigned char * (*tcl_SetByteArrayLength) (Tcl_Obj *objPtr, Tcl_Size numBytes); /* 58 */
void (*tcl_SetByteArrayObj) (Tcl_Obj *objPtr, const unsigned char *bytes, Tcl_Size numBytes); /* 59 */
void (*tcl_SetDoubleObj) (Tcl_Obj *objPtr, double doubleValue); /* 60 */
void (*reserved61)(void);
void (*tcl_SetListObj) (Tcl_Obj *objPtr, Tcl_Size objc, Tcl_Obj *const objv[]); /* 62 */
void (*reserved63)(void);
void (*tcl_SetObjLength) (Tcl_Obj *objPtr, Tcl_Size length); /* 64 */
void (*tcl_SetStringObj) (Tcl_Obj *objPtr, const char *bytes, Tcl_Size length); /* 65 */
void (*reserved66)(void);
void (*reserved67)(void);
void (*tcl_AllowExceptions) (Tcl_Interp *interp); /* 68 */
void (*tcl_AppendElement) (Tcl_Interp *interp, const char *element); /* 69 */
void (*tcl_AppendResult) (Tcl_Interp *interp, ...); /* 70 */
Tcl_AsyncHandler (*tcl_AsyncCreate) (Tcl_AsyncProc *proc, void *clientData); /* 71 */
void (*tcl_AsyncDelete) (Tcl_AsyncHandler async); /* 72 */
int (*tcl_AsyncInvoke) (Tcl_Interp *interp, int code); /* 73 */
void (*tcl_AsyncMark) (Tcl_AsyncHandler async); /* 74 */
int (*tcl_AsyncReady) (void); /* 75 */
void (*reserved76)(void);
void (*reserved77)(void);
int (*tcl_BadChannelOption) (Tcl_Interp *interp, const char *optionName, const char *optionList); /* 78 */
void (*tcl_CallWhenDeleted) (Tcl_Interp *interp, Tcl_InterpDeleteProc *proc, void *clientData); /* 79 */
void (*tcl_CancelIdleCall) (Tcl_IdleProc *idleProc, void *clientData); /* 80 */
int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */
int (*tcl_CommandComplete) (const char *cmd); /* 82 */
char * (*tcl_Concat) (Tcl_Size argc, const char *const *argv); /* 83 */
Tcl_Size (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */
Tcl_Size (*tcl_ConvertCountedElement) (const char *src, Tcl_Size length, char *dst, int flags); /* 85 */
int (*tcl_CreateAlias) (Tcl_Interp *childInterp, const char *childCmd, Tcl_Interp *target, const char *targetCmd, Tcl_Size argc, const char *const *argv); /* 86 */
int (*tcl_CreateAliasObj) (Tcl_Interp *childInterp, const char *childCmd, Tcl_Interp *target, const char *targetCmd, Tcl_Size objc, Tcl_Obj *const objv[]); /* 87 */
Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, void *instanceData, int mask); /* 88 */
|
| ︙ | ︙ | |||
2295 2296 2297 2298 2299 2300 2301 |
char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, Tcl_DString *dsPtr); /* 333 */
Tcl_Size (*tcl_UtfToLower) (char *src); /* 334 */
Tcl_Size (*tcl_UtfToTitle) (char *src); /* 335 */
Tcl_Size (*tcl_UtfToChar16) (const char *src, unsigned short *chPtr); /* 336 */
Tcl_Size (*tcl_UtfToUpper) (char *src); /* 337 */
Tcl_Size (*tcl_WriteChars) (Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 338 */
Tcl_Size (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */
| | | | | 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 |
char * (*tcl_UtfToExternalDString) (Tcl_Encoding encoding, const char *src, Tcl_Size srcLen, Tcl_DString *dsPtr); /* 333 */
Tcl_Size (*tcl_UtfToLower) (char *src); /* 334 */
Tcl_Size (*tcl_UtfToTitle) (char *src); /* 335 */
Tcl_Size (*tcl_UtfToChar16) (const char *src, unsigned short *chPtr); /* 336 */
Tcl_Size (*tcl_UtfToUpper) (char *src); /* 337 */
Tcl_Size (*tcl_WriteChars) (Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 338 */
Tcl_Size (*tcl_WriteObj) (Tcl_Channel chan, Tcl_Obj *objPtr); /* 339 */
char * (*tcl_GetString) (Tcl_Obj *objPtr); /* 340 */
void (*reserved341)(void);
void (*reserved342)(void);
void (*tcl_AlertNotifier) (void *clientData); /* 343 */
void (*tcl_ServiceModeHook) (int mode); /* 344 */
int (*tcl_UniCharIsAlnum) (int ch); /* 345 */
int (*tcl_UniCharIsAlpha) (int ch); /* 346 */
int (*tcl_UniCharIsDigit) (int ch); /* 347 */
int (*tcl_UniCharIsLower) (int ch); /* 348 */
int (*tcl_UniCharIsSpace) (int ch); /* 349 */
|
| ︙ | ︙ | |||
2348 2349 2350 2351 2352 2353 2354 |
void (*tcl_SetNotifier) (const Tcl_NotifierProcs *notifierProcPtr); /* 386 */
Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */
int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */
int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */
int (*tcl_ProcObjCmd) (void *clientData, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); /* 390 */
void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */
void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */
| | | 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 |
void (*tcl_SetNotifier) (const Tcl_NotifierProcs *notifierProcPtr); /* 386 */
Tcl_Mutex * (*tcl_GetAllocMutex) (void); /* 387 */
int (*tcl_GetChannelNames) (Tcl_Interp *interp); /* 388 */
int (*tcl_GetChannelNamesEx) (Tcl_Interp *interp, const char *pattern); /* 389 */
int (*tcl_ProcObjCmd) (void *clientData, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); /* 390 */
void (*tcl_ConditionFinalize) (Tcl_Condition *condPtr); /* 391 */
void (*tcl_MutexFinalize) (Tcl_Mutex *mutex); /* 392 */
int (*tcl_CreateThread) (Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, void *clientData, TCL_HASH_TYPE stackSize, int flags); /* 393 */
Tcl_Size (*tcl_ReadRaw) (Tcl_Channel chan, char *dst, Tcl_Size bytesToRead); /* 394 */
Tcl_Size (*tcl_WriteRaw) (Tcl_Channel chan, const char *src, Tcl_Size srcLen); /* 395 */
Tcl_Channel (*tcl_GetTopChannel) (Tcl_Channel chan); /* 396 */
int (*tcl_ChannelBuffered) (Tcl_Channel chan); /* 397 */
const char * (*tcl_ChannelName) (const Tcl_ChannelType *chanTypePtr); /* 398 */
Tcl_ChannelTypeVersion (*tcl_ChannelVersion) (const Tcl_ChannelType *chanTypePtr); /* 399 */
Tcl_DriverBlockModeProc * (*tcl_ChannelBlockModeProc) (const Tcl_ChannelType *chanTypePtr); /* 400 */
|
| ︙ | ︙ | |||
2376 2377 2378 2379 2380 2381 2382 |
int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */
void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */
void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */
void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */
int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */
void (*reserved419)(void);
void (*reserved420)(void);
| | | | | | | 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 |
int (*tcl_IsChannelRegistered) (Tcl_Interp *interp, Tcl_Channel channel); /* 414 */
void (*tcl_CutChannel) (Tcl_Channel channel); /* 415 */
void (*tcl_SpliceChannel) (Tcl_Channel channel); /* 416 */
void (*tcl_ClearChannelHandlers) (Tcl_Channel channel); /* 417 */
int (*tcl_IsChannelExisting) (const char *channelName); /* 418 */
void (*reserved419)(void);
void (*reserved420)(void);
void (*reserved421)(void);
Tcl_HashEntry * (*tcl_CreateHashEntry) (Tcl_HashTable *tablePtr, const void *key, int *newPtr); /* 422 */
void (*tcl_InitCustomHashTable) (Tcl_HashTable *tablePtr, int keyType, const Tcl_HashKeyType *typePtr); /* 423 */
void (*tcl_InitObjHashTable) (Tcl_HashTable *tablePtr); /* 424 */
void * (*tcl_CommandTraceInfo) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *procPtr, void *prevClientData); /* 425 */
int (*tcl_TraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 426 */
void (*tcl_UntraceCommand) (Tcl_Interp *interp, const char *varName, int flags, Tcl_CommandTraceProc *proc, void *clientData); /* 427 */
void * (*tcl_AttemptAlloc) (TCL_HASH_TYPE size); /* 428 */
void * (*tcl_AttemptDbCkalloc) (TCL_HASH_TYPE size, const char *file, int line); /* 429 */
void * (*tcl_AttemptRealloc) (void *ptr, TCL_HASH_TYPE size); /* 430 */
void * (*tcl_AttemptDbCkrealloc) (void *ptr, TCL_HASH_TYPE size, const char *file, int line); /* 431 */
int (*tcl_AttemptSetObjLength) (Tcl_Obj *objPtr, Tcl_Size length); /* 432 */
Tcl_ThreadId (*tcl_GetChannelThread) (Tcl_Channel channel); /* 433 */
Tcl_UniChar * (*tclGetUnicodeFromObj) (Tcl_Obj *objPtr, void *lengthPtr); /* 434 */
void (*reserved435)(void);
void (*reserved436)(void);
Tcl_Obj * (*tcl_SubstObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags); /* 437 */
int (*tcl_DetachChannel) (Tcl_Interp *interp, Tcl_Channel channel); /* 438 */
|
| ︙ | ︙ | |||
2507 2508 2509 2510 2511 2512 2513 |
int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */
int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */
int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */
int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */
int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */
int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */
int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */
| | | | 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 |
int (*tcl_SetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *unknownList); /* 545 */
int (*tcl_SetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int flags); /* 546 */
int (*tcl_GetEnsembleSubcommandList) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **subcmdListPtr); /* 547 */
int (*tcl_GetEnsembleMappingDict) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **mapDictPtr); /* 548 */
int (*tcl_GetEnsembleUnknownHandler) (Tcl_Interp *interp, Tcl_Command token, Tcl_Obj **unknownListPtr); /* 549 */
int (*tcl_GetEnsembleFlags) (Tcl_Interp *interp, Tcl_Command token, int *flagsPtr); /* 550 */
int (*tcl_GetEnsembleNamespace) (Tcl_Interp *interp, Tcl_Command token, Tcl_Namespace **namespacePtrPtr); /* 551 */
void (*tcl_SetTimeProc) (Tcl_GetTimeProc *getProc, Tcl_ScaleTimeProc *scaleProc, void *clientData); /* 552 */
void (*tcl_QueryTimeProc) (Tcl_GetTimeProc **getProc, Tcl_ScaleTimeProc **scaleProc, void **clientData); /* 553 */
Tcl_DriverThreadActionProc * (*tcl_ChannelThreadActionProc) (const Tcl_ChannelType *chanTypePtr); /* 554 */
Tcl_Obj * (*tcl_NewBignumObj) (void *value); /* 555 */
Tcl_Obj * (*tcl_DbNewBignumObj) (void *value, const char *file, int line); /* 556 */
void (*tcl_SetBignumObj) (Tcl_Obj *obj, void *value); /* 557 */
int (*tcl_GetBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, void *value); /* 558 */
int (*tcl_TakeBignumFromObj) (Tcl_Interp *interp, Tcl_Obj *obj, void *value); /* 559 */
int (*tcl_TruncateChannel) (Tcl_Channel chan, long long length); /* 560 */
|
| ︙ | ︙ | |||
2592 2593 2594 2595 2596 2597 2598 |
void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */
Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, const char *service, const char *host, unsigned flags, int backlog, Tcl_TcpAcceptProc *acceptProc, void *callbackData); /* 631 */
int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *zipname, const char *mountPoint, const char *passwd); /* 632 */
int (*tclZipfs_Unmount) (Tcl_Interp *interp, const char *mountPoint); /* 633 */
Tcl_Obj * (*tclZipfs_TclLibrary) (void); /* 634 */
int (*tclZipfs_MountBuffer) (Tcl_Interp *interp, const void *data, size_t datalen, const char *mountPoint, int copy); /* 635 */
void (*tcl_FreeInternalRep) (Tcl_Obj *objPtr); /* 636 */
| | | 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 |
void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */
Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, const char *service, const char *host, unsigned flags, int backlog, Tcl_TcpAcceptProc *acceptProc, void *callbackData); /* 631 */
int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *zipname, const char *mountPoint, const char *passwd); /* 632 */
int (*tclZipfs_Unmount) (Tcl_Interp *interp, const char *mountPoint); /* 633 */
Tcl_Obj * (*tclZipfs_TclLibrary) (void); /* 634 */
int (*tclZipfs_MountBuffer) (Tcl_Interp *interp, const void *data, size_t datalen, const char *mountPoint, int copy); /* 635 */
void (*tcl_FreeInternalRep) (Tcl_Obj *objPtr); /* 636 */
char * (*tcl_InitStringRep) (Tcl_Obj *objPtr, const char *bytes, TCL_HASH_TYPE numBytes); /* 637 */
Tcl_ObjInternalRep * (*tcl_FetchInternalRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr); /* 638 */
void (*tcl_StoreInternalRep) (Tcl_Obj *objPtr, const Tcl_ObjType *typePtr, const Tcl_ObjInternalRep *irPtr); /* 639 */
int (*tcl_HasStringRep) (Tcl_Obj *objPtr); /* 640 */
void (*tcl_IncrRefCount) (Tcl_Obj *objPtr); /* 641 */
void (*tcl_DecrRefCount) (Tcl_Obj *objPtr); /* 642 */
int (*tcl_IsShared) (Tcl_Obj *objPtr); /* 643 */
int (*tcl_LinkArray) (Tcl_Interp *interp, const char *varName, void *addr, int type, Tcl_Size size); /* 644 */
|
| ︙ | ︙ | |||
2645 2646 2647 2648 2649 2650 2651 |
Tcl_Size (*tcl_GetEncodingNulLength) (Tcl_Encoding encoding); /* 683 */
int (*tcl_GetWideUIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideUInt *uwidePtr); /* 684 */
Tcl_Obj * (*tcl_DStringToObj) (Tcl_DString *dsPtr); /* 685 */
int (*tcl_UtfNcmp) (const char *s1, const char *s2, size_t n); /* 686 */
int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, size_t n); /* 687 */
Tcl_Obj * (*tcl_NewWideUIntObj) (Tcl_WideUInt wideValue); /* 688 */
void (*tcl_SetWideUIntObj) (Tcl_Obj *objPtr, Tcl_WideUInt uwideValue); /* 689 */
| < < < < < < < < < < < < | | 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 |
Tcl_Size (*tcl_GetEncodingNulLength) (Tcl_Encoding encoding); /* 683 */
int (*tcl_GetWideUIntFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_WideUInt *uwidePtr); /* 684 */
Tcl_Obj * (*tcl_DStringToObj) (Tcl_DString *dsPtr); /* 685 */
int (*tcl_UtfNcmp) (const char *s1, const char *s2, size_t n); /* 686 */
int (*tcl_UtfNcasecmp) (const char *s1, const char *s2, size_t n); /* 687 */
Tcl_Obj * (*tcl_NewWideUIntObj) (Tcl_WideUInt wideValue); /* 688 */
void (*tcl_SetWideUIntObj) (Tcl_Obj *objPtr, Tcl_WideUInt uwideValue); /* 689 */
void (*tclUnusedStubEntry) (void); /* 690 */
} TclStubs;
extern const TclStubs *tclStubsPtr;
#ifdef __cplusplus
}
#endif
|
| ︙ | ︙ | |||
2723 2724 2725 2726 2727 2728 2729 | /* Slot 22 is reserved */ #define Tcl_DbNewByteArrayObj \ (tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */ #define Tcl_DbNewDoubleObj \ (tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */ #define Tcl_DbNewListObj \ (tclStubsPtr->tcl_DbNewListObj) /* 25 */ | < | | | | > > > | < | 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 | /* Slot 22 is reserved */ #define Tcl_DbNewByteArrayObj \ (tclStubsPtr->tcl_DbNewByteArrayObj) /* 23 */ #define Tcl_DbNewDoubleObj \ (tclStubsPtr->tcl_DbNewDoubleObj) /* 24 */ #define Tcl_DbNewListObj \ (tclStubsPtr->tcl_DbNewListObj) /* 25 */ /* Slot 26 is reserved */ #define Tcl_DbNewObj \ (tclStubsPtr->tcl_DbNewObj) /* 27 */ #define Tcl_DbNewStringObj \ (tclStubsPtr->tcl_DbNewStringObj) /* 28 */ #define Tcl_DuplicateObj \ (tclStubsPtr->tcl_DuplicateObj) /* 29 */ #define TclFreeObj \ (tclStubsPtr->tclFreeObj) /* 30 */ #define Tcl_GetBoolean \ (tclStubsPtr->tcl_GetBoolean) /* 31 */ #define Tcl_GetBooleanFromObj \ (tclStubsPtr->tcl_GetBooleanFromObj) /* 32 */ #define Tcl_GetByteArrayFromObj \ (tclStubsPtr->tcl_GetByteArrayFromObj) /* 33 */ #define Tcl_GetDouble \ (tclStubsPtr->tcl_GetDouble) /* 34 */ #define Tcl_GetDoubleFromObj \ (tclStubsPtr->tcl_GetDoubleFromObj) /* 35 */ /* Slot 36 is reserved */ #define Tcl_GetInt \ (tclStubsPtr->tcl_GetInt) /* 37 */ #define Tcl_GetIntFromObj \ (tclStubsPtr->tcl_GetIntFromObj) /* 38 */ #define Tcl_GetLongFromObj \ (tclStubsPtr->tcl_GetLongFromObj) /* 39 */ #define Tcl_GetObjType \ |
| ︙ | ︙ | |||
2766 2767 2768 2769 2770 2771 2772 | (tclStubsPtr->tclListObjGetElements) /* 45 */ #define Tcl_ListObjIndex \ (tclStubsPtr->tcl_ListObjIndex) /* 46 */ #define TclListObjLength \ (tclStubsPtr->tclListObjLength) /* 47 */ #define Tcl_ListObjReplace \ (tclStubsPtr->tcl_ListObjReplace) /* 48 */ | | < | < | < | 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 | (tclStubsPtr->tclListObjGetElements) /* 45 */ #define Tcl_ListObjIndex \ (tclStubsPtr->tcl_ListObjIndex) /* 46 */ #define TclListObjLength \ (tclStubsPtr->tclListObjLength) /* 47 */ #define Tcl_ListObjReplace \ (tclStubsPtr->tcl_ListObjReplace) /* 48 */ /* Slot 49 is reserved */ #define Tcl_NewByteArrayObj \ (tclStubsPtr->tcl_NewByteArrayObj) /* 50 */ #define Tcl_NewDoubleObj \ (tclStubsPtr->tcl_NewDoubleObj) /* 51 */ /* Slot 52 is reserved */ #define Tcl_NewListObj \ (tclStubsPtr->tcl_NewListObj) /* 53 */ /* Slot 54 is reserved */ #define Tcl_NewObj \ (tclStubsPtr->tcl_NewObj) /* 55 */ #define Tcl_NewStringObj \ (tclStubsPtr->tcl_NewStringObj) /* 56 */ /* Slot 57 is reserved */ #define Tcl_SetByteArrayLength \ (tclStubsPtr->tcl_SetByteArrayLength) /* 58 */ #define Tcl_SetByteArrayObj \ (tclStubsPtr->tcl_SetByteArrayObj) /* 59 */ #define Tcl_SetDoubleObj \ (tclStubsPtr->tcl_SetDoubleObj) /* 60 */ /* Slot 61 is reserved */ #define Tcl_SetListObj \ (tclStubsPtr->tcl_SetListObj) /* 62 */ /* Slot 63 is reserved */ #define Tcl_SetObjLength \ (tclStubsPtr->tcl_SetObjLength) /* 64 */ #define Tcl_SetStringObj \ (tclStubsPtr->tcl_SetStringObj) /* 65 */ /* Slot 66 is reserved */ /* Slot 67 is reserved */ #define Tcl_AllowExceptions \ |
| ︙ | ︙ | |||
2815 2816 2817 2818 2819 2820 2821 | (tclStubsPtr->tcl_AsyncDelete) /* 72 */ #define Tcl_AsyncInvoke \ (tclStubsPtr->tcl_AsyncInvoke) /* 73 */ #define Tcl_AsyncMark \ (tclStubsPtr->tcl_AsyncMark) /* 74 */ #define Tcl_AsyncReady \ (tclStubsPtr->tcl_AsyncReady) /* 75 */ | | < < | > | | 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 | (tclStubsPtr->tcl_AsyncDelete) /* 72 */ #define Tcl_AsyncInvoke \ (tclStubsPtr->tcl_AsyncInvoke) /* 73 */ #define Tcl_AsyncMark \ (tclStubsPtr->tcl_AsyncMark) /* 74 */ #define Tcl_AsyncReady \ (tclStubsPtr->tcl_AsyncReady) /* 75 */ /* Slot 76 is reserved */ /* Slot 77 is reserved */ #define Tcl_BadChannelOption \ (tclStubsPtr->tcl_BadChannelOption) /* 78 */ #define Tcl_CallWhenDeleted \ (tclStubsPtr->tcl_CallWhenDeleted) /* 79 */ #define Tcl_CancelIdleCall \ (tclStubsPtr->tcl_CancelIdleCall) /* 80 */ #define Tcl_Close \ (tclStubsPtr->tcl_Close) /* 81 */ #define Tcl_CommandComplete \ (tclStubsPtr->tcl_CommandComplete) /* 82 */ #define Tcl_Concat \ (tclStubsPtr->tcl_Concat) /* 83 */ #define Tcl_ConvertElement \ (tclStubsPtr->tcl_ConvertElement) /* 84 */ #define Tcl_ConvertCountedElement \ |
| ︙ | ︙ | |||
3307 3308 3309 3310 3311 3312 3313 | (tclStubsPtr->tcl_UtfToChar16) /* 336 */ #define Tcl_UtfToUpper \ (tclStubsPtr->tcl_UtfToUpper) /* 337 */ #define Tcl_WriteChars \ (tclStubsPtr->tcl_WriteChars) /* 338 */ #define Tcl_WriteObj \ (tclStubsPtr->tcl_WriteObj) /* 339 */ | | | < | < | | 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 | (tclStubsPtr->tcl_UtfToChar16) /* 336 */ #define Tcl_UtfToUpper \ (tclStubsPtr->tcl_UtfToUpper) /* 337 */ #define Tcl_WriteChars \ (tclStubsPtr->tcl_WriteChars) /* 338 */ #define Tcl_WriteObj \ (tclStubsPtr->tcl_WriteObj) /* 339 */ #define Tcl_GetString \ (tclStubsPtr->tcl_GetString) /* 340 */ /* Slot 341 is reserved */ /* Slot 342 is reserved */ #define Tcl_AlertNotifier \ (tclStubsPtr->tcl_AlertNotifier) /* 343 */ #define Tcl_ServiceModeHook \ (tclStubsPtr->tcl_ServiceModeHook) /* 344 */ #define Tcl_UniCharIsAlnum \ (tclStubsPtr->tcl_UniCharIsAlnum) /* 345 */ #define Tcl_UniCharIsAlpha \ |
| ︙ | ︙ | |||
3462 3463 3464 3465 3466 3467 3468 | (tclStubsPtr->tcl_SpliceChannel) /* 416 */ #define Tcl_ClearChannelHandlers \ (tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */ #define Tcl_IsChannelExisting \ (tclStubsPtr->tcl_IsChannelExisting) /* 418 */ /* Slot 419 is reserved */ /* Slot 420 is reserved */ | < | | 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 | (tclStubsPtr->tcl_SpliceChannel) /* 416 */ #define Tcl_ClearChannelHandlers \ (tclStubsPtr->tcl_ClearChannelHandlers) /* 417 */ #define Tcl_IsChannelExisting \ (tclStubsPtr->tcl_IsChannelExisting) /* 418 */ /* Slot 419 is reserved */ /* Slot 420 is reserved */ /* Slot 421 is reserved */ #define Tcl_CreateHashEntry \ (tclStubsPtr->tcl_CreateHashEntry) /* 422 */ #define Tcl_InitCustomHashTable \ (tclStubsPtr->tcl_InitCustomHashTable) /* 423 */ #define Tcl_InitObjHashTable \ (tclStubsPtr->tcl_InitObjHashTable) /* 424 */ #define Tcl_CommandTraceInfo \ |
| ︙ | ︙ | |||
3997 3998 3999 4000 4001 4002 4003 | (tclStubsPtr->tcl_UtfNcmp) /* 686 */ #define Tcl_UtfNcasecmp \ (tclStubsPtr->tcl_UtfNcasecmp) /* 687 */ #define Tcl_NewWideUIntObj \ (tclStubsPtr->tcl_NewWideUIntObj) /* 688 */ #define Tcl_SetWideUIntObj \ (tclStubsPtr->tcl_SetWideUIntObj) /* 689 */ | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 | (tclStubsPtr->tcl_UtfNcmp) /* 686 */ #define Tcl_UtfNcasecmp \ (tclStubsPtr->tcl_UtfNcasecmp) /* 687 */ #define Tcl_NewWideUIntObj \ (tclStubsPtr->tcl_NewWideUIntObj) /* 688 */ #define Tcl_SetWideUIntObj \ (tclStubsPtr->tcl_SetWideUIntObj) /* 689 */ #define TclUnusedStubEntry \ (tclStubsPtr->tclUnusedStubEntry) /* 690 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #undef TclUnusedStubEntry #ifdef _WIN32 # undef Tcl_CreateFileHandler # undef Tcl_DeleteFileHandler # undef Tcl_GetOpenFile #endif #undef TCL_STORAGE_CLASS |
| ︙ | ︙ | |||
4079 4080 4081 4082 4083 4084 4085 | #define Tcl_UpVar(interp, frameName, varName, localName, flags) \ Tcl_UpVar2(interp, frameName, varName, NULL, localName, flags) #define Tcl_AddErrorInfo(interp, message) \ Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, -1)) #define Tcl_AddObjErrorInfo(interp, message, length) \ Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, length)) #define Tcl_Eval(interp, objPtr) \ | | | | > > > > > > > > > > > > > > > > > | > > > > > > > > | | | | | | > > | | | | | | > | 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 |
#define Tcl_UpVar(interp, frameName, varName, localName, flags) \
Tcl_UpVar2(interp, frameName, varName, NULL, localName, flags)
#define Tcl_AddErrorInfo(interp, message) \
Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, -1))
#define Tcl_AddObjErrorInfo(interp, message, length) \
Tcl_AppendObjToErrorInfo(interp, Tcl_NewStringObj(message, length))
#define Tcl_Eval(interp, objPtr) \
Tcl_EvalEx(interp, objPtr, -1, 0)
#define Tcl_GlobalEval(interp, objPtr) \
Tcl_EvalEx(interp, objPtr, -1, TCL_EVAL_GLOBAL)
#define Tcl_GetStringResult(interp) Tcl_GetString(Tcl_GetObjResult(interp))
#define Tcl_SetResult(interp, result, freeProc) \
do { \
const char *__result = result; \
Tcl_FreeProc *__freeProc = freeProc; \
Tcl_SetObjResult(interp, Tcl_NewStringObj(__result, -1)); \
if (__result != NULL && __freeProc != NULL && __freeProc != TCL_VOLATILE) { \
if (__freeProc == TCL_DYNAMIC) { \
Tcl_Free((void *)__result); \
} else { \
(*__freeProc)((void *)__result); \
} \
} \
} while(0)
#if defined(USE_TCL_STUBS)
# if defined(_WIN32) && defined(_WIN64) && TCL_MAJOR_VERSION < 9
# undef Tcl_GetTime
/* Handle Win64 tk.dll being loaded in Cygwin (only needed for Tcl 8). */
# define Tcl_GetTime(t) \
do { \
struct { \
Tcl_Time now; \
long long reserved; \
} _t; \
_t.reserved = -1; \
tclStubsPtr->tcl_GetTime((&_t.now)); \
if (_t.reserved != -1) { \
_t.now.usec = (long) _t.reserved; \
} \
*(t) = _t.now; \
} while (0)
# endif
# ifdef __CYGWIN__
/* On Cygwin, long is 64-bit while on Win64 long is 32-bit. Therefore
* we have to make sure that all stub entries on Cygwin follow the
* Win64 signature. Cygwin stubbed extensions cannot use those stub
* entries any more, they should use the 64-bit alternatives where
* possible.
*/
# undef Tcl_GetLongFromObj
# undef Tcl_ExprLong
# undef Tcl_ExprLongObj
# define Tcl_GetLongFromObj ((int(*)(Tcl_Interp*,Tcl_Obj*,long*))Tcl_GetWideIntFromObj)
# define Tcl_ExprLong TclExprLong
static inline int TclExprLong(Tcl_Interp *interp, const char *string, long *ptr){
int intValue;
int result = tclStubsPtr->tcl_ExprLong(interp, string, (long *)&intValue);
if (result == TCL_OK) *ptr = (long)intValue;
return result;
}
# define Tcl_ExprLongObj TclExprLongObj
static inline int TclExprLongObj(Tcl_Interp *interp, Tcl_Obj *obj, long *ptr){
int intValue;
int result = tclStubsPtr->tcl_ExprLongObj(interp, obj, (long *)&intValue);
if (result == TCL_OK) *ptr = (long)intValue;
return result;
}
# endif
#endif
#undef Tcl_GetString
#undef Tcl_GetUnicode
#undef Tcl_CreateHashEntry
#define Tcl_GetString(objPtr) \
Tcl_GetStringFromObj(objPtr, (Tcl_Size *)NULL)
#define Tcl_GetUnicode(objPtr) \
Tcl_GetUnicodeFromObj(objPtr, (Tcl_Size *)NULL)
#undef Tcl_GetIndexFromObjStruct
#if TCL_MAJOR_VERSION > 8
# undef Tcl_GetBooleanFromObj
# undef Tcl_GetBoolean
#endif
#if !defined(TCLBOOLWARNING)
#if !defined(__cplusplus) && !defined(BUILD_tcl) && !defined(BUILD_tk) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define TCLBOOLWARNING(boolPtr) (void)(sizeof(struct {_Static_assert(sizeof(*(boolPtr)) <= sizeof(int), "sizeof(boolPtr) too large");int dummy;})),
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* If this gives: "error: size of array ‘_bool_Var’ is negative", it means that sizeof(*boolPtr)>sizeof(int), which is not allowed */
# define TCLBOOLWARNING(boolPtr) ({__attribute__((unused)) char _bool_Var[sizeof(*(boolPtr)) <= sizeof(int) ? 1 : -1];}),
#else
# define TCLBOOLWARNING(boolPtr)
#endif
#endif /* !TCLBOOLWARNING */
#if defined(USE_TCL_STUBS)
#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \
(tclStubsPtr->tcl_GetIndexFromObjStruct((interp), (objPtr), (tablePtr), (offset), (msg), \
(flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr)))
#if TCL_MAJOR_VERSION > 8
#define Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) \
((sizeof(*(boolPtr)) <= sizeof(int)) ? Tcl_GetBoolFromObj(interp, objPtr, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr)) : \
(TCLBOOLWARNING(boolPtr)Tcl_Panic("sizeof(%s) must be <= sizeof(int)", & #boolPtr [1]),TCL_ERROR))
#define Tcl_GetBoolean(interp, src, boolPtr) \
((sizeof(*(boolPtr)) <= sizeof(int)) ? Tcl_GetBool(interp, src, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr)) : \
(TCLBOOLWARNING(boolPtr)Tcl_Panic("sizeof(%s) must be <= sizeof(int)", & #boolPtr [1]),TCL_ERROR))
#endif
#else
#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \
((Tcl_GetIndexFromObjStruct)((interp), (objPtr), (tablePtr), (offset), (msg), \
(flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr)))
#if TCL_MAJOR_VERSION > 8
#define Tcl_GetBooleanFromObj(interp, objPtr, boolPtr) \
((sizeof(*(boolPtr)) <= sizeof(int)) ? Tcl_GetBoolFromObj(interp, objPtr, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr)) : \
(TCLBOOLWARNING(boolPtr)Tcl_Panic("sizeof(%s) must be <= sizeof(int)", & #boolPtr [1]),TCL_ERROR))
#define Tcl_GetBoolean(interp, src, boolPtr) \
((sizeof(*(boolPtr)) <= sizeof(int)) ? Tcl_GetBool(interp, src, (TCL_NULL_OK-2)&(int)sizeof((*(boolPtr))), (char *)(boolPtr)) : \
(TCLBOOLWARNING(boolPtr)Tcl_Panic("sizeof(%s) must be <= sizeof(int)", & #boolPtr [1]),TCL_ERROR))
#endif
#endif
#ifdef TCL_MEM_DEBUG
# undef Tcl_Alloc
# define Tcl_Alloc(x) \
(Tcl_DbCkalloc((x), __FILE__, __LINE__))
# undef Tcl_Free
|
| ︙ | ︙ | |||
4221 4222 4223 4224 4225 4226 4227 | # undef Tcl_GetUniChar # define Tcl_GetUniChar TclGetUniChar # undef Tcl_UtfNcmp # define Tcl_UtfNcmp TclUtfNcmp # undef Tcl_UtfNcasecmp # define Tcl_UtfNcasecmp TclUtfNcasecmp #endif | > | | > > > > | > | < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 |
# undef Tcl_GetUniChar
# define Tcl_GetUniChar TclGetUniChar
# undef Tcl_UtfNcmp
# define Tcl_UtfNcmp TclUtfNcmp
# undef Tcl_UtfNcasecmp
# define Tcl_UtfNcasecmp TclUtfNcasecmp
#endif
#if TCL_MAJOR_VERSION > 8
# if defined(USE_TCL_STUBS)
# define Tcl_WCharToUtfDString (sizeof(wchar_t) != sizeof(short) \
? (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))tclStubsPtr->tcl_UniCharToUtfDString \
: (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_Char16ToUtfDString)
# define Tcl_UtfToWCharDString (sizeof(wchar_t) != sizeof(short) \
? (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))tclStubsPtr->tcl_UtfToUniCharDString \
: (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToChar16DString)
# define Tcl_UtfToWChar (sizeof(wchar_t) != sizeof(short) \
? (Tcl_Size (*)(const char *, wchar_t *))tclStubsPtr->tcl_UtfToUniChar \
: (Tcl_Size (*)(const char *, wchar_t *))Tcl_UtfToChar16)
# define Tcl_WCharLen (sizeof(wchar_t) != sizeof(short) \
? (Tcl_Size (*)(wchar_t *))tclStubsPtr->tcl_UniCharLen \
: (Tcl_Size (*)(wchar_t *))Tcl_Char16Len)
# else
# define Tcl_WCharToUtfDString (sizeof(wchar_t) != sizeof(short) \
? (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_UniCharToUtfDString \
: (char *(*)(const wchar_t *, Tcl_Size, Tcl_DString *))Tcl_Char16ToUtfDString)
# define Tcl_UtfToWCharDString (sizeof(wchar_t) != sizeof(short) \
? (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToUniCharDString \
: (wchar_t *(*)(const char *, Tcl_Size, Tcl_DString *))Tcl_UtfToChar16DString)
# define Tcl_UtfToWChar (sizeof(wchar_t) != sizeof(short) \
? (Tcl_Size (*)(const char *, wchar_t *))Tcl_UtfToUniChar \
: (Tcl_Size (*)(const char *, wchar_t *))Tcl_UtfToChar16)
# define Tcl_WCharLen (sizeof(wchar_t) != sizeof(short) \
? (Tcl_Size (*)(wchar_t *))Tcl_UniCharLen \
: (Tcl_Size (*)(wchar_t *))Tcl_Char16Len)
# endif
#endif
/*
* Deprecated Tcl procedures:
*/
#define Tcl_EvalObj(interp, objPtr) \
Tcl_EvalObjEx(interp, objPtr, 0)
#define Tcl_GlobalEvalObj(interp, objPtr) \
Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_GLOBAL)
#if TCL_MAJOR_VERSION > 8
# undef Tcl_Close
# define Tcl_Close(interp, chan) Tcl_CloseEx(interp, chan, 0)
#endif
#undef TclUtfCharComplete
#undef TclUtfNext
#undef TclUtfPrev
#ifndef TCL_NO_DEPRECATED
# define Tcl_CreateSlave Tcl_CreateChild
# define Tcl_GetSlave Tcl_GetChild
# define Tcl_GetMaster Tcl_GetParent
#endif
/* Protect those 11 functions, make them useless through the stub table */
#undef TclGetStringFromObj
#undef TclGetBytesFromObj
#undef TclGetUnicodeFromObj
#undef TclListObjGetElements
#undef TclListObjLength
#undef TclDictObjSize
#undef TclSplitList
#undef TclSplitPath
#undef TclFSSplitPath
#undef TclParseArgsObjv
#undef TclGetAliasObj
#if TCL_MAJOR_VERSION < 9
/* TIP #627 */
# undef Tcl_CreateObjCommand2
# define Tcl_CreateObjCommand2 Tcl_CreateObjCommand
# undef Tcl_CreateObjTrace2
# define Tcl_CreateObjTrace2 Tcl_CreateObjTrace
# undef Tcl_NRCreateCommand2
# define Tcl_NRCreateCommand2 Tcl_NRCreateCommand
# undef Tcl_NRCallObjProc2
# define Tcl_NRCallObjProc2 Tcl_NRCallObjProc
/* TIP #660 */
# undef Tcl_GetSizeIntFromObj
# define Tcl_GetSizeIntFromObj Tcl_GetIntFromObj
# undef Tcl_GetBytesFromObj
# define Tcl_GetBytesFromObj(interp, objPtr, sizePtr) \
tclStubsPtr->tclGetBytesFromObj((interp), (objPtr), (sizePtr))
# undef Tcl_GetStringFromObj
# define Tcl_GetStringFromObj(objPtr, sizePtr) \
tclStubsPtr->tclGetStringFromObj((objPtr), (sizePtr))
# undef Tcl_GetUnicodeFromObj
# define Tcl_GetUnicodeFromObj(objPtr, sizePtr) \
tclStubsPtr->tclGetUnicodeFromObj((objPtr), (sizePtr))
# undef Tcl_ListObjGetElements
# define Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr) \
tclStubsPtr->tclListObjGetElements((interp), (listPtr), (objcPtr), (objvPtr))
# undef Tcl_ListObjLength
# define Tcl_ListObjLength(interp, listPtr, lengthPtr) \
tclStubsPtr->tclListObjLength((interp), (listPtr), (lengthPtr))
# undef Tcl_DictObjSize
# define Tcl_DictObjSize(interp, dictPtr, sizePtr) \
tclStubsPtr->tclDictObjSize((interp), (dictPtr), (sizePtr))
# undef Tcl_SplitList
# define Tcl_SplitList(interp, listStr, argcPtr, argvPtr) \
tclStubsPtr->tclSplitList((interp), (listStr), (argcPtr), (argvPtr))
# undef Tcl_SplitPath
# define Tcl_SplitPath(path, argcPtr, argvPtr) \
tclStubsPtr->tclSplitPath((path), (argcPtr), (argvPtr))
# undef Tcl_FSSplitPath
# define Tcl_FSSplitPath(pathPtr, lenPtr) \
tclStubsPtr->tclFSSplitPath((pathPtr), (lenPtr))
# undef Tcl_ParseArgsObjv
# define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) \
tclStubsPtr->tclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv))
# undef Tcl_GetAliasObj
# define Tcl_GetAliasObj(interp, childCmd, targetInterpPtr, targetCmdPtr, objcPtr, objv) \
tclStubsPtr->tclGetAliasObj((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (objcPtr), (objv))
# undef Tcl_OpenTcpServerEx
# undef TclZipfs_Mount
# undef TclZipfs_Unmount
# undef TclZipfs_TclLibrary
# undef TclZipfs_MountBuffer
# undef Tcl_FreeInternalRep
# undef Tcl_InitStringRep
# undef Tcl_FetchInternalRep
# undef Tcl_StoreInternalRep
# undef Tcl_HasStringRep
# undef Tcl_LinkArray
# undef Tcl_GetIntForIndex
# undef Tcl_FSTildeExpand
# undef Tcl_ExternalToUtfDStringEx
# undef Tcl_UtfToExternalDStringEx
# undef Tcl_AsyncMarkFromSignal
# undef Tcl_GetBool
# undef Tcl_GetBoolFromObj
# undef Tcl_GetNumberFromObj
# undef Tcl_GetNumber
# undef Tcl_RemoveChannelMode
# undef Tcl_GetEncodingNulLength
# undef Tcl_GetWideUIntFromObj
# undef Tcl_DStringToObj
# undef Tcl_NewWideUIntObj
# undef Tcl_SetWideUIntObj
#elif defined(TCL_8_API)
# undef Tcl_GetByteArrayFromObj
# undef Tcl_GetBytesFromObj
# undef Tcl_GetStringFromObj
# undef Tcl_GetUnicodeFromObj
# undef Tcl_ListObjGetElements
# undef Tcl_ListObjLength
# undef Tcl_DictObjSize
# undef Tcl_SplitList
# undef Tcl_SplitPath
# undef Tcl_FSSplitPath
# undef Tcl_ParseArgsObjv
# undef Tcl_GetAliasObj
# if !defined(USE_TCL_STUBS)
# define Tcl_GetByteArrayFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \
TclGetBytesFromObj(NULL, (objPtr), (sizePtr)) : \
(Tcl_GetBytesFromObj)(NULL, (objPtr), (Tcl_Size *)(void *)(sizePtr)))
# define Tcl_GetBytesFromObj(interp, objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \
TclGetBytesFromObj((interp), (objPtr), (sizePtr)) : \
(Tcl_GetBytesFromObj)((interp), (objPtr), (Tcl_Size *)(void *)(sizePtr)))
# define Tcl_GetStringFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \
(TclGetStringFromObj)((objPtr), (sizePtr)) : \
(Tcl_GetStringFromObj)((objPtr), (Tcl_Size *)(void *)(sizePtr)))
# define Tcl_GetUnicodeFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \
|
| ︙ | ︙ | |||
4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 | # define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ TclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv)) : \ (Tcl_ParseArgsObjv)((interp), (argTable), (Tcl_Size *)(void *)(objcPtr), (objv), (remObjv))) # define Tcl_GetAliasObj(interp, childCmd, targetInterpPtr, targetCmdPtr, objcPtr, objv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ TclGetAliasObj((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (objcPtr), (objv)) : \ (Tcl_GetAliasObj)((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (Tcl_Size *)(void *)(objcPtr), (objv))) # elif !defined(BUILD_tcl) # define Tcl_GetBytesFromObj(interp, objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ tclStubsPtr->tclGetBytesFromObj((interp), (objPtr), (sizePtr)) : \ tclStubsPtr->tcl_GetBytesFromObj((interp), (objPtr), (Tcl_Size *)(void *)(sizePtr))) # define Tcl_GetStringFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ tclStubsPtr->tclGetStringFromObj((objPtr), (sizePtr)) : \ tclStubsPtr->tcl_GetStringFromObj((objPtr), (Tcl_Size *)(void *)(sizePtr))) # define Tcl_GetUnicodeFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ | > > > | 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 | # define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ TclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv)) : \ (Tcl_ParseArgsObjv)((interp), (argTable), (Tcl_Size *)(void *)(objcPtr), (objv), (remObjv))) # define Tcl_GetAliasObj(interp, childCmd, targetInterpPtr, targetCmdPtr, objcPtr, objv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ TclGetAliasObj((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (objcPtr), (objv)) : \ (Tcl_GetAliasObj)((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (Tcl_Size *)(void *)(objcPtr), (objv))) # elif !defined(BUILD_tcl) # define Tcl_GetByteArrayFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ tclStubsPtr->tclGetBytesFromObj(NULL, (objPtr), (sizePtr)) : \ tclStubsPtr->tcl_GetBytesFromObj(NULL, (objPtr), (Tcl_Size *)(void *)(sizePtr))) # define Tcl_GetBytesFromObj(interp, objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ tclStubsPtr->tclGetBytesFromObj((interp), (objPtr), (sizePtr)) : \ tclStubsPtr->tcl_GetBytesFromObj((interp), (objPtr), (Tcl_Size *)(void *)(sizePtr))) # define Tcl_GetStringFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ tclStubsPtr->tclGetStringFromObj((objPtr), (sizePtr)) : \ tclStubsPtr->tcl_GetStringFromObj((objPtr), (Tcl_Size *)(void *)(sizePtr))) # define Tcl_GetUnicodeFromObj(objPtr, sizePtr) (sizeof(*(sizePtr)) <= sizeof(int) ? \ |
| ︙ | ︙ | |||
4368 4369 4370 4371 4372 4373 4374 | # define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ tclStubsPtr->tclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv)) : \ tclStubsPtr->tcl_ParseArgsObjv((interp), (argTable), (Tcl_Size *)(void *)(objcPtr), (objv), (remObjv))) # define Tcl_GetAliasObj(interp, childCmd, targetInterpPtr, targetCmdPtr, objcPtr, objv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ tclStubsPtr->tclGetAliasObj((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (objcPtr), (objv)) : \ tclStubsPtr->tcl_GetAliasObj((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (Tcl_Size *)(void *)(objcPtr), (objv))) # endif /* defined(USE_TCL_STUBS) */ | | > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 | # define Tcl_ParseArgsObjv(interp, argTable, objcPtr, objv, remObjv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ tclStubsPtr->tclParseArgsObjv((interp), (argTable), (objcPtr), (objv), (remObjv)) : \ tclStubsPtr->tcl_ParseArgsObjv((interp), (argTable), (Tcl_Size *)(void *)(objcPtr), (objv), (remObjv))) # define Tcl_GetAliasObj(interp, childCmd, targetInterpPtr, targetCmdPtr, objcPtr, objv) (sizeof(*(objcPtr)) <= sizeof(int) ? \ tclStubsPtr->tclGetAliasObj((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (objcPtr), (objv)) : \ tclStubsPtr->tcl_GetAliasObj((interp), (childCmd), (targetInterpPtr), (targetCmdPtr), (Tcl_Size *)(void *)(objcPtr), (objv))) # endif /* defined(USE_TCL_STUBS) */ #else /* !defined(TCL_8_API) */ # undef Tcl_GetByteArrayFromObj # define Tcl_GetByteArrayFromObj(objPtr, sizePtr) \ Tcl_GetBytesFromObj(NULL, (objPtr), (sizePtr)) #endif /* defined(TCL_8_API) */ #endif /* _TCLDECLS */ |
Changes to generic/tclDictObj.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | struct Dict; /* * Prototypes for functions defined later in this file: */ static void DeleteDict(struct Dict *dict); | | | | | | | | | | | | | | | | | | | | | | | | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
struct Dict;
/*
* Prototypes for functions defined later in this file:
*/
static void DeleteDict(struct Dict *dict);
static Tcl_ObjCmdProc DictAppendCmd;
static Tcl_ObjCmdProc DictCreateCmd;
static Tcl_ObjCmdProc DictExistsCmd;
static Tcl_ObjCmdProc DictFilterCmd;
static Tcl_ObjCmdProc DictGetCmd;
static Tcl_ObjCmdProc DictGetDefCmd;
static Tcl_ObjCmdProc DictIncrCmd;
static Tcl_ObjCmdProc DictInfoCmd;
static Tcl_ObjCmdProc DictKeysCmd;
static Tcl_ObjCmdProc DictLappendCmd;
static Tcl_ObjCmdProc DictMergeCmd;
static Tcl_ObjCmdProc DictRemoveCmd;
static Tcl_ObjCmdProc DictReplaceCmd;
static Tcl_ObjCmdProc DictSetCmd;
static Tcl_ObjCmdProc DictSizeCmd;
static Tcl_ObjCmdProc DictUnsetCmd;
static Tcl_ObjCmdProc DictUpdateCmd;
static Tcl_ObjCmdProc DictValuesCmd;
static Tcl_ObjCmdProc DictWithCmd;
static Tcl_DupInternalRepProc DupDictInternalRep;
static Tcl_FreeInternalRepProc FreeDictInternalRep;
static void InvalidateDictChain(Tcl_Obj *dictObj);
static Tcl_SetFromAnyProc SetDictFromAny;
static Tcl_UpdateStringProc UpdateStringOfDict;
static Tcl_AllocHashEntryProc AllocChainEntry;
static inline void InitChainTable(struct Dict *dict);
static inline void DeleteChainTable(struct Dict *dict);
static inline Tcl_HashEntry * CreateChainEntry(struct Dict *dict,
Tcl_Obj *keyPtr, int *newPtr);
static inline int DeleteChainEntry(struct Dict *dict,
Tcl_Obj *keyPtr);
static Tcl_NRPostProc FinalizeDictUpdate;
static Tcl_NRPostProc FinalizeDictWith;
static Tcl_ObjCmdProc DictForNRCmd;
static Tcl_ObjCmdProc DictMapNRCmd;
static Tcl_NRPostProc DictForLoopCallback;
static Tcl_NRPostProc DictMapLoopCallback;
/*
* Table of dict subcommand names and implementations.
*/
static const EnsembleImplMap implementationMap[] = {
{"append", DictAppendCmd, TclCompileDictAppendCmd, NULL, NULL, 0 },
{"create", DictCreateCmd, TclCompileDictCreateCmd, NULL, NULL, 0 },
{"exists", DictExistsCmd, TclCompileDictExistsCmd, NULL, NULL, 0 },
{"filter", DictFilterCmd, NULL, NULL, NULL, 0 },
{"for", NULL, TclCompileDictForCmd, DictForNRCmd, NULL, 0 },
{"get", DictGetCmd, TclCompileDictGetCmd, NULL, NULL, 0 },
{"getdef", DictGetDefCmd, TclCompileDictGetWithDefaultCmd, NULL,NULL,0},
{"getwithdefault", DictGetDefCmd, TclCompileDictGetWithDefaultCmd,
NULL, NULL, 0 },
{"incr", DictIncrCmd, TclCompileDictIncrCmd, NULL, NULL, 0 },
{"info", DictInfoCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
{"keys", DictKeysCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
{"lappend", DictLappendCmd, TclCompileDictLappendCmd, NULL, NULL, 0 },
{"map", NULL, TclCompileDictMapCmd, DictMapNRCmd, NULL, 0 },
{"merge", DictMergeCmd, TclCompileDictMergeCmd, NULL, NULL, 0 },
{"remove", DictRemoveCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0 },
{"replace", DictReplaceCmd, NULL, NULL, NULL, 0 },
{"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 },
{"size", DictSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0 },
{"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 },
{"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 },
{"values", DictValuesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0 },
{"with", DictWithCmd, TclCompileDictWithCmd, NULL, NULL, 0 },
{NULL, NULL, NULL, NULL, NULL, 0}
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
/*
* The structure below defines the dictionary object type by means of
* functions that can be invoked by generic object code.
*/
const Tcl_ObjType tclDictType = {
"dict",
| | | | | | | | | | | | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
/*
* The structure below defines the dictionary object type by means of
* functions that can be invoked by generic object code.
*/
const Tcl_ObjType tclDictType = {
"dict",
FreeDictInternalRep, /* freeIntRepProc */
DupDictInternalRep, /* dupIntRepProc */
UpdateStringOfDict, /* updateStringProc */
SetDictFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define DictSetInternalRep(objPtr, dictRepPtr) \
do { \
Tcl_ObjInternalRep ir; \
ir.twoPtrValue.ptr1 = (dictRepPtr); \
ir.twoPtrValue.ptr2 = NULL; \
Tcl_StoreInternalRep((objPtr), &tclDictType, &ir); \
} while (0)
#define DictGetInternalRep(objPtr, dictRepPtr) \
do { \
const Tcl_ObjInternalRep *irPtr; \
irPtr = TclFetchInternalRep((objPtr), &tclDictType); \
(dictRepPtr) = irPtr ? (Dict *)irPtr->twoPtrValue.ptr1 : NULL; \
} while (0)
/*
* The type of the specially adapted version of the Tcl_Obj*-containing hash
* table defined in the tclObj.c code. This version differs in that it
* allocates a bit more space in each hash entry in order to hold the pointers
* used to keep the hash entries in a linked list.
*
* Note that this type of hash table is *only* suitable for direct use in
* *this* file. Everything else should use the dict iterator API.
*/
static const Tcl_HashKeyType chainHashType = {
TCL_HASH_KEY_TYPE_VERSION,
TCL_HASH_KEY_DIRECT_COMPARE, /* allows compare keys by pointers */
TclHashObjKey,
TclCompareObjKeys,
AllocChainEntry,
TclFreeObjEntry
};
/*
|
| ︙ | ︙ | |||
541 542 543 544 545 546 547 |
/*
* Pass 2: copy into string rep buffer.
*/
dst = Tcl_InitStringRep(dictPtr, NULL, bytesNeeded - 1);
TclOOM(dst, bytesNeeded);
for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
| < | < | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 |
/*
* Pass 2: copy into string rep buffer.
*/
dst = Tcl_InitStringRep(dictPtr, NULL, bytesNeeded - 1);
TclOOM(dst, bytesNeeded);
for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
flagPtr[i] |= ( i ? TCL_DONT_QUOTE_HASH : 0 );
keyPtr = (Tcl_Obj *)Tcl_GetHashKey(&dict->table, &cPtr->entry);
elem = TclGetStringFromObj(keyPtr, &length);
dst += TclConvertElement(elem, length, dst, flagPtr[i]);
*dst++ = ' ';
flagPtr[i+1] |= TCL_DONT_QUOTE_HASH;
valuePtr = (Tcl_Obj *)Tcl_GetHashValue(&cPtr->entry);
|
| ︙ | ︙ | |||
611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
/* Cannot fail, we already know the Tcl_ObjType is "list". */
TclListObjGetElements(NULL, objPtr, &objc, &objv);
if (objc & 1) {
goto missingValue;
}
for (i=0 ; i<objc ; i+=2) {
/* Store key and value in the hash table we're building. */
hPtr = CreateChainEntry(dict, objv[i], &isNew);
if (!isNew) {
Tcl_Obj *discardedValue = (Tcl_Obj *)Tcl_GetHashValue(hPtr);
/*
* Not really a well-formed dictionary as there are duplicate
| > | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
/* Cannot fail, we already know the Tcl_ObjType is "list". */
TclListObjGetElements(NULL, objPtr, &objc, &objv);
if (objc & 1) {
goto missingValue;
}
for (i=0 ; i<objc ; i+=2) {
/* Store key and value in the hash table we're building. */
hPtr = CreateChainEntry(dict, objv[i], &isNew);
if (!isNew) {
Tcl_Obj *discardedValue = (Tcl_Obj *)Tcl_GetHashValue(hPtr);
/*
* Not really a well-formed dictionary as there are duplicate
|
| ︙ | ︙ | |||
1261 1262 1263 1264 1265 1266 1267 | * Removes a reference to the dictionary's internal rep. * *---------------------------------------------------------------------- */ void Tcl_DictObjDone( | | | 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 |
* Removes a reference to the dictionary's internal rep.
*
*----------------------------------------------------------------------
*/
void
Tcl_DictObjDone(
Tcl_DictSearch *searchPtr) /* Pointer to a hash search context. */
{
Dict *dict;
if (searchPtr->epoch) {
searchPtr->epoch = 0;
dict = (Dict *) searchPtr->dictionaryPtr;
if (dict->refCount-- <= 1) {
|
| ︙ | ︙ | |||
1466 1467 1468 1469 1470 1471 1472 |
int line)
{
Tcl_Obj *dictPtr;
Dict *dict;
TclDbNewObj(dictPtr, file, line);
TclInvalidateStringRep(dictPtr);
| | | 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 |
int line)
{
Tcl_Obj *dictPtr;
Dict *dict;
TclDbNewObj(dictPtr, file, line);
TclInvalidateStringRep(dictPtr);
dict = (Dict *)Tcl_Alloc(sizeof(Dict));
InitChainTable(dict);
dict->epoch = 1;
dict->chain = NULL;
dict->refCount = 1;
DictSetInternalRep(dictPtr, dict);
return dictPtr;
}
|
| ︙ | ︙ | |||
1655 1656 1657 1658 1659 1660 1661 |
*----------------------------------------------------------------------
*/
static int
DictCreateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 |
*----------------------------------------------------------------------
*/
static int
DictCreateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictObj;
int i;
/*
* Must have an even number of arguments; note that number of preceding
* arguments (i.e. "dict create" is also even, which makes this much
* easier.)
*/
|
| ︙ | ︙ | |||
1705 1706 1707 1708 1709 1710 1711 |
*----------------------------------------------------------------------
*/
static int
DictGetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 |
*----------------------------------------------------------------------
*/
static int
DictGetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *valuePtr = NULL;
int result;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...?");
|
| ︙ | ︙ | |||
1798 1799 1800 1801 1802 1803 1804 |
*----------------------------------------------------------------------
*/
static int
DictGetDefCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 |
*----------------------------------------------------------------------
*/
static int
DictGetDefCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *keyPtr, *valuePtr, *defaultPtr;
Tcl_Obj *const *keyPath;
int numKeys;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...? key default");
return TCL_ERROR;
}
/*
|
| ︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 |
*----------------------------------------------------------------------
*/
static int
DictReplaceCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 |
*----------------------------------------------------------------------
*/
static int
DictReplaceCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr;
int i;
if ((objc < 2) || (objc & 1)) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key value ...?");
return TCL_ERROR;
}
dictPtr = objv[1];
|
| ︙ | ︙ | |||
1911 1912 1913 1914 1915 1916 1917 |
*----------------------------------------------------------------------
*/
static int
DictRemoveCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 |
*----------------------------------------------------------------------
*/
static int
DictRemoveCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr;
int i;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?key ...?");
return TCL_ERROR;
}
dictPtr = objv[1];
|
| ︙ | ︙ | |||
1959 1960 1961 1962 1963 1964 1965 |
*----------------------------------------------------------------------
*/
static int
DictMergeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 |
*----------------------------------------------------------------------
*/
static int
DictMergeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *targetObj, *keyObj = NULL, *valueObj = NULL;
int allocatedDict = 0;
int i, done;
Tcl_DictSearch search;
if (objc == 1) {
/*
* No dictionary arguments; return default (empty value).
*/
|
| ︙ | ︙ | |||
2046 2047 2048 2049 2050 2051 2052 |
*----------------------------------------------------------------------
*/
static int
DictKeysCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 |
*----------------------------------------------------------------------
*/
static int
DictKeysCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *listPtr;
const char *pattern = NULL;
if (objc!=2 && objc!=3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary ?pattern?");
|
| ︙ | ︙ | |||
2125 2126 2127 2128 2129 2130 2131 |
*----------------------------------------------------------------------
*/
static int
DictValuesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 |
*----------------------------------------------------------------------
*/
static int
DictValuesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *valuePtr = NULL, *listPtr;
Tcl_DictSearch search;
int done;
const char *pattern;
|
| ︙ | ︙ | |||
2185 2186 2187 2188 2189 2190 2191 |
*----------------------------------------------------------------------
*/
static int
DictSizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 |
*----------------------------------------------------------------------
*/
static int
DictSizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int result;
Tcl_Size size;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary");
|
| ︙ | ︙ | |||
2278 2279 2280 2281 2282 2283 2284 |
*----------------------------------------------------------------------
*/
static int
DictExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 |
*----------------------------------------------------------------------
*/
static int
DictExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *valuePtr;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary key ?key ...?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2320 2321 2322 2323 2324 2325 2326 |
*----------------------------------------------------------------------
*/
static int
DictInfoCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 |
*----------------------------------------------------------------------
*/
static int
DictInfoCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Dict *dict;
char *statsStr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary");
|
| ︙ | ︙ | |||
2364 2365 2366 2367 2368 2369 2370 |
*----------------------------------------------------------------------
*/
static int
DictIncrCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 |
*----------------------------------------------------------------------
*/
static int
DictIncrCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int code = TCL_OK;
Tcl_Obj *dictPtr, *valuePtr = NULL;
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?increment?");
|
| ︙ | ︙ | |||
2485 2486 2487 2488 2489 2490 2491 |
*----------------------------------------------------------------------
*/
static int
DictLappendCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | < | 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 |
*----------------------------------------------------------------------
*/
static int
DictLappendCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *valuePtr, *resultPtr;
int i, allocatedDict = 0, allocatedValue = 0;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?value ...?");
return TCL_ERROR;
}
dictPtr = Tcl_ObjGetVar2(interp, objv[1], NULL, 0);
|
| ︙ | ︙ | |||
2573 2574 2575 2576 2577 2578 2579 |
*----------------------------------------------------------------------
*/
static int
DictAppendCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 |
*----------------------------------------------------------------------
*/
static int
DictAppendCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *valuePtr, *resultPtr;
int allocatedDict = 0;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?value ...?");
|
| ︙ | ︙ | |||
2675 2676 2677 2678 2679 2680 2681 |
*----------------------------------------------------------------------
*/
static int
DictForNRCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 |
*----------------------------------------------------------------------
*/
static int
DictForNRCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *scriptObj, *keyVarObj, *valueVarObj;
Tcl_Obj **varv, *keyObj, *valueObj;
Tcl_DictSearch *searchPtr;
Tcl_Size varc;
|
| ︙ | ︙ | |||
2750 2751 2752 2753 2754 2755 2756 |
goto error;
}
/*
* Run the script.
*/
| | | | 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 |
goto error;
}
/*
* Run the script.
*/
TclNRAddCallback(interp, DictForLoopCallback, searchPtr, keyVarObj,
valueVarObj, scriptObj);
return TclNREvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3);
/*
* For unwinding everything on error.
*/
error:
|
| ︙ | ︙ | |||
2832 2833 2834 2835 2836 2837 2838 |
goto done;
}
/*
* Run the script.
*/
| | | | 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 |
goto done;
}
/*
* Run the script.
*/
TclNRAddCallback(interp, DictForLoopCallback, searchPtr, keyVarObj,
valueVarObj, scriptObj);
return TclNREvalObjEx(interp, scriptObj, 0, iPtr->cmdFramePtr, 3);
/*
* For unwinding everything once the iterating is done.
*/
done:
|
| ︙ | ︙ | |||
2871 2872 2873 2874 2875 2876 2877 |
*----------------------------------------------------------------------
*/
static int
DictMapNRCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 |
*----------------------------------------------------------------------
*/
static int
DictMapNRCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj **varv, *keyObj, *valueObj;
DictMapStorage *storagePtr;
Tcl_Size varc;
int done;
|
| ︙ | ︙ | |||
2954 2955 2956 2957 2958 2959 2960 |
}
TclDecrRefCount(valueObj);
/*
* Run the script.
*/
| | < | 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 |
}
TclDecrRefCount(valueObj);
/*
* Run the script.
*/
TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL);
return TclNREvalObjEx(interp, storagePtr->scriptObj, 0,
iPtr->cmdFramePtr, 3);
/*
* For unwinding everything on error.
*/
|
| ︙ | ︙ | |||
3045 3046 3047 3048 3049 3050 3051 |
}
TclDecrRefCount(valueObj);
/*
* Run the script.
*/
| | < | 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 |
}
TclDecrRefCount(valueObj);
/*
* Run the script.
*/
TclNRAddCallback(interp, DictMapLoopCallback, storagePtr, NULL,NULL,NULL);
return TclNREvalObjEx(interp, storagePtr->scriptObj, 0,
iPtr->cmdFramePtr, 3);
/*
* For unwinding everything once the iterating is done.
*/
|
| ︙ | ︙ | |||
3086 3087 3088 3089 3090 3091 3092 |
*----------------------------------------------------------------------
*/
static int
DictSetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 |
*----------------------------------------------------------------------
*/
static int
DictSetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *resultPtr;
int result, allocatedDict = 0;
if (objc < 4) {
Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?key ...? value");
|
| ︙ | ︙ | |||
3146 3147 3148 3149 3150 3151 3152 |
*----------------------------------------------------------------------
*/
static int
DictUnsetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 |
*----------------------------------------------------------------------
*/
static int
DictUnsetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *dictPtr, *resultPtr;
int result, allocatedDict = 0;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictVarName key ?key ...?");
|
| ︙ | ︙ | |||
3205 3206 3207 3208 3209 3210 3211 |
*----------------------------------------------------------------------
*/
static int
DictFilterCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 |
*----------------------------------------------------------------------
*/
static int
DictFilterCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
static const char *const filters[] = {
"key", "script", "value", NULL
};
enum FilterTypes {
|
| ︙ | ︙ | |||
3227 3228 3229 3230 3231 3232 3233 |
const char *pattern;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary filterType ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[2], filters, "filterType",
| | | 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 |
const char *pattern;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictionary filterType ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[2], filters, "filterType",
0, &index) != TCL_OK) {
return TCL_ERROR;
}
switch (index) {
case FILTER_KEYS:
/*
* Create a dictionary whose keys all match a certain pattern.
|
| ︙ | ︙ | |||
3279 3280 3281 3282 3283 3284 3285 |
/*
* Can't optimize this match for trivial globbing: would disturb
* order.
*/
resultObj = Tcl_NewDictObj();
while (!done) {
| | | 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 |
/*
* Can't optimize this match for trivial globbing: would disturb
* order.
*/
resultObj = Tcl_NewDictObj();
while (!done) {
int i;
for (i=3 ; i<objc ; i++) {
pattern = TclGetString(objv[i]);
if (Tcl_StringMatch(TclGetString(keyObj), pattern)) {
Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj);
break; /* stop inner loop */
}
|
| ︙ | ︙ | |||
3305 3306 3307 3308 3309 3310 3311 |
if (Tcl_DictObjFirst(interp, objv[1], &search,
&keyObj, &valueObj, &done) != TCL_OK) {
return TCL_ERROR;
}
resultObj = Tcl_NewDictObj();
while (!done) {
| | | 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 |
if (Tcl_DictObjFirst(interp, objv[1], &search,
&keyObj, &valueObj, &done) != TCL_OK) {
return TCL_ERROR;
}
resultObj = Tcl_NewDictObj();
while (!done) {
int i;
for (i=3 ; i<objc ; i++) {
pattern = TclGetString(objv[i]);
if (Tcl_StringMatch(TclGetString(valueObj), pattern)) {
Tcl_DictObjPut(NULL, resultObj, keyObj, valueObj);
break; /* stop inner loop */
}
|
| ︙ | ︙ | |||
3490 3491 3492 3493 3494 3495 3496 |
*----------------------------------------------------------------------
*/
static int
DictUpdateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | > | | 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 |
*----------------------------------------------------------------------
*/
static int
DictUpdateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *dictPtr, *objPtr;
int i;
Tcl_Size dummy;
if (objc < 5 || !(objc & 1)) {
Tcl_WrongNumArgs(interp, 1, objv,
"dictVarName key varName ?key varName ...? script");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3535 3536 3537 3538 3539 3540 3541 |
* Execute the body after setting up the NRE handler to process the
* results.
*/
objPtr = Tcl_NewListObj(objc-3, objv+2);
Tcl_IncrRefCount(objPtr);
Tcl_IncrRefCount(objv[1]);
| | | 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 |
* Execute the body after setting up the NRE handler to process the
* results.
*/
objPtr = Tcl_NewListObj(objc-3, objv+2);
Tcl_IncrRefCount(objPtr);
Tcl_IncrRefCount(objv[1]);
TclNRAddCallback(interp, FinalizeDictUpdate, objv[1], objPtr, NULL,NULL);
return TclNREvalObjEx(interp, objv[objc-1], 0, iPtr->cmdFramePtr, objc-1);
}
static int
FinalizeDictUpdate(
void *data[],
|
| ︙ | ︙ | |||
3648 3649 3650 3651 3652 3653 3654 |
*----------------------------------------------------------------------
*/
static int
DictWithCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 |
*----------------------------------------------------------------------
*/
static int
DictWithCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *dictPtr, *keysPtr, *pathPtr;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "dictVarName ?key ...? script");
|
| ︙ | ︙ | |||
3852 3853 3854 3855 3856 3857 3858 |
* variable, or NULL if the variable is a
* scalar. */
Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or
* the name of a variable. NULL if the 'index'
* parameter is >= 0 */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
| | | | 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 |
* variable, or NULL if the variable is a
* scalar. */
Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or
* the name of a variable. NULL if the 'index'
* parameter is >= 0 */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
int index, /* Index into the local variable table of the
* variable, or -1. Only used when part1Ptr is
* NULL. */
int pathc, /* The number of elements in the path into the
* dictionary. */
Tcl_Obj *const pathv[], /* The elements of the path to the subdict. */
Tcl_Obj *keysPtr) /* List of keys to be synchronized. This is
* the result value from TclDictWithInit. */
{
Tcl_Obj *dictPtr, *leafPtr, *valPtr;
Tcl_Size i, allocdict, keyc;
|
| ︙ | ︙ | |||
3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 |
TclDecrRefCount(dictPtr);
}
return TCL_ERROR;
}
return TCL_OK;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > | 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 |
TclDecrRefCount(dictPtr);
}
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclInitDictCmd --
*
* This function is create the "dict" Tcl command. See the user
* documentation for details on what it does, and TIP#111 for the formal
* specification.
*
* Results:
* A Tcl command handle.
*
* Side effects:
* May advance compilation epoch.
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitDictCmd(
Tcl_Interp *interp)
{
return TclMakeEnsemble(interp, "dict", implementationMap);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclDisassemble.c.
| ︙ | ︙ | |||
9 10 11 12 13 14 15 | * Copyright © 2013-2016 Donal K. Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | * Copyright © 2013-2016 Donal K. Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" #include "tclOOInt.h" /* * Prototypes for procedures defined later in this file: */ |
| ︙ | ︙ | |||
33 34 35 36 37 38 39 |
/*
* The structure below defines an instruction name Tcl object to allow
* reporting of inner contexts in errorstack without string allocation.
*/
static const Tcl_ObjType instNameType = {
| | | | | | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
/*
* The structure below defines an instruction name Tcl object to allow
* reporting of inner contexts in errorstack without string allocation.
*/
static const Tcl_ObjType instNameType = {
"instname", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
UpdateStringOfInstName, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define InstNameSetInternalRep(objPtr, inst) \
do { \
Tcl_ObjInternalRep ir; \
ir.wideValue = (inst); \
|
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
*----------------------------------------------------------------------
*/
void
TclDebugPrintByteCodeObj(
Tcl_Obj *objPtr) /* The bytecode object to disassemble. */
{
| | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
*----------------------------------------------------------------------
*/
void
TclDebugPrintByteCodeObj(
Tcl_Obj *objPtr) /* The bytecode object to disassemble. */
{
if (tclTraceCompile >= 2) {
Tcl_Obj *bufPtr = DisassembleByteCodeObj(objPtr);
fprintf(stdout, "\n%s", TclGetString(bufPtr));
Tcl_DecrRefCount(bufPtr);
fflush(stdout);
}
}
|
| ︙ | ︙ | |||
276 277 278 279 280 281 282 |
numCmds = codePtr->numCommands;
/*
* Print header lines describing the ByteCode.
*/
Tcl_AppendPrintfToObj(bufferObj,
| | < < | < | < < < | < | < | < < | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
numCmds = codePtr->numCommands;
/*
* Print header lines describing the ByteCode.
*/
Tcl_AppendPrintfToObj(bufferObj,
"ByteCode %p, refCt %" TCL_SIZE_MODIFIER "d, epoch %" TCL_SIZE_MODIFIER "d, interp %p (epoch %" TCL_SIZE_MODIFIER "d)\n",
codePtr, codePtr->refCount, codePtr->compileEpoch, iPtr, iPtr->compileEpoch);
Tcl_AppendToObj(bufferObj, " Source ", -1);
PrintSourceToObj(bufferObj, codePtr->source,
TclMin(codePtr->numSrcBytes, 55));
GetLocationInformation(codePtr->procPtr, &fileObj, &line);
if (line >= 0 && fileObj != NULL) {
Tcl_AppendPrintfToObj(bufferObj, "\n File \"%s\" Line %d",
TclGetString(fileObj), line);
}
Tcl_AppendPrintfToObj(bufferObj,
"\n Cmds %d, src %" TCL_SIZE_MODIFIER "d, inst %" TCL_SIZE_MODIFIER "d, litObjs %" TCL_SIZE_MODIFIER "d, aux %" TCL_SIZE_MODIFIER "d, stkDepth %" TCL_SIZE_MODIFIER "d, code/src %.2f\n",
numCmds, codePtr->numSrcBytes, codePtr->numCodeBytes,
codePtr->numLitObjects, codePtr->numAuxDataItems,
codePtr->maxStackDepth,
#ifdef TCL_COMPILE_STATS
codePtr->numSrcBytes?
codePtr->structureSize/(float)codePtr->numSrcBytes :
#endif
0.0);
#ifdef TCL_COMPILE_STATS
Tcl_AppendPrintfToObj(bufferObj,
" Code %" TCL_Z_MODIFIER "u = header %" TCL_Z_MODIFIER "u+inst %" TCL_SIZE_MODIFIER "d+litObj %"
TCL_Z_MODIFIER "u+exc %" TCL_Z_MODIFIER "u+aux %" TCL_Z_MODIFIER "u+cmdMap %" TCL_SIZE_MODIFIER "d\n",
codePtr->structureSize,
offsetof(ByteCode, localCachePtr),
codePtr->numCodeBytes,
codePtr->numLitObjects * sizeof(Tcl_Obj *),
codePtr->numExceptRanges*sizeof(ExceptionRange),
codePtr->numAuxDataItems * sizeof(AuxData),
codePtr->numCmdLocBytes);
#endif /* TCL_COMPILE_STATS */
/*
* If the ByteCode is the compiled body of a Tcl procedure, print
* information about that procedure. Note that we don't know the
* procedure's name since ByteCode's can be shared among procedures.
*/
if (codePtr->procPtr != NULL) {
Proc *procPtr = codePtr->procPtr;
Tcl_Size numCompiledLocals = procPtr->numCompiledLocals;
Tcl_AppendPrintfToObj(bufferObj,
" Proc %p, refCt %" TCL_SIZE_MODIFIER "d, args %" TCL_SIZE_MODIFIER "d, compiled locals %" TCL_SIZE_MODIFIER "d\n",
procPtr, procPtr->refCount, procPtr->numArgs,
numCompiledLocals);
if (numCompiledLocals > 0) {
CompiledLocal *localPtr = procPtr->firstLocalPtr;
for (i = 0; i < numCompiledLocals; i++) {
Tcl_AppendPrintfToObj(bufferObj,
|
| ︙ | ︙ | |||
362 363 364 365 366 367 368 |
}
/*
* Print the ExceptionRange array.
*/
if ((int)codePtr->numExceptRanges > 0) {
| | < < | < < | < < | < | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
}
/*
* Print the ExceptionRange array.
*/
if ((int)codePtr->numExceptRanges > 0) {
Tcl_AppendPrintfToObj(bufferObj, " Exception ranges %" TCL_SIZE_MODIFIER "d, depth %" TCL_SIZE_MODIFIER "d:\n",
codePtr->numExceptRanges, codePtr->maxExceptDepth);
for (i = 0; i < (int)codePtr->numExceptRanges; i++) {
ExceptionRange *rangePtr = &codePtr->exceptArrayPtr[i];
Tcl_AppendPrintfToObj(bufferObj,
" %" TCL_SIZE_MODIFIER "d: level %" TCL_SIZE_MODIFIER "d, %s, pc %" TCL_SIZE_MODIFIER "d-%" TCL_SIZE_MODIFIER "d, ",
i, rangePtr->nestingLevel,
(rangePtr->type==LOOP_EXCEPTION_RANGE ? "loop" : "catch"),
rangePtr->codeOffset,
(rangePtr->codeOffset + rangePtr->numCodeBytes - 1));
switch (rangePtr->type) {
case LOOP_EXCEPTION_RANGE:
Tcl_AppendPrintfToObj(bufferObj, "continue %" TCL_SIZE_MODIFIER "d, break %" TCL_SIZE_MODIFIER "d\n",
rangePtr->continueOffset, rangePtr->breakOffset);
break;
case CATCH_EXCEPTION_RANGE:
Tcl_AppendPrintfToObj(bufferObj, "catch %" TCL_SIZE_MODIFIER "d\n",
rangePtr->catchOffset);
break;
default:
Tcl_Panic("DisassembleByteCodeObj: bad ExceptionRange type %d",
rangePtr->type);
}
}
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 |
srcLen = TclGetInt4AtPtr(srcLengthNext);
srcLengthNext += 4;
} else {
srcLen = TclGetInt1AtPtr(srcLengthNext);
srcLengthNext++;
}
| | < | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
srcLen = TclGetInt4AtPtr(srcLengthNext);
srcLengthNext += 4;
} else {
srcLen = TclGetInt1AtPtr(srcLengthNext);
srcLengthNext++;
}
Tcl_AppendPrintfToObj(bufferObj, "%s%4" TCL_SIZE_MODIFIER "d: pc %d-%d, src %d-%d",
((i % 2)? " " : "\n "),
(i+1), codeOffset, (codeOffset + codeLen - 1),
srcOffset, (srcOffset + srcLen - 1));
}
if (numCmds > 0) {
Tcl_AppendToObj(bufferObj, "\n", -1);
}
|
| ︙ | ︙ | |||
573 574 575 576 577 578 579 |
AuxData *auxPtr = NULL;
suffixBuffer[0] = '\0';
Tcl_AppendPrintfToObj(bufferObj, "(%u) %s ", pcOffset, instDesc->name);
for (i = 0; i < instDesc->numOperands; i++) {
switch (instDesc->opTypes[i]) {
case OPERAND_INT1:
| | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 |
AuxData *auxPtr = NULL;
suffixBuffer[0] = '\0';
Tcl_AppendPrintfToObj(bufferObj, "(%u) %s ", pcOffset, instDesc->name);
for (i = 0; i < instDesc->numOperands; i++) {
switch (instDesc->opTypes[i]) {
case OPERAND_INT1:
opnd = TclGetInt1AtPtr(pc+numBytes); numBytes++;
Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
break;
case OPERAND_INT4:
opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
break;
case OPERAND_UINT1:
opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
Tcl_AppendPrintfToObj(bufferObj, "%u ", opnd);
break;
case OPERAND_UINT4:
opnd = TclGetUInt4AtPtr(pc+numBytes); numBytes += 4;
if (opCode == INST_START_CMD) {
snprintf(suffixBuffer+strlen(suffixBuffer), sizeof(suffixBuffer) - strlen(suffixBuffer),
", %u cmds start here", opnd);
}
Tcl_AppendPrintfToObj(bufferObj, "%u ", opnd);
break;
case OPERAND_OFFSET1:
opnd = TclGetInt1AtPtr(pc+numBytes); numBytes++;
snprintf(suffixBuffer, sizeof(suffixBuffer), "pc %u", pcOffset+opnd);
Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
break;
case OPERAND_OFFSET4:
opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
if (opCode == INST_START_CMD) {
snprintf(suffixBuffer, sizeof(suffixBuffer), "next cmd at pc %u", pcOffset+opnd);
} else {
snprintf(suffixBuffer, sizeof(suffixBuffer), "pc %u", pcOffset+opnd);
}
Tcl_AppendPrintfToObj(bufferObj, "%+d ", opnd);
break;
case OPERAND_LIT1:
opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
suffixObj = codePtr->objArrayPtr[opnd];
Tcl_AppendPrintfToObj(bufferObj, "%u ", opnd);
break;
case OPERAND_LIT4:
opnd = TclGetUInt4AtPtr(pc+numBytes); numBytes += 4;
suffixObj = codePtr->objArrayPtr[opnd];
Tcl_AppendPrintfToObj(bufferObj, "%u ", opnd);
break;
case OPERAND_AUX4:
opnd = TclGetUInt4AtPtr(pc+numBytes); numBytes += 4;
Tcl_AppendPrintfToObj(bufferObj, "%u ", opnd);
auxPtr = &codePtr->auxDataArrayPtr[opnd];
break;
case OPERAND_IDX4:
opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
if (opnd >= -1) {
Tcl_AppendPrintfToObj(bufferObj, "%d ", opnd);
} else if (opnd == -2) {
Tcl_AppendPrintfToObj(bufferObj, "end ");
} else {
Tcl_AppendPrintfToObj(bufferObj, "end-%d ", -2-opnd);
}
break;
case OPERAND_LVT1:
opnd = TclGetUInt1AtPtr(pc+numBytes);
numBytes++;
goto printLVTindex;
case OPERAND_LVT4:
opnd = TclGetUInt4AtPtr(pc+numBytes);
numBytes += 4;
printLVTindex:
if (localPtr != NULL) {
if (opnd >= localCt) {
Tcl_Panic("FormatInstruction: bad local var index %u (%" TCL_SIZE_MODIFIER "d locals)",
opnd, localCt);
}
for (j = 0; j < opnd; j++) {
localPtr = localPtr->nextPtr;
}
if (TclIsVarTemporary(localPtr)) {
snprintf(suffixBuffer, sizeof(suffixBuffer), "temp var %u", opnd);
} else {
snprintf(suffixBuffer, sizeof(suffixBuffer), "var ");
suffixSrc = localPtr->name;
}
}
Tcl_AppendPrintfToObj(bufferObj, "%%v%u ", opnd);
break;
case OPERAND_SCLS1:
opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
Tcl_AppendPrintfToObj(bufferObj, "%s ",
tclStringClassTable[opnd].name);
break;
case OPERAND_NONE:
default:
break;
}
}
if (suffixObj) {
|
| ︙ | ︙ | |||
822 823 824 825 826 827 828 |
break;
case INST_SYNTAX:
case INST_RETURN_IMM:
objc = 2;
break;
| | | < | < | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 |
break;
case INST_SYNTAX:
case INST_RETURN_IMM:
objc = 2;
break;
case INST_INVOKE_STK4:
objc = TclGetUInt4AtPtr(pc+1);
break;
case INST_INVOKE_STK1:
objc = TclGetUInt1AtPtr(pc+1);
break;
}
result = iPtr->innerContext;
if (Tcl_IsShared(result)) {
Tcl_DecrRefCount(result);
iPtr->innerContext = result = Tcl_NewListObj(objc + 1, NULL);
Tcl_IncrRefCount(result);
|
| ︙ | ︙ | |||
908 909 910 911 912 913 914 |
*----------------------------------------------------------------------
*/
static void
UpdateStringOfInstName(
Tcl_Obj *objPtr)
{
| | | 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 |
*----------------------------------------------------------------------
*/
static void
UpdateStringOfInstName(
Tcl_Obj *objPtr)
{
size_t inst; /* NOTE: We know this is really an unsigned char */
char *dst;
InstNameGetInternalRep(objPtr, inst);
if (inst >= LAST_INST_OPCODE) {
dst = Tcl_InitStringRep(objPtr, NULL, TCL_INTEGER_SPACE + 5);
TclOOM(dst, TCL_INTEGER_SPACE + 5);
|
| ︙ | ︙ | |||
1104 1105 1106 1107 1108 1109 1110 |
opnd = pc + 1;
for (i=0 ; i<instDesc->numOperands ; i++) {
switch (instDesc->opTypes[i]) {
case OPERAND_INT1:
val = TclGetInt1AtPtr(opnd);
opnd += 1;
goto formatNumber;
| < < < | 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 |
opnd = pc + 1;
for (i=0 ; i<instDesc->numOperands ; i++) {
switch (instDesc->opTypes[i]) {
case OPERAND_INT1:
val = TclGetInt1AtPtr(opnd);
opnd += 1;
goto formatNumber;
case OPERAND_UINT1:
val = TclGetUInt1AtPtr(opnd);
opnd += 1;
goto formatNumber;
case OPERAND_INT4:
val = TclGetInt4AtPtr(opnd);
opnd += 4;
|
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 |
TclNewObj(exn);
for (i=0 ; i<(int)codePtr->numExceptRanges ; i++) {
ExceptionRange *rangePtr = &codePtr->exceptArrayPtr[i];
switch (rangePtr->type) {
case LOOP_EXCEPTION_RANGE:
Tcl_ListObjAppendElement(NULL, exn, Tcl_ObjPrintf(
| | < < < | < < | 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 |
TclNewObj(exn);
for (i=0 ; i<(int)codePtr->numExceptRanges ; i++) {
ExceptionRange *rangePtr = &codePtr->exceptArrayPtr[i];
switch (rangePtr->type) {
case LOOP_EXCEPTION_RANGE:
Tcl_ListObjAppendElement(NULL, exn, Tcl_ObjPrintf(
"type %s level %" TCL_SIZE_MODIFIER "d from %" TCL_SIZE_MODIFIER "d to %" TCL_SIZE_MODIFIER "d break %" TCL_SIZE_MODIFIER "d continue %" TCL_SIZE_MODIFIER "d",
"loop", rangePtr->nestingLevel, rangePtr->codeOffset,
rangePtr->codeOffset + rangePtr->numCodeBytes - 1,
rangePtr->breakOffset, rangePtr->continueOffset));
break;
case CATCH_EXCEPTION_RANGE:
Tcl_ListObjAppendElement(NULL, exn, Tcl_ObjPrintf(
"type %s level %" TCL_SIZE_MODIFIER "d from %" TCL_SIZE_MODIFIER "d to %" TCL_SIZE_MODIFIER "d catch %" TCL_SIZE_MODIFIER "d",
"catch", rangePtr->nestingLevel, rangePtr->codeOffset,
rangePtr->codeOffset + rangePtr->numCodeBytes - 1,
rangePtr->catchOffset));
break;
}
}
|
| ︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 |
*----------------------------------------------------------------------
*/
int
Tcl_DisassembleObjCmd(
void *clientData, /* What type of operation. */
Tcl_Interp *interp, /* Current interpreter. */
| | | < < < < < < < < < < < < | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 |
*----------------------------------------------------------------------
*/
int
Tcl_DisassembleObjCmd(
void *clientData, /* What type of operation. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const types[] = {
"constructor", "destructor",
"lambda", "method", "objmethod", "proc", "script", NULL
};
enum Types {
DISAS_CLASS_CONSTRUCTOR, DISAS_CLASS_DESTRUCTOR,
DISAS_LAMBDA, DISAS_CLASS_METHOD, DISAS_OBJECT_METHOD, DISAS_PROC,
DISAS_SCRIPT
} idx;
int result;
Tcl_Obj *codeObjPtr = NULL;
Proc *procPtr = NULL;
Tcl_HashEntry *hPtr;
Object *oPtr;
ByteCode *codePtr;
Method *methodPtr;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "type ...");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], types, "type", 0, &idx)!=TCL_OK){
return TCL_ERROR;
}
switch (idx) {
case DISAS_LAMBDA: {
Tcl_Obj *nsObjPtr;
/*
* Compile (if uncompiled) and disassemble a lambda term.
*/
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "lambdaTerm");
return TCL_ERROR;
}
procPtr = TclGetLambdaFromObj(interp, objv[2], &nsObjPtr);
if (procPtr == NULL) {
return TCL_ERROR;
}
result = TclPushProcCallFrame(procPtr, interp, objc, objv, 1);
if (result != TCL_OK) {
return result;
}
TclPopStackFrame(interp);
codeObjPtr = procPtr->bodyPtr;
break;
|
| ︙ | ︙ | |||
1468 1469 1470 1471 1472 1473 1474 | return TCL_ERROR; } /* * Look up the body of a constructor. */ | < | > > > | > > > > | | > > > | > > | > > > > | > > > > > > > > > > > > < | > > > | > > > > | | > > > | > > | > > > > | > > > > > > > > > > > > < | | | > > > > > > | > < < | | | < < < | | | | 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 |
return TCL_ERROR;
}
/*
* Look up the body of a constructor.
*/
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (oPtr->classPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" is not a class", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
methodPtr = oPtr->classPtr->constructorPtr;
if (methodPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" has no defined constructor",
TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE",
"CONSRUCTOR", (char *)NULL);
return TCL_ERROR;
}
procPtr = TclOOGetProcFromMethod(methodPtr);
if (procPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"body not available for this kind of constructor", -1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE",
"METHODTYPE", (char *)NULL);
return TCL_ERROR;
}
/*
* Compile if necessary.
*/
if (!TclHasInternalRep(procPtr->bodyPtr, &tclByteCodeType)) {
Command cmd;
/*
* Yes, this is ugly, but we need to pass the namespace in to the
* compiler in two places.
*/
cmd.nsPtr = (Namespace *) oPtr->namespacePtr;
procPtr->cmdPtr = &cmd;
result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr,
(Namespace *) oPtr->namespacePtr, "body of constructor",
TclGetString(objv[2]));
procPtr->cmdPtr = NULL;
if (result != TCL_OK) {
return result;
}
}
codeObjPtr = procPtr->bodyPtr;
break;
case DISAS_CLASS_DESTRUCTOR:
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "className");
return TCL_ERROR;
}
/*
* Look up the body of a destructor.
*/
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (oPtr->classPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" is not a class", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
methodPtr = oPtr->classPtr->destructorPtr;
if (methodPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" has no defined destructor",
TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE",
"DESRUCTOR", (char *)NULL);
return TCL_ERROR;
}
procPtr = TclOOGetProcFromMethod(methodPtr);
if (procPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"body not available for this kind of destructor", -1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE",
"METHODTYPE", (char *)NULL);
return TCL_ERROR;
}
/*
* Compile if necessary.
*/
if (!TclHasInternalRep(procPtr->bodyPtr, &tclByteCodeType)) {
Command cmd;
/*
* Yes, this is ugly, but we need to pass the namespace in to the
* compiler in two places.
*/
cmd.nsPtr = (Namespace *) oPtr->namespacePtr;
procPtr->cmdPtr = &cmd;
result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr,
(Namespace *) oPtr->namespacePtr, "body of destructor",
TclGetString(objv[2]));
procPtr->cmdPtr = NULL;
if (result != TCL_OK) {
return result;
}
}
codeObjPtr = procPtr->bodyPtr;
break;
case DISAS_CLASS_METHOD:
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "className methodName");
return TCL_ERROR;
}
/*
* Look up the body of a class method.
*/
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (oPtr->classPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" is not a class", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
hPtr = Tcl_FindHashEntry(&oPtr->classPtr->classMethods,
objv[3]);
goto methodBody;
case DISAS_OBJECT_METHOD:
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "objectName methodName");
return TCL_ERROR;
}
/*
* Look up the body of an instance method.
*/
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[2]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (oPtr->methodsPtr == NULL) {
goto unknownMethod;
}
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, objv[3]);
/*
* Compile (if necessary) and disassemble a method body.
*/
methodBody:
if (hPtr == NULL) {
unknownMethod:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unknown method \"%s\"", TclGetString(objv[3])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[3]), (char *)NULL);
return TCL_ERROR;
}
procPtr = TclOOGetProcFromMethod((Method *)Tcl_GetHashValue(hPtr));
if (procPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"body not available for this kind of method", -1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "DISASSEMBLE",
"METHODTYPE", (char *)NULL);
return TCL_ERROR;
}
if (!TclHasInternalRep(procPtr->bodyPtr, &tclByteCodeType)) {
Command cmd;
/*
* Yes, this is ugly, but we need to pass the namespace in to the
* compiler in two places.
*/
cmd.nsPtr = (Namespace *) oPtr->namespacePtr;
procPtr->cmdPtr = &cmd;
result = TclProcCompileProc(interp, procPtr, procPtr->bodyPtr,
(Namespace *) oPtr->namespacePtr, "body of method",
TclGetString(objv[3]));
procPtr->cmdPtr = NULL;
if (result != TCL_OK) {
return result;
}
}
codeObjPtr = procPtr->bodyPtr;
break;
default:
CLANG_ASSERT(0);
}
/*
* Do the actual disassembly.
*/
ByteCodeGetInternalRep(codeObjPtr, &tclByteCodeType, codePtr);
|
| ︙ | ︙ |
Changes to generic/tclEncoding.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* * tclEncoding.c -- * * Contains the implementation of the encoding conversion package. * * Copyright © 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * tclEncoding.c -- * * Contains the implementation of the encoding conversion package. * * Copyright © 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" typedef size_t (LengthProc)(const char *src); /* * The following data structure represents an encoding, which describes how to * convert between various character sets and UTF-8. */ |
| ︙ | ︙ | |||
254 255 256 257 258 259 260 | static size_t unilen4(const char *src); static Tcl_EncodingConvertProc Utf32ToUtfProc; static Tcl_EncodingConvertProc UtfToUtf32Proc; static Tcl_EncodingConvertProc Utf16ToUtfProc; static Tcl_EncodingConvertProc UtfToUtf16Proc; static Tcl_EncodingConvertProc UtfToUcs2Proc; static Tcl_EncodingConvertProc UtfToUtfProc; | < < | | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
static size_t unilen4(const char *src);
static Tcl_EncodingConvertProc Utf32ToUtfProc;
static Tcl_EncodingConvertProc UtfToUtf32Proc;
static Tcl_EncodingConvertProc Utf16ToUtfProc;
static Tcl_EncodingConvertProc UtfToUtf16Proc;
static Tcl_EncodingConvertProc UtfToUcs2Proc;
static Tcl_EncodingConvertProc UtfToUtfProc;
static Tcl_EncodingConvertProc Iso88591FromUtfProc;
static Tcl_EncodingConvertProc Iso88591ToUtfProc;
/*
* A Tcl_ObjType for holding a cached Tcl_Encoding in the twoPtrValue.ptr1
* field of the internalrep. This should help the lifetime of encodings be more
* useful. See concerns raised in [Bug 1077262].
*/
static const Tcl_ObjType encodingType = {
"encoding",
FreeEncodingInternalRep,
DupEncodingInternalRep,
NULL,
NULL,
TCL_OBJTYPE_V0
};
#define EncodingSetInternalRep(objPtr, encoding) \
do { \
Tcl_ObjInternalRep ir; \
ir.twoPtrValue.ptr1 = (encoding); \
|
| ︙ | ︙ | |||
513 514 515 516 517 518 519 |
* DEFINED IN tcl.h (TCL_ENCODING_* et al). Be cognizant of this
* when adding bits. TODO - should really be defined in a single file.
*
* To prevent conflicting bits, only define bits within 0xff00 mask here.
*/
enum InternalEncodingFlags {
TCL_ENCODING_LE = 0x100, /* Used to distinguish LE/BE variants */
| > > | | < < | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
* DEFINED IN tcl.h (TCL_ENCODING_* et al). Be cognizant of this
* when adding bits. TODO - should really be defined in a single file.
*
* To prevent conflicting bits, only define bits within 0xff00 mask here.
*/
enum InternalEncodingFlags {
TCL_ENCODING_LE = 0x100, /* Used to distinguish LE/BE variants */
ENCODING_UTF = 0x200, /* For UTF-8 encoding, allow 4-byte output
* sequences */
ENCODING_INPUT = 0x400 /* For UTF-8/CESU-8 encoding, means
* external -> internal */
};
void
TclInitEncodingSubsystem(void)
{
Tcl_EncodingType type;
TableEncodingData *dataPtr;
|
| ︙ | ︙ | |||
563 564 565 566 567 568 569 |
tclIdentityEncoding = Tcl_CreateEncoding(&type);
type.encodingName = "utf-8";
type.toUtfProc = UtfToUtfProc;
type.fromUtfProc = UtfToUtfProc;
type.freeProc = NULL;
type.nullSize = 1;
| | | < < < < < | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 |
tclIdentityEncoding = Tcl_CreateEncoding(&type);
type.encodingName = "utf-8";
type.toUtfProc = UtfToUtfProc;
type.fromUtfProc = UtfToUtfProc;
type.freeProc = NULL;
type.nullSize = 1;
type.clientData = INT2PTR(ENCODING_UTF);
tclUtf8Encoding = Tcl_CreateEncoding(&type);
type.clientData = NULL;
type.encodingName = "cesu-8";
Tcl_CreateEncoding(&type);
type.toUtfProc = Utf16ToUtfProc;
type.fromUtfProc = UtfToUcs2Proc;
type.freeProc = NULL;
type.nullSize = 2;
type.encodingName = "ucs-2le";
|
| ︙ | ︙ | |||
884 885 886 887 888 889 890 |
Tcl_Interp *interp) /* Interp to hold result. */
{
Tcl_HashTable table;
Tcl_HashSearch search;
Tcl_HashEntry *hPtr;
Tcl_Obj *map, *name, *result;
Tcl_DictSearch mapSearch;
| | | | | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
Tcl_Interp *interp) /* Interp to hold result. */
{
Tcl_HashTable table;
Tcl_HashSearch search;
Tcl_HashEntry *hPtr;
Tcl_Obj *map, *name, *result;
Tcl_DictSearch mapSearch;
int dummy, done = 0;
TclNewObj(result);
Tcl_InitObjHashTable(&table);
/*
* Copy encoding names from loaded encoding table to table.
*/
Tcl_MutexLock(&encodingMutex);
for (hPtr = Tcl_FirstHashEntry(&encodingTable, &search); hPtr != NULL;
hPtr = Tcl_NextHashEntry(&search)) {
Encoding *encodingPtr = (Encoding *)Tcl_GetHashValue(hPtr);
Tcl_CreateHashEntry(&table,
Tcl_NewStringObj(encodingPtr->name, TCL_INDEX_NONE), &dummy);
}
Tcl_MutexUnlock(&encodingMutex);
FillEncodingFileMap();
map = TclGetProcessGlobalValue(&encodingFileMap);
/*
* Copy encoding names from encoding file map to table.
*/
Tcl_DictObjFirst(NULL, map, &mapSearch, &name, NULL, &done);
for (; !done; Tcl_DictObjNext(&mapSearch, &name, NULL, &done)) {
Tcl_CreateHashEntry(&table, name, &dummy);
}
/*
* Pull all encoding names from table into the result list.
*/
for (hPtr = Tcl_FirstHashEntry(&table, &search); hPtr != NULL;
|
| ︙ | ︙ | |||
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 |
int
Tcl_SetSystemEncoding(
Tcl_Interp *interp, /* Interp for error reporting, if not NULL. */
const char *name) /* The name of the desired encoding, or NULL/""
* to reset to default encoding. */
{
Tcl_Encoding encoding = NULL;
if (name && *name) {
encoding = Tcl_GetEncoding(interp, name); /* this increases refCount */
if (encoding == NULL) {
return TCL_ERROR;
}
}
/* Don't lock (and change anything, bump epoch) if it remains unchanged. */
if ((encoding ? encoding : defaultEncoding) == systemEncoding) {
if (encoding) {
Tcl_FreeEncoding(encoding); /* paired to Tcl_GetEncoding */
| > | > > > > | 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
int
Tcl_SetSystemEncoding(
Tcl_Interp *interp, /* Interp for error reporting, if not NULL. */
const char *name) /* The name of the desired encoding, or NULL/""
* to reset to default encoding. */
{
Tcl_Encoding encoding = NULL;
if (name && *name) {
encoding = Tcl_GetEncoding(interp, name); /* this increases refCount */
if (encoding == NULL) {
return TCL_ERROR;
}
}
/* Don't lock (and change anything, bump epoch) if it remains unchanged. */
if ((encoding ? encoding : defaultEncoding) == systemEncoding) {
if (encoding) {
Tcl_FreeEncoding(encoding); /* paired to Tcl_GetEncoding */
}
return TCL_OK;
}
/* Checks above ensure this is only called when system encoding changes */
Tcl_MutexLock(&encodingMutex);
if (!encoding) {
encoding = defaultEncoding; /* need increase its refCount */
|
| ︙ | ︙ | |||
1204 1205 1206 1207 1208 1209 1210 |
if (encoding == NULL) {
encoding = systemEncoding;
}
encodingPtr = (Encoding *)encoding;
if (src == NULL) {
srcLen = 0;
| | | 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 |
if (encoding == NULL) {
encoding = systemEncoding;
}
encodingPtr = (Encoding *)encoding;
if (src == NULL) {
srcLen = 0;
src = "";
} else if (srcLen < 0) {
srcLen = encodingPtr->lengthProc(src);
}
flags &= ~TCL_ENCODING_END;
flags |= TCL_ENCODING_START;
if (encodingPtr->toUtfProc == UtfToUtfProc) {
|
| ︙ | ︙ | |||
1307 1308 1309 1310 1311 1312 1313 | * The converted bytes are stored in the output buffer. * *------------------------------------------------------------------------- */ int Tcl_ExternalToUtf( | | | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 |
* The converted bytes are stored in the output buffer.
*
*-------------------------------------------------------------------------
*/
int
Tcl_ExternalToUtf(
TCL_UNUSED(Tcl_Interp *), /* TODO: Re-examine this. */
Tcl_Encoding encoding, /* The encoding for the source string, or NULL
* for the default system encoding. */
const char *src, /* Source string in specified encoding. */
Tcl_Size srcLen, /* Source string length in bytes, or
* negative for encoding-specific string
* length. */
int flags, /* Conversion control flags. */
|
| ︙ | ︙ | |||
1336 1337 1338 1339 1340 1341 1342 |
int *dstWrotePtr, /* Filled with the number of bytes that were
* stored in the output buffer as a result of
* the conversion. */
int *dstCharsPtr) /* Filled with the number of characters that
* correspond to the bytes stored in the
* output buffer. */
{
| | | | < < < < < < < < < < < | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | > > > | < > | > > > | | < | < | > > | > > | > > | | | < > | < | > > > > > > | | | | | < | | < | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < | < < < < | < < < < | | < < < < < < < < < < < > > | | < < < < < | < < < < | < < | < < < < < < < | 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 |
int *dstWrotePtr, /* Filled with the number of bytes that were
* stored in the output buffer as a result of
* the conversion. */
int *dstCharsPtr) /* Filled with the number of characters that
* correspond to the bytes stored in the
* output buffer. */
{
const Encoding *encodingPtr;
int result, srcRead, dstWrote, dstChars = 0;
int noTerminate = flags & TCL_ENCODING_NO_TERMINATE;
int charLimited = (flags & TCL_ENCODING_CHAR_LIMIT) && dstCharsPtr;
int maxChars = INT_MAX;
Tcl_EncodingState state;
if (encoding == NULL) {
encoding = systemEncoding;
}
encodingPtr = (Encoding *) encoding;
if (src == NULL) {
srcLen = 0;
src = "";
} else if (srcLen < 0) {
srcLen = encodingPtr->lengthProc(src);
}
if (statePtr == NULL) {
flags |= TCL_ENCODING_START | TCL_ENCODING_END;
statePtr = &state;
}
if (srcLen > INT_MAX) {
srcLen = INT_MAX;
flags &= ~TCL_ENCODING_END;
}
if (dstLen > INT_MAX) {
dstLen = INT_MAX;
}
if (srcReadPtr == NULL) {
srcReadPtr = &srcRead;
}
if (dstWrotePtr == NULL) {
dstWrotePtr = &dstWrote;
}
if (dstCharsPtr == NULL) {
dstCharsPtr = &dstChars;
flags &= ~TCL_ENCODING_CHAR_LIMIT;
} else if (charLimited) {
maxChars = *dstCharsPtr;
}
if (!noTerminate) {
if (dstLen < 1) {
return TCL_CONVERT_NOSPACE;
}
/*
* If there are any null characters in the middle of the buffer,
* they will converted to the UTF-8 null character (\xC0\x80). To get
* the actual \0 at the end of the destination buffer, we need to
* append it manually. First make room for it...
*/
dstLen--;
} else {
if (dstLen <= 0 && srcLen > 0) {
return TCL_CONVERT_NOSPACE;
}
}
if (encodingPtr->toUtfProc == UtfToUtfProc) {
flags |= ENCODING_INPUT;
}
do {
Tcl_EncodingState savedState = *statePtr;
result = encodingPtr->toUtfProc(encodingPtr->clientData, src, srcLen,
flags, statePtr, dst, dstLen, srcReadPtr, dstWrotePtr,
dstCharsPtr);
if (*dstCharsPtr <= maxChars) {
break;
}
dstLen = Tcl_UtfAtIndex(dst, maxChars) - dst + (TCL_UTF_MAX - 1);
*statePtr = savedState;
} while (1);
if (!noTerminate) {
/* ...and then append it */
dst[*dstWrotePtr] = '\0';
}
return result;
}
/*
*-------------------------------------------------------------------------
|
| ︙ | ︙ | |||
1772 1773 1774 1775 1776 1777 1778 |
if (encoding == NULL) {
encoding = systemEncoding;
}
encodingPtr = (Encoding *) encoding;
if (src == NULL) {
srcLen = 0;
| | | 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 |
if (encoding == NULL) {
encoding = systemEncoding;
}
encodingPtr = (Encoding *) encoding;
if (src == NULL) {
srcLen = 0;
src = "";
} else if (srcLen < 0) {
srcLen = strlen(src);
}
flags &= ~TCL_ENCODING_END;
flags |= TCL_ENCODING_START;
while (1) {
|
| ︙ | ︙ | |||
1878 1879 1880 1881 1882 1883 1884 | * The converted bytes are stored in the output buffer. * *------------------------------------------------------------------------- */ int Tcl_UtfToExternal( | | | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 |
* The converted bytes are stored in the output buffer.
*
*-------------------------------------------------------------------------
*/
int
Tcl_UtfToExternal(
TCL_UNUSED(Tcl_Interp *), /* TODO: Re-examine this. */
Tcl_Encoding encoding, /* The encoding for the converted string, or
* NULL for the default system encoding. */
const char *src, /* Source string in UTF-8. */
Tcl_Size srcLen, /* Source string length in bytes, or
* < 0 for strlen(). */
int flags, /* Conversion control flags. */
Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
|
| ︙ | ︙ | |||
1906 1907 1908 1909 1910 1911 1912 |
int *dstWrotePtr, /* Filled with the number of bytes that were
* stored in the output buffer as a result of
* the conversion. */
int *dstCharsPtr) /* Filled with the number of characters that
* correspond to the bytes stored in the
* output buffer. */
{
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < | | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < | | < < < < < < < < < < | | < < | < < | < < | | < < < < | < < < | | | | | < < < < < < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < > | < > | < < < < < | < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < | < < < < < | < < < < < | 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 |
int *dstWrotePtr, /* Filled with the number of bytes that were
* stored in the output buffer as a result of
* the conversion. */
int *dstCharsPtr) /* Filled with the number of characters that
* correspond to the bytes stored in the
* output buffer. */
{
const Encoding *encodingPtr;
int result, srcRead, dstWrote, dstChars;
Tcl_EncodingState state;
if (encoding == NULL) {
encoding = systemEncoding;
}
encodingPtr = (Encoding *) encoding;
if (src == NULL) {
srcLen = 0;
src = "";
} else if (srcLen < 0) {
srcLen = strlen(src);
}
if (statePtr == NULL) {
flags |= TCL_ENCODING_START | TCL_ENCODING_END;
statePtr = &state;
}
if (srcLen > INT_MAX) {
srcLen = INT_MAX;
flags &= ~TCL_ENCODING_END;
}
if (dstLen > INT_MAX) {
dstLen = INT_MAX;
}
if (srcReadPtr == NULL) {
srcReadPtr = &srcRead;
}
if (dstWrotePtr == NULL) {
dstWrotePtr = &dstWrote;
}
if (dstCharsPtr == NULL) {
dstCharsPtr = &dstChars;
}
if (dstLen < encodingPtr->nullSize) {
return TCL_CONVERT_NOSPACE;
}
dstLen -= encodingPtr->nullSize;
result = encodingPtr->fromUtfProc(encodingPtr->clientData, src, srcLen,
flags, statePtr, dst, dstLen, srcReadPtr,
dstWrotePtr, dstCharsPtr);
/*
* Buffer is terminated irrespective of result. Not sure this is
* reasonable but keep for historical/compatibility reasons.
*/
memset(&dst[*dstWrotePtr], '\0', encodingPtr->nullSize);
return result;
}
/*
*---------------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2272 2273 2274 2275 2276 2277 2278 |
Tcl_FindExecutable(
const char *argv0) /* The value of the application's argv[0]
* (native). */
{
const char *version = Tcl_InitSubsystems();
TclpSetInitialEncodings();
TclpFindExecutable(argv0);
| < < < | 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 |
Tcl_FindExecutable(
const char *argv0) /* The value of the application's argv[0]
* (native). */
{
const char *version = Tcl_InitSubsystems();
TclpSetInitialEncodings();
TclpFindExecutable(argv0);
return version;
}
/*
*---------------------------------------------------------------------------
*
* OpenEncodingFileChannel --
|
| ︙ | ︙ | |||
2303 2304 2305 2306 2307 2308 2309 |
static Tcl_Channel
OpenEncodingFileChannel(
Tcl_Interp *interp, /* Interp for error reporting, if not NULL. */
const char *name) /* The name of the encoding file on disk and
* also the name for new encoding. */
{
| | < | 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 |
static Tcl_Channel
OpenEncodingFileChannel(
Tcl_Interp *interp, /* Interp for error reporting, if not NULL. */
const char *name) /* The name of the encoding file on disk and
* also the name for new encoding. */
{
Tcl_Obj *fileNameObj = Tcl_ObjPrintf("%s.enc", name);
Tcl_Obj *searchPath = Tcl_DuplicateObj(Tcl_GetEncodingSearchPath());
Tcl_Obj *map = TclGetProcessGlobalValue(&encodingFileMap);
Tcl_Obj **dir, *path, *directory = NULL;
Tcl_Channel chan = NULL;
Tcl_Size i, numDirs;
TclListObjGetElements(NULL, searchPath, &numDirs, &dir);
|
| ︙ | ︙ | |||
2510 2511 2512 2513 2514 2515 2516 |
/*
* Speed over memory. Use a full 256 character table to decode hex
* sequences in the encoding files.
*/
static const char staticHex[] = {
| | | | | | | | | | | | | | | | | | 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 |
/*
* Speed over memory. Use a full 256 character table to decode hex
* sequences in the encoding files.
*/
static const char staticHex[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 ... 15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 ... 31 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32 ... 47 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 48 ... 63 */
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 64 ... 79 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 ... 95 */
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 96 ... 111 */
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 112 ... 127 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128 ... 143 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144 ... 159 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 160 ... 175 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176 ... 191 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192 ... 207 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208 ... 223 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 224 ... 239 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 240 ... 255 */
};
Tcl_DStringInit(&lineString);
if (Tcl_Gets(chan, &lineString) < 0) {
return NULL;
}
line = Tcl_DStringValue(&lineString);
|
| ︙ | ︙ | |||
2957 2958 2959 2960 2961 2962 2963 2964 2965 |
*srcReadPtr = srcLen;
*dstWrotePtr = srcLen;
*dstCharsPtr = srcLen;
memcpy(dst, src, srcLen);
return result;
}
static int
UtfToUtfProc(
| > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 |
*srcReadPtr = srcLen;
*dstWrotePtr = srcLen;
*dstCharsPtr = srcLen;
memcpy(dst, src, srcLen);
return result;
}
/*
*-------------------------------------------------------------------------
*
* UtfToUtfProc --
*
* Converts from UTF-8 to UTF-8. Note that the UTF-8 to UTF-8 translation
* is not a no-op, because it turns a stream of improperly formed
* UTF-8 into a properly-formed stream.
*
* Results:
* Returns TCL_OK if conversion was successful.
*
* Side effects:
* None.
*
*-------------------------------------------------------------------------
*/
static int
UtfToUtfProc(
void *clientData, /* additional flags */
const char *src, /* Source string in UTF-8. */
int srcLen, /* Source string length in bytes. */
int flags, /* TCL_ENCODING_* conversion control flags. */
Tcl_EncodingState *statePtr,/* Place for conversion routine to store state
* information used during a piecewise
* conversion. Contents of statePtr are
* initialized and/or reset by conversion
* routine under control of flags argument. */
char *dst, /* Output buffer in which converted string is
* stored. */
|
| ︙ | ︙ | |||
3219 3220 3221 3222 3223 3224 3225 |
charLimit = *dstCharsPtr;
}
dstStart = dst;
flags |= PTR2INT(clientData);
/*
| > | | | | | | | | | | > | | | | < < < < | | | | | | | | | | > > | | < | | < < < < < < < < < < < < < < < < < < < | < < < | | | > | | 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 |
charLimit = *dstCharsPtr;
}
dstStart = dst;
flags |= PTR2INT(clientData);
/*
* If output is UTF-8 or encoding for Tcl's internal encoding,
* max space needed is TCL_UTF_MAX. Otherwise, need 6 bytes (CESU-8)
*/
dstEnd = dst + dstLen - ((flags & (ENCODING_INPUT|ENCODING_UTF)) ? TCL_UTF_MAX : 6);
/*
* Macro to output an isolated high surrogate when it is not followed
* by a low surrogate. NOT to be called for strict profile since
* that should raise an error.
*/
#define OUTPUT_ISOLATEDSURROGATE \
do { \
Tcl_UniChar high; \
if (PROFILE_REPLACE(profile)) { \
high = UNICODE_REPLACE_CHAR; \
} else { \
high = (Tcl_UniChar)(ptrdiff_t) *statePtr; \
} \
assert(!(flags & ENCODING_UTF)); /* Must be CESU-8 */ \
assert(HIGH_SURROGATE(high)); \
assert(!PROFILE_STRICT(profile)); \
dst += Tcl_UniCharToUtf(high, dst); \
*statePtr = 0; /* Reset state */ \
} while (0)
/*
* Macro to check for isolated surrogate and either break with
* an error if profile is strict, or output an appropriate
* character for replace and tcl8 profiles and continue.
*/
#define CHECK_ISOLATEDSURROGATE \
if (*statePtr) { \
if (PROFILE_STRICT(profile)) { \
result = TCL_CONVERT_SYNTAX; \
break; \
} \
OUTPUT_ISOLATEDSURROGATE; \
continue; /* Rerun loop so length checks etc. repeated */ \
} else \
(void) 0
profile = ENCODING_PROFILE_GET(flags);
for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
if ((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
/*
* If there is more string to follow, this will ensure that the
* last UTF-8 character in the source buffer hasn't been cut off.
*/
result = TCL_CONVERT_MULTIBYTE;
break;
}
if (dst > dstEnd) {
result = TCL_CONVERT_NOSPACE;
break;
}
if (UCHAR(*src) < 0x80 && !((UCHAR(*src) == 0) && (flags & ENCODING_INPUT))) {
CHECK_ISOLATEDSURROGATE;
/*
* Copy 7bit characters, but skip null-bytes when we are in input
* mode, so that they get converted to \xC0\x80.
*/
*dst++ = *src++;
} else if ((UCHAR(*src) == 0xC0) && (src + 1 < srcEnd) &&
(UCHAR(src[1]) == 0x80) &&
(!(flags & ENCODING_INPUT) || !PROFILE_TCL8(profile))) {
/* Special sequence \xC0\x80 */
CHECK_ISOLATEDSURROGATE;
if (!PROFILE_TCL8(profile) && (flags & ENCODING_INPUT)) {
if (PROFILE_REPLACE(profile)) {
dst += Tcl_UniCharToUtf(UNICODE_REPLACE_CHAR, dst);
src += 2;
} else {
/* PROFILE_STRICT */
result = TCL_CONVERT_SYNTAX;
break;
}
} else {
/*
* Convert 0xC080 to real nulls when we are in output mode,
* irrespective of the profile.
*/
*dst++ = 0;
src += 2;
}
} else if (!Tcl_UtfCharComplete(src, srcEnd - src)) {
/*
* Incomplete byte sequence not because there are insufficient
* bytes in source buffer (have already checked that above) but
* because the UTF-8 sequence is truncated.
*/
CHECK_ISOLATEDSURROGATE;
if (flags & ENCODING_INPUT) {
/* Incomplete bytes for modified UTF-8 target */
if (PROFILE_STRICT(profile)) {
result = (flags & TCL_ENCODING_CHAR_LIMIT)
? TCL_CONVERT_MULTIBYTE
: TCL_CONVERT_SYNTAX;
|
| ︙ | ︙ | |||
3367 3368 3369 3370 3371 3372 3373 |
/* Have a complete character */
size_t len = TclUtfToUniChar(src, &ch);
Tcl_UniChar savedSurrogate = (Tcl_UniChar) (ptrdiff_t)*statePtr;
*statePtr = 0; /* Reset surrogate */
if (flags & ENCODING_INPUT) {
| | > | | | > > > > > > > > > > > > > | | | | | < | | | | | < | | | | | | | | | | | | | | | | | < | | | | | | | | | | < | | > | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 |
/* Have a complete character */
size_t len = TclUtfToUniChar(src, &ch);
Tcl_UniChar savedSurrogate = (Tcl_UniChar) (ptrdiff_t)*statePtr;
*statePtr = 0; /* Reset surrogate */
if (flags & ENCODING_INPUT) {
if (((len < 2) && (ch != 0)) || ((ch > 0xFFFF) && !(flags & ENCODING_UTF))) {
if (PROFILE_STRICT(profile)) {
result = TCL_CONVERT_SYNTAX;
break;
} else if (PROFILE_REPLACE(profile)) {
ch = UNICODE_REPLACE_CHAR;
}
}
}
const char *saveSrc = src;
src += len;
if (!(flags & ENCODING_UTF) && !(flags & ENCODING_INPUT)
&& (ch > 0x7FF)) {
assert(savedSurrogate == 0); /* Since this flag combo
will never set *statePtr */
if (ch > 0xFFFF) {
/* CESU-8 6-byte sequence for chars > U+FFFF */
ch -= 0x10000;
*dst++ = 0xED;
*dst++ = (char) (((ch >> 16) & 0x0F) | 0xA0);
*dst++ = (char) (((ch >> 10) & 0x3F) | 0x80);
ch = (ch & 0x03FF) | 0xDC00;
}
*dst++ = (char)(((ch >> 12) | 0xE0) & 0xEF);
*dst++ = (char)(((ch >> 6) | 0x80) & 0xBF);
*dst++ = (char)((ch | 0x80) & 0xBF);
continue;
} else if (SURROGATE(ch)) {
if ((flags & ENCODING_UTF)) {
/* UTF-8, not CESU-8, so surrogates should not appear */
if (PROFILE_STRICT(profile)) {
result = (flags & ENCODING_INPUT)
? TCL_CONVERT_SYNTAX : TCL_CONVERT_UNKNOWN;
src = saveSrc;
break;
} else if (PROFILE_REPLACE(profile)) {
ch = UNICODE_REPLACE_CHAR;
} else {
/* PROFILE_TCL8 - output as is */
}
} else {
/* CESU-8 */
if (LOW_SURROGATE(ch)) {
if (savedSurrogate) {
assert(HIGH_SURROGATE(savedSurrogate));
ch = 0x10000 + ((savedSurrogate - 0xd800) << 10) + (ch - 0xdc00);
} else {
/* Isolated low surrogate */
if (PROFILE_STRICT(profile)) {
result = (flags & ENCODING_INPUT)
? TCL_CONVERT_SYNTAX : TCL_CONVERT_UNKNOWN;
src = saveSrc;
break;
} else if (PROFILE_REPLACE(profile)) {
ch = UNICODE_REPLACE_CHAR;
} else {
/* Tcl8 profile. Output low surrogate as is */
}
}
} else {
assert(HIGH_SURROGATE(ch));
/* Save the high surrogate */
*statePtr = (Tcl_EncodingState) (ptrdiff_t) ch;
if (savedSurrogate) {
assert(HIGH_SURROGATE(savedSurrogate));
if (PROFILE_STRICT(profile)) {
result = (flags & ENCODING_INPUT)
? TCL_CONVERT_SYNTAX : TCL_CONVERT_UNKNOWN;
src = saveSrc;
break;
} else if (PROFILE_REPLACE(profile)) {
ch = UNICODE_REPLACE_CHAR;
} else {
/* Output the isolated high surrogate */
ch = savedSurrogate;
}
} else {
/* High surrogate saved in *statePtr. Do not output anything just yet. */
--numChars; /* Cancel the increment at end of loop */
continue;
}
}
}
} else {
/* Normal character */
CHECK_ISOLATEDSURROGATE;
}
dst += Tcl_UniCharToUtf(ch, dst);
}
}
/* Check if an high surrogate left over */
if (*statePtr) {
assert(!(flags & ENCODING_UTF)); /* CESU-8, Not UTF-8 */
if (!(flags & TCL_ENCODING_END)) {
/* More data coming */
} else {
/* No more data coming */
if (PROFILE_STRICT(profile)) {
result = (flags & ENCODING_INPUT)
? TCL_CONVERT_SYNTAX : TCL_CONVERT_UNKNOWN;
} else {
if (PROFILE_REPLACE(profile)) {
ch = UNICODE_REPLACE_CHAR;
} else {
ch = (Tcl_UniChar) (ptrdiff_t) *statePtr;
}
if (dst < dstEnd) {
|
| ︙ | ︙ | |||
3507 3508 3509 3510 3511 3512 3513 |
}
}
*srcReadPtr = src - srcStart;
*dstWrotePtr = dst - dstStart;
*dstCharsPtr = numChars;
return result;
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 |
}
}
*srcReadPtr = src - srcStart;
*dstWrotePtr = dst - dstStart;
*dstCharsPtr = numChars;
return result;
}
/*
*-------------------------------------------------------------------------
*
* Utf32ToUtfProc --
*
|
| ︙ | ︙ | |||
3608 3609 3610 3611 3612 3613 3614 |
srcStart = src;
srcEnd = src + srcLen;
dstStart = dst;
dstEnd = dst + dstLen - TCL_UTF_MAX;
| | | 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 |
srcStart = src;
srcEnd = src + srcLen;
dstStart = dst;
dstEnd = dst + dstLen - TCL_UTF_MAX;
for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
if (dst > dstEnd) {
result = TCL_CONVERT_NOSPACE;
break;
}
if (flags & TCL_ENCODING_LE) {
ch = (unsigned int)(src[3] & 0xFF) << 24 | (src[2] & 0xFF) << 16
|
| ︙ | ︙ | |||
3851 3852 3853 3854 3855 3856 3857 |
srcStart = src;
srcEnd = src + srcLen;
dstStart = dst;
dstEnd = dst + dstLen - TCL_UTF_MAX;
| | | 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 |
srcStart = src;
srcEnd = src + srcLen;
dstStart = dst;
dstEnd = dst + dstLen - TCL_UTF_MAX;
for (numChars = 0; src < srcEnd && numChars <= charLimit; src += 2, numChars++) {
if (dst > dstEnd && !HIGH_SURROGATE(ch)) {
result = TCL_CONVERT_NOSPACE;
break;
}
unsigned short prev = ch;
if (flags & TCL_ENCODING_LE) {
|
| ︙ | ︙ | |||
3878 3879 3880 3881 3882 3883 3884 |
*/
dst += Tcl_UniCharToUtf(ch | TCL_COMBINE, dst);
} else {
/* High surrogate was not followed by a low surrogate */
if (PROFILE_STRICT(flags)) {
result = TCL_CONVERT_SYNTAX;
src -= 2; /* Go back to beginning of high surrogate */
| | | 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 |
*/
dst += Tcl_UniCharToUtf(ch | TCL_COMBINE, dst);
} else {
/* High surrogate was not followed by a low surrogate */
if (PROFILE_STRICT(flags)) {
result = TCL_CONVERT_SYNTAX;
src -= 2; /* Go back to beginning of high surrogate */
dst--; /* Also undo writing a single byte too much */
break;
}
if (PROFILE_REPLACE(flags)) {
/*
* Previous loop wrote a single byte to mark the high surrogate.
* Replace it with the replacement character.
*/
|
| ︙ | ︙ | |||
4290 4291 4292 4293 4294 4295 4296 |
dstEnd = dst + dstLen - TCL_UTF_MAX;
toUnicode = (const unsigned short *const *) dataPtr->toUnicode;
prefixBytes = dataPtr->prefixBytes;
pageZero = toUnicode[0];
result = TCL_OK;
| | | 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 |
dstEnd = dst + dstLen - TCL_UTF_MAX;
toUnicode = (const unsigned short *const *) dataPtr->toUnicode;
prefixBytes = dataPtr->prefixBytes;
pageZero = toUnicode[0];
result = TCL_OK;
for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
if (dst > dstEnd) {
result = TCL_CONVERT_NOSPACE;
break;
}
byte = *((unsigned char *) src);
if (prefixBytes[byte]) {
if (src >= srcEnd-1) {
|
| ︙ | ︙ | |||
4523 4524 4525 4526 4527 4528 4529 |
srcStart = src;
srcEnd = src + srcLen;
dstStart = dst;
dstEnd = dst + dstLen - TCL_UTF_MAX;
result = TCL_OK;
| | | 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 |
srcStart = src;
srcEnd = src + srcLen;
dstStart = dst;
dstEnd = dst + dstLen - TCL_UTF_MAX;
result = TCL_OK;
for (numChars = 0; src < srcEnd && numChars <= charLimit; numChars++) {
Tcl_UniChar ch = 0;
if (dst > dstEnd) {
result = TCL_CONVERT_NOSPACE;
break;
}
ch = *((unsigned char *) src);
|
| ︙ | ︙ | |||
4755 4756 4757 4758 4759 4760 4761 |
dstEnd = dst + dstLen - TCL_UTF_MAX;
state = PTR2INT(*statePtr);
if (flags & TCL_ENCODING_START) {
state = 0;
}
| | | 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 |
dstEnd = dst + dstLen - TCL_UTF_MAX;
state = PTR2INT(*statePtr);
if (flags & TCL_ENCODING_START) {
state = 0;
}
for (numChars = 0; src < srcEnd && numChars <= charLimit; ) {
int byte, hi, lo, ch;
if (dst > dstEnd) {
result = TCL_CONVERT_NOSPACE;
break;
}
byte = *((unsigned char *) src);
|
| ︙ | ︙ | |||
5280 5281 5282 5283 5284 5285 5286 |
}
return (char *) p - src;
}
/*
*-------------------------------------------------------------------------
*
| | | 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 |
}
return (char *) p - src;
}
/*
*-------------------------------------------------------------------------
*
* InitializeEncodingSearchPath --
*
* This is the fallback routine that sets the default value of the
* encoding search path if the application has not set one via a call to
* Tcl_SetEncodingSearchPath() by the first time the search path is needed
* to load encoding data.
*
* The default encoding search path is produced by taking each directory
|
| ︙ | ︙ | |||
5458 5459 5460 5461 5462 5463 5464 |
objPtr = Tcl_NewListObj(n, NULL);
for (i = 0; i < n; ++i) {
Tcl_ListObjAppendElement(interp, objPtr,
Tcl_NewStringObj(encodingProfiles[i].name, TCL_INDEX_NONE));
}
Tcl_SetObjResult(interp, objPtr);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 |
objPtr = Tcl_NewListObj(n, NULL);
for (i = 0; i < n; ++i) {
Tcl_ListObjAppendElement(interp, objPtr,
Tcl_NewStringObj(encodingProfiles[i].name, TCL_INDEX_NONE));
}
Tcl_SetObjResult(interp, objPtr);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclEnsemble.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | #include "tclCompile.h" /* * Declarations for functions local to this file: */ static Tcl_Command InitEnsembleFromOptions(Tcl_Interp *interp, | | | | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include "tclCompile.h" /* * Declarations for functions local to this file: */ static Tcl_Command InitEnsembleFromOptions(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int ReadOneEnsembleOption(Tcl_Interp *interp, Tcl_Command token, Tcl_Obj *optionObj); static int ReadAllEnsembleOptions(Tcl_Interp *interp, Tcl_Command token); static int SetEnsembleConfigOptions(Tcl_Interp *interp, Tcl_Command token, int objc, Tcl_Obj *const objv[]); static inline int EnsembleUnknownCallback(Tcl_Interp *interp, EnsembleConfig *ensemblePtr, int objc, Tcl_Obj *const objv[], Tcl_Obj **prefixObjPtr); static int NsEnsembleImplementationCmdNR(void *clientData, Tcl_Interp *interp,int objc,Tcl_Obj *const objv[]); static void BuildEnsembleConfig(EnsembleConfig *ensemblePtr); static int NsEnsembleStringOrder(const void *strPtr1, const void *strPtr2); static void DeleteEnsembleConfig(void *clientData); static void MakeCachedEnsembleCommand(Tcl_Obj *objPtr, EnsembleConfig *ensemblePtr, Tcl_HashEntry *hPtr, Tcl_Obj *fix); |
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
* ensembleCmdType is a Tcl object type that contains a reference to an
* ensemble subcommand, e.g. the "length" in [string length ab]. It is used
* to cache the mapping between the subcommand itself and the real command
* that implements it.
*/
static const Tcl_ObjType ensembleCmdType = {
| | | | | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
* ensembleCmdType is a Tcl object type that contains a reference to an
* ensemble subcommand, e.g. the "length" in [string length ab]. It is used
* to cache the mapping between the subcommand itself and the real command
* that implements it.
*/
static const Tcl_ObjType ensembleCmdType = {
"ensembleCommand", /* the type's name */
FreeEnsembleCmdRep, /* freeIntRepProc */
DupEnsembleCmdRep, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define ECRSetInternalRep(objPtr, ecRepPtr) \
do { \
Tcl_ObjInternalRep ir; \
ir.twoPtrValue.ptr1 = (ecRepPtr); \
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 |
*----------------------------------------------------------------------
*/
int
TclNamespaceEnsembleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
*----------------------------------------------------------------------
*/
int
TclNamespaceEnsembleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
Tcl_Command token; /* The ensemble command. */
enum EnsSubcmds index;
if (nsPtr == NULL || nsPtr->flags & NS_DEAD) {
if (!Tcl_InterpDeleted(interp)) {
|
| ︙ | ︙ | |||
254 255 256 257 258 259 260 |
* options are supported.
*
*----------------------------------------------------------------------
*/
static Tcl_Command
InitEnsembleFromOptions(
Tcl_Interp *interp,
| | | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
* options are supported.
*
*----------------------------------------------------------------------
*/
static Tcl_Command
InitEnsembleFromOptions(
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
Namespace *cxtPtr = nsPtr->parentPtr;
Namespace *altFoundNsPtr, *actualCxtPtr;
const char *name = nsPtr->name;
Tcl_Size len;
int allocatedMapFlag = 0;
|
| ︙ | ︙ | |||
584 585 586 587 588 589 590 |
*
*----------------------------------------------------------------------
*/
static int
SetEnsembleConfigOptions(
Tcl_Interp *interp,
Tcl_Command token, /* The ensemble to configure. */
| | | | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 |
*
*----------------------------------------------------------------------
*/
static int
SetEnsembleConfigOptions(
Tcl_Interp *interp,
Tcl_Command token, /* The ensemble to configure. */
int objc, /* The count of option-related arguments. */
Tcl_Obj *const objv[]) /* Option-related arguments. */
{
Tcl_Size len;
int allocatedMapFlag = 0;
Tcl_Obj *subcmdObj = NULL, *mapObj = NULL, *paramObj = NULL,
*unknownObj = NULL; /* Defaults, silence gcc 4 warnings */
Tcl_Obj *listObj;
Tcl_DictSearch search;
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 |
static inline EnsembleConfig *
GetEnsembleFromCommand(
Tcl_Interp *interp, /* Where to report an error. May be NULL. */
Tcl_Command token) /* What to check for ensemble-ness. */
{
Command *cmdPtr = (Command *) token;
| | | | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 |
static inline EnsembleConfig *
GetEnsembleFromCommand(
Tcl_Interp *interp, /* Where to report an error. May be NULL. */
Tcl_Command token) /* What to check for ensemble-ness. */
{
Command *cmdPtr = (Command *) token;
if (cmdPtr->objProc != TclEnsembleImplementationCmd) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"command is not an ensemble", TCL_AUTO_LENGTH));
Tcl_SetErrorCode(interp,
"TCL", "ENSEMBLE", "NOT_ENSEMBLE", (char *)NULL);
}
return NULL;
}
return (EnsembleConfig *) cmdPtr->objClientData;
}
/*
*----------------------------------------------------------------------
*
* BumpEpochIfNecessary --
*
|
| ︙ | ︙ | |||
1481 1482 1483 1484 1485 1486 1487 |
Tcl_Command token;
token = Tcl_FindCommand(interp, TclGetString(cmdNameObj), NULL, flags);
if (token == NULL) {
return NULL;
}
| | | | 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 |
Tcl_Command token;
token = Tcl_FindCommand(interp, TclGetString(cmdNameObj), NULL, flags);
if (token == NULL) {
return NULL;
}
if (((Command *) token)->objProc != TclEnsembleImplementationCmd) {
/*
* Reuse existing infrastructure for following import link chains
* rather than duplicating it.
*/
token = TclGetOriginalCommand(token);
if (token == NULL ||
((Command *) token)->objProc != TclEnsembleImplementationCmd) {
if (flags & TCL_LEAVE_ERR_MSG) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" is not an ensemble command",
TclGetString(cmdNameObj)));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "ENSEMBLE",
TclGetString(cmdNameObj), (char *)NULL);
}
|
| ︙ | ︙ | |||
1528 1529 1530 1531 1532 1533 1534 |
int
Tcl_IsEnsemble(
Tcl_Command token) /* The command to check. */
{
Command *cmdPtr = (Command *) token;
| | | | 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 |
int
Tcl_IsEnsemble(
Tcl_Command token) /* The command to check. */
{
Command *cmdPtr = (Command *) token;
if (cmdPtr->objProc == TclEnsembleImplementationCmd) {
return 1;
}
cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (cmdPtr == NULL || cmdPtr->objProc != TclEnsembleImplementationCmd) {
return 0;
}
return 1;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1579 1580 1581 1582 1583 1584 1585 |
{
Tcl_Command ensemble;
Tcl_Namespace *ns;
Tcl_DString buf, hiddenBuf;
const char **nameParts = NULL;
const char *cmdName = NULL;
Tcl_Size i, nameCount = 0;
| | < | 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 |
{
Tcl_Command ensemble;
Tcl_Namespace *ns;
Tcl_DString buf, hiddenBuf;
const char **nameParts = NULL;
const char *cmdName = NULL;
Tcl_Size i, nameCount = 0;
int ensembleFlags = 0, hiddenLen;
/*
* Construct the path for the ensemble namespace and create it.
*/
Tcl_DStringInit(&buf);
Tcl_DStringInit(&hiddenBuf);
|
| ︙ | ︙ | |||
1664 1665 1666 1667 1668 1669 1670 |
TclNewObj(mapDict);
for (i=0 ; map[i].name != NULL ; i++) {
TclNewStringObj(toObj, Tcl_DStringValue(&buf),
Tcl_DStringLength(&buf));
Tcl_AppendToObj(toObj, map[i].name, TCL_AUTO_LENGTH);
TclDictPut(NULL, mapDict, map[i].name, toObj);
| | | | | | | 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 |
TclNewObj(mapDict);
for (i=0 ; map[i].name != NULL ; i++) {
TclNewStringObj(toObj, Tcl_DStringValue(&buf),
Tcl_DStringLength(&buf));
Tcl_AppendToObj(toObj, map[i].name, TCL_AUTO_LENGTH);
TclDictPut(NULL, mapDict, map[i].name, toObj);
if (map[i].proc || map[i].nreProc) {
/*
* If the command is unsafe, hide it when we're in a safe
* interpreter. The code to do this is really hokey! It also
* doesn't work properly yet; this function is always
* currently called before the safe-interp flag is set so the
* Tcl_IsSafe check fails.
*/
if (map[i].unsafe && Tcl_IsSafe(interp)) {
cmdPtr = (Command *)
Tcl_NRCreateCommand(interp, "___tmp", map[i].proc,
map[i].nreProc, map[i].clientData, NULL);
Tcl_DStringSetLength(&hiddenBuf, hiddenLen);
if (Tcl_HideCommand(interp, "___tmp",
Tcl_DStringAppend(&hiddenBuf, map[i].name,
TCL_AUTO_LENGTH))) {
Tcl_Panic("%s", Tcl_GetStringResult(interp));
}
/* don't compile unsafe subcommands in safe interp */
cmdPtr->compileProc = NULL;
} else {
/*
* Not hidden, so just create it. Yay!
*/
cmdPtr = (Command *)
Tcl_NRCreateCommand(interp, TclGetString(toObj),
map[i].proc, map[i].nreProc, map[i].clientData,
NULL);
cmdPtr->compileProc = map[i].compileProc;
}
}
}
Tcl_SetEnsembleMappingDict(interp, ensemble, mapDict);
}
|
| ︙ | ︙ | |||
1735 1736 1737 1738 1739 1740 1741 |
*----------------------------------------------------------------------
*/
int
TclEnsembleImplementationCmd(
void *clientData,
Tcl_Interp *interp,
| | | | | | | 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 |
*----------------------------------------------------------------------
*/
int
TclEnsembleImplementationCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
return Tcl_NRCallObjProc(interp, NsEnsembleImplementationCmdNR,
clientData, objc, objv);
}
static int
NsEnsembleImplementationCmdNR(
void *clientData, /* The ensemble this is the impl. of. */
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
EnsembleConfig *ensemblePtr = (EnsembleConfig *) clientData;
/* The ensemble itself. */
Tcl_Obj *prefixObj; /* An object containing the prefix words of
* the command that implements the
* subcommand. */
Tcl_HashEntry *hPtr; /* Used for efficient lookup of fully
|
| ︙ | ︙ | |||
1966 1967 1968 1969 1970 1971 1972 |
* Record the words of the command as given so that routines like
* Tcl_WrongNumArgs can produce the correct error message. Parameters
* count both as inserted and removed arguments.
*/
if (TclInitRewriteEnsemble(interp, 2 + ensemblePtr->numParameters,
prefixObjc + ensemblePtr->numParameters, objv)) {
| | | | 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 |
* Record the words of the command as given so that routines like
* Tcl_WrongNumArgs can produce the correct error message. Parameters
* count both as inserted and removed arguments.
*/
if (TclInitRewriteEnsemble(interp, 2 + ensemblePtr->numParameters,
prefixObjc + ensemblePtr->numParameters, objv)) {
TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL,
NULL);
}
/*
* Hand off to the target command.
*/
TclSkipTailcall(interp);
|
| ︙ | ︙ | |||
2343 2344 2345 2346 2347 2348 2349 |
* ----------------------------------------------------------------------
*/
static inline int
EnsembleUnknownCallback(
Tcl_Interp *interp,
EnsembleConfig *ensemblePtr,/* The ensemble structure. */
| | | | 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 |
* ----------------------------------------------------------------------
*/
static inline int
EnsembleUnknownCallback(
Tcl_Interp *interp,
EnsembleConfig *ensemblePtr,/* The ensemble structure. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[], /* Actual arguments. */
Tcl_Obj **prefixObjPtr) /* Where to write the prefix suggested by the
* unknown callback. Must not be NULL. Only has
* a meaningful value on TCL_OK. */
{
Tcl_Size paramc;
int result;
Tcl_Size i, prefixObjc;
|
| ︙ | ︙ | |||
2745 2746 2747 2748 2749 2750 2751 |
int done;
Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch,
&keyObj, &valueObj, &done);
while (!done) {
const char *name = TclGetString(keyObj);
| | | 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 |
int done;
Tcl_DictObjFirst(NULL, ensemblePtr->subcommandDict, &dictSearch,
&keyObj, &valueObj, &done);
while (!done) {
const char *name = TclGetString(keyObj);
hPtr = Tcl_CreateHashEntry(hash, name, &isNew);
Tcl_SetHashValue(hPtr, valueObj);
Tcl_IncrRefCount(valueObj);
Tcl_DictObjNext(&dictSearch, &keyObj, &valueObj, &done);
}
} else {
/*
* Use the array of patterns and the hash table whose keys are the
|
| ︙ | ︙ | |||
3223 3224 3225 3226 3227 3228 3229 |
/*
* See whether we have a nested ensemble. If we do, we can go round the
* mulberry bush again, consuming the next word.
*/
if (cmdPtr->compileProc == TclCompileEnsemble) {
tokenPtr = TokenAfter(tokenPtr);
| | | 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 |
/*
* See whether we have a nested ensemble. If we do, we can go round the
* mulberry bush again, consuming the next word.
*/
if (cmdPtr->compileProc == TclCompileEnsemble) {
tokenPtr = TokenAfter(tokenPtr);
if ((int)parsePtr->numWords < depth + 1
|| tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
/*
* Too hard because the user has done something unpleasant like
* omitting the sub-ensemble's command name or used a non-constant
* name for a sub-ensemble's command name; we respond by bailing
* out completely (this is a rare case). [Bug 6d2f249a01]
*/
|
| ︙ | ︙ | |||
3256 3257 3258 3259 3260 3261 3262 |
goto cleanup;
}
/*
* Throw out any line information generated by the failed compile attempt.
*/
| > > > > > | > > > > > > | 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 |
goto cleanup;
}
/*
* Throw out any line information generated by the failed compile attempt.
*/
while (mapPtr->nuloc > eclIndex + 1) {
mapPtr->nuloc--;
Tcl_Free(mapPtr->loc[mapPtr->nuloc].line);
mapPtr->loc[mapPtr->nuloc].line = NULL;
}
/*
* Reset the index of next command. Toss out any from failed nested
* partial compiles.
*/
envPtr->numCommands = mapPtr->nuloc;
/*
* Failed to do a full compile for some reason. Try to do a direct invoke
* instead of going through the ensemble lookup process again.
*/
tryCompileToInv:
|
| ︙ | ︙ | |||
3302 3303 3304 3305 3306 3307 3308 |
* we're just giving up.
*/
cleanup:
Tcl_DecrRefCount(replaced);
return ourResult;
}
| | | | 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 |
* we're just giving up.
*/
cleanup:
Tcl_DecrRefCount(replaced);
return ourResult;
}
int
TclAttemptCompileProc(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
Tcl_Size depth,
Command *cmdPtr,
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation;
int result;
Tcl_Size i;
Tcl_Token *saveTokenPtr = parsePtr->tokenPtr;
Tcl_Size savedStackDepth = envPtr->currStackDepth;
Tcl_Size savedCodeNext = envPtr->codeNext - envPtr->codeStart;
Tcl_Size savedAuxDataArrayNext = envPtr->auxDataArrayNext;
Tcl_Size savedExceptArrayNext = envPtr->exceptArrayNext;
#ifdef TCL_COMPILE_DEBUG
Tcl_Size savedExceptDepth = envPtr->exceptDepth;
#endif
if (cmdPtr->compileProc == NULL) {
|
| ︙ | ︙ | |||
3344 3345 3346 3347 3348 3349 3350 |
parsePtr->numWords -= (depth - 1);
/*
* Shift the line information arrays to account for different word
* index values.
*/
| | | | | | 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 |
parsePtr->numWords -= (depth - 1);
/*
* Shift the line information arrays to account for different word
* index values.
*/
mapPtr->loc[eclIndex].line += (depth - 1);
mapPtr->loc[eclIndex].next += (depth - 1);
/*
* Hand off compilation to the subcommand compiler. At last!
*/
result = cmdPtr->compileProc(interp, parsePtr, cmdPtr, envPtr);
/*
* Undo the shift.
*/
mapPtr->loc[eclIndex].line -= (depth - 1);
mapPtr->loc[eclIndex].next -= (depth - 1);
parsePtr->numWords += (depth - 1);
parsePtr->tokenPtr = saveTokenPtr;
/*
* If our target failed to compile, revert any data from failed partial
* compiles. Note that envPtr->numCommands need not be checked because
|
| ︙ | ︙ | |||
3431 3432 3433 3434 3435 3436 3437 |
parsePtr->tokenPtr->start, diff);
}
#endif
}
return result;
}
| | < < < < | | | | < > | | > | > > > | > > | > < < < < < < < < < | 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 |
parsePtr->tokenPtr->start, diff);
}
#endif
}
return result;
}
/*
* How to compile a subcommand to a _replacing_ invoke of its implementation
* command.
*/
static void
CompileToInvokedCommand(
Tcl_Interp *interp,
Tcl_Parse *parsePtr,
Tcl_Obj *replacements,
Command *cmdPtr,
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation;
Tcl_Token *tokPtr;
Tcl_Obj *objPtr, **words;
const char *bytes;
int cmdLit, extraLiteralFlags = LITERAL_CMD_NAME;
Tcl_Size i, numWords, length;
/*
* Push the words of the command. Take care; the command words may be
* scripts that have backslashes in them, and [info frame 0] can see the
* difference. Hence the call to TclContinuationsEnterDerived...
*/
TclListObjGetElements(NULL, replacements, &numWords, &words);
for (i = 0, tokPtr = parsePtr->tokenPtr; i < parsePtr->numWords;
i++, tokPtr = TokenAfter(tokPtr)) {
if (i > 0 && i <= numWords) {
bytes = TclGetStringFromObj(words[i - 1], &length);
PushLiteral(envPtr, bytes, length);
continue;
}
SetLineInformation(i);
if (tokPtr->type == TCL_TOKEN_SIMPLE_WORD) {
int literal = TclRegisterLiteral(envPtr,
tokPtr[1].start, tokPtr[1].size, 0);
if (envPtr->clNext) {
TclContinuationsEnterDerived(
TclFetchLiteral(envPtr, literal),
tokPtr[1].start - envPtr->source,
envPtr->clNext);
}
TclEmitPush(literal, envPtr);
} else {
CompileTokens(envPtr, tokPtr, interp);
}
}
/*
* Push the name of the command we're actually dispatching to as part of
* the implementation.
*/
TclNewObj(objPtr);
Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
bytes = TclGetStringFromObj(objPtr, &length);
if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_VIA_RESOLVER)) {
extraLiteralFlags |= LITERAL_UNSHARED;
}
cmdLit = TclRegisterLiteral(envPtr, bytes, length, extraLiteralFlags);
TclSetCmdNameObj(interp, TclFetchLiteral(envPtr, cmdLit), cmdPtr);
TclEmitPush(cmdLit, envPtr);
TclDecrRefCount(objPtr);
/*
* Do the replacing dispatch.
*/
TclEmitInvoke(envPtr, INST_INVOKE_REPLACE, parsePtr->numWords,
numWords + 1);
}
/*
* Helpers that do issuing of instructions for commands that "don't have
* compilers" (well, they do; these). They all work by just generating base
* code to invoke the command; they're intended for ensemble subcommands so
* that the costs of INST_INVOKE_REPLACE can be avoided where we can work out
* that they're not needed.
*
* Note that these are NOT suitable for commands where there's an argument
* that is a script, as an [info level] or [info frame] in the inner context
* can see the difference.
*/
static int
CompileBasicNArgCommand(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to definition of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Obj *objPtr;
TclNewObj(objPtr);
Tcl_IncrRefCount(objPtr);
Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
TclCompileInvocation(interp, parsePtr->tokenPtr, objPtr,
parsePtr->numWords, envPtr);
Tcl_DecrRefCount(objPtr);
return TCL_OK;
|
| ︙ | ︙ | |||
3759 3760 3761 3762 3763 3764 3765 |
{
/*
* Verify that the number of arguments is correct; that's the only case
* that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
* which is the only code that sees the shenanigans of ensemble dispatch.
*/
| | | 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 |
{
/*
* Verify that the number of arguments is correct; that's the only case
* that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
* which is the only code that sees the shenanigans of ensemble dispatch.
*/
if ((int)parsePtr->numWords < 1) {
return TCL_ERROR;
}
return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
}
int
|
| ︙ | ︙ | |||
3781 3782 3783 3784 3785 3786 3787 |
{
/*
* Verify that the number of arguments is correct; that's the only case
* that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
* which is the only code that sees the shenanigans of ensemble dispatch.
*/
| | | 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 |
{
/*
* Verify that the number of arguments is correct; that's the only case
* that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
* which is the only code that sees the shenanigans of ensemble dispatch.
*/
if ((int)parsePtr->numWords < 2) {
return TCL_ERROR;
}
return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
}
int
|
| ︙ | ︙ | |||
3803 3804 3805 3806 3807 3808 3809 |
{
/*
* Verify that the number of arguments is correct; that's the only case
* that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
* which is the only code that sees the shenanigans of ensemble dispatch.
*/
| | | 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 |
{
/*
* Verify that the number of arguments is correct; that's the only case
* that we know will avoid the call to Tcl_WrongNumArgs() at invoke time,
* which is the only code that sees the shenanigans of ensemble dispatch.
*/
if ((int)parsePtr->numWords < 3) {
return TCL_ERROR;
}
return CompileBasicNArgCommand(interp, parsePtr, cmdPtr, envPtr);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclEnv.c.
| ︙ | ︙ | |||
36 37 38 39 40 41 42 | Tcl_ExternalToUtfDString(NULL, str, -1, dsPtr) # define utf2tenvirondstr(str, dsPtr) \ Tcl_UtfToExternalDString(NULL, str, -1, dsPtr) # define techar char #endif /* MODULE_SCOPE */ | | | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
Tcl_ExternalToUtfDString(NULL, str, -1, dsPtr)
# define utf2tenvirondstr(str, dsPtr) \
Tcl_UtfToExternalDString(NULL, str, -1, dsPtr)
# define techar char
#endif
/* MODULE_SCOPE */
size_t TclEnvEpoch = 0; /* Epoch of the tcl environment
* (if changed with tcl-env). */
static struct {
Tcl_Size cacheSize; /* Number of env strings in cache. */
char **cache; /* Array containing all of the environment
* strings that Tcl has allocated. */
#ifndef USE_PUTENV
techar **ourEnviron; /* Cache of the array that we allocate. We
* need to track this in case another
* subsystem swaps around the environ array
* like we do. */
Tcl_Size ourEnvironSize; /* Non-zero means that the environ array was
* malloced and has this many total entries
* allocated to it (not all may be in use at
* once). Zero means that the environment
|
| ︙ | ︙ | |||
426 427 428 429 430 431 432 |
#if defined(_WIN32)
if (tenviron == NULL) {
/*
* When we are started from main(), the _wenviron array could
* be NULL and will be initialized by the first _wgetenv() call.
*/
| | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
#if defined(_WIN32)
if (tenviron == NULL) {
/*
* When we are started from main(), the _wenviron array could
* be NULL and will be initialized by the first _wgetenv() call.
*/
(void) _wgetenv(L"WINDIR");
}
#endif
TclSetEnv(name, value+1);
}
TclEnvEpoch++;
Tcl_DStringFree(&nameString);
|
| ︙ | ︙ |
Changes to generic/tclEvent.c.
| ︙ | ︙ | |||
31 32 33 34 35 36 37 |
Tcl_Obj *returnOpts; /* Active return options when the error
* occurred */
struct BgError *nextPtr; /* Next in list of all pending error reports
* for this interpreter, or NULL for end of
* list. */
} BgError;
| < < < < < < < | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
Tcl_Obj *returnOpts; /* Active return options when the error
* occurred */
struct BgError *nextPtr; /* Next in list of all pending error reports
* for this interpreter, or NULL for end of
* list. */
} BgError;
/*
* One of the structures below is associated with the "tclBgError" assoc data
* for each interpreter. It keeps track of the head and tail of the list of
* pending background errors for the interpreter.
*/
typedef struct {
|
| ︙ | ︙ | |||
61 62 63 64 65 66 67 |
/*
* For each "vwait" event source a structure of the following type
* is used:
*/
typedef struct {
| | | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
/*
* For each "vwait" event source a structure of the following type
* is used:
*/
typedef struct {
int *donePtr; /* Pointer to flag to signal or NULL. */
int sequence; /* Order of occurrence. */
int mask; /* 0, or TCL_READABLE/TCL_WRITABLE. */
Tcl_Obj *sourceObj; /* Name of the event source, either a
* variable name or channel name. */
} VwaitItem;
/*
* For each exit handler created with a call to Tcl_Create(Late)ExitHandler
* there is a structure of the following type:
*/
typedef struct ExitHandler {
Tcl_ExitProc *proc; /* Function to call when process exits. */
void *clientData; /* One word of information to pass to proc. */
struct ExitHandler *nextPtr;/* Next in list of all exit handlers for this
* application, or NULL for end of list. */
} ExitHandler;
/*
* There is both per-process and per-thread exit handlers. The first list is
* controlled by a mutex. The other is in thread local storage.
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 | /* * This variable is set to 1 when Tcl_Exit is called. The variable is checked * by TclInExit() to allow different behavior for exit-time processing, e.g., * in closing of files and pipes. */ | | | | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
/*
* This variable is set to 1 when Tcl_Exit is called. The variable is checked
* by TclInExit() to allow different behavior for exit-time processing, e.g.,
* in closing of files and pipes.
*/
static int inExit = 0;
static int subsystemsInitialized = 0;
static const char ENCODING_ERROR[] = "\n\t(encoding error in stderr)";
/*
* This variable contains the application wide exit handler. It will be called
* by Tcl_Exit instead of the C-runtime exit if this variable is set to a
* non-NULL value.
*/
static Tcl_ExitProc *appExitPtr = NULL;
typedef struct ThreadSpecificData {
ExitHandler *firstExitPtr; /* First in list of all exit handlers for this
* thread. */
int inExit; /* True when this thread is exiting. This is
* used as a hack to decide to close the
* standard channels. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
#if TCL_THREADS
typedef struct {
Tcl_ThreadCreateProc *proc; /* Main() function of the thread */
void *clientData; /* The one argument to Main() */
} ThreadClientData;
static Tcl_ThreadCreateType NewThreadProc(void *clientData);
#endif /* TCL_THREADS */
/*
* Prototypes for functions referenced only in this file:
*/
|
| ︙ | ︙ | |||
185 186 187 188 189 190 191 |
errPtr->errorMsg = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(errPtr->errorMsg);
errPtr->returnOpts = Tcl_GetReturnOptions(interp, code);
Tcl_IncrRefCount(errPtr->returnOpts);
errPtr->nextPtr = NULL;
(void) TclGetBgErrorHandler(interp);
| | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
errPtr->errorMsg = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(errPtr->errorMsg);
errPtr->returnOpts = Tcl_GetReturnOptions(interp, code);
Tcl_IncrRefCount(errPtr->returnOpts);
errPtr->nextPtr = NULL;
(void) TclGetBgErrorHandler(interp);
assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL);
if (assocPtr->firstBgPtr == NULL) {
assocPtr->firstBgPtr = errPtr;
Tcl_DoWhenIdle(HandleBgErrors, assocPtr);
} else {
assocPtr->lastBgPtr->nextPtr = errPtr;
}
assocPtr->lastBgPtr = errPtr;
|
| ︙ | ︙ | |||
215 216 217 218 219 220 221 | * Depends on what actions the handler command takes for the errors. * *---------------------------------------------------------------------- */ static void HandleBgErrors( | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
* Depends on what actions the handler command takes for the errors.
*
*----------------------------------------------------------------------
*/
static void
HandleBgErrors(
void *clientData) /* Pointer to ErrAssocData structure. */
{
ErrAssocData *assocPtr = (ErrAssocData *)clientData;
Tcl_Interp *interp = assocPtr->interp;
BgError *errPtr;
/*
* Not bothering to save/restore the interp state. Assume that any code
|
| ︙ | ︙ | |||
245 246 247 248 249 250 251 | */ Tcl_Obj *copyObj = TclListObjCopy(NULL, assocPtr->cmdPrefix); errPtr = assocPtr->firstBgPtr; TclListObjGetElements(NULL, copyObj, &prefixObjc, &prefixObjv); | | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | */ Tcl_Obj *copyObj = TclListObjCopy(NULL, assocPtr->cmdPrefix); errPtr = assocPtr->firstBgPtr; TclListObjGetElements(NULL, copyObj, &prefixObjc, &prefixObjv); tempObjv = (Tcl_Obj**)Tcl_Alloc((prefixObjc+2) * sizeof(Tcl_Obj *)); memcpy(tempObjv, prefixObjv, prefixObjc*sizeof(Tcl_Obj *)); tempObjv[prefixObjc] = errPtr->errorMsg; tempObjv[prefixObjc+1] = errPtr->returnOpts; Tcl_AllowExceptions(interp); code = Tcl_EvalObjv(interp, prefixObjc+2, tempObjv, TCL_EVAL_GLOBAL); /* |
| ︙ | ︙ | |||
328 329 330 331 332 333 334 |
*----------------------------------------------------------------------
*/
int
TclDefaultBgErrorHandlerObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
*----------------------------------------------------------------------
*/
int
TclDefaultBgErrorHandlerObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *valuePtr;
Tcl_Obj *tempObjv[2];
int result, code, level;
Tcl_InterpState saved;
if (objc != 3) {
|
| ︙ | ︙ | |||
457 458 459 460 461 462 463 |
* barrage of error messages. The hidden "bgerror" command can be used
* by a security policy to interpose on such attacks and e.g. kill the
* applet after a few attempts.
*/
if (Tcl_IsSafe(interp)) {
Tcl_RestoreInterpState(interp, saved);
| | | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 |
* barrage of error messages. The hidden "bgerror" command can be used
* by a security policy to interpose on such attacks and e.g. kill the
* applet after a few attempts.
*/
if (Tcl_IsSafe(interp)) {
Tcl_RestoreInterpState(interp, saved);
TclObjInvoke(interp, 2, tempObjv, TCL_INVOKE_HIDDEN);
} else {
Tcl_Channel errChannel = Tcl_GetStdChannel(TCL_STDERR);
if (errChannel != NULL) {
Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(resultPtr);
|
| ︙ | ︙ | |||
525 526 527 528 529 530 531 |
*/
void
TclSetBgErrorHandler(
Tcl_Interp *interp,
Tcl_Obj *cmdPrefix)
{
| | | | 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 |
*/
void
TclSetBgErrorHandler(
Tcl_Interp *interp,
Tcl_Obj *cmdPrefix)
{
ErrAssocData *assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL);
if (cmdPrefix == NULL) {
Tcl_Panic("TclSetBgErrorHandler: NULL cmdPrefix argument");
}
if (assocPtr == NULL) {
/*
* First access: initialize.
*/
assocPtr = (ErrAssocData*)Tcl_Alloc(sizeof(ErrAssocData));
assocPtr->interp = interp;
assocPtr->cmdPrefix = NULL;
assocPtr->firstBgPtr = NULL;
assocPtr->lastBgPtr = NULL;
Tcl_SetAssocData(interp, "tclBgError", BgErrorDeleteProc, assocPtr);
}
if (assocPtr->cmdPrefix) {
Tcl_DecrRefCount(assocPtr->cmdPrefix);
}
assocPtr->cmdPrefix = cmdPrefix;
Tcl_IncrRefCount(assocPtr->cmdPrefix);
}
|
| ︙ | ︙ | |||
570 571 572 573 574 575 576 |
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclGetBgErrorHandler(
Tcl_Interp *interp)
{
| | | | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclGetBgErrorHandler(
Tcl_Interp *interp)
{
ErrAssocData *assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL);
if (assocPtr == NULL) {
Tcl_Obj *bgerrorObj;
TclNewLiteralStringObj(bgerrorObj, "::tcl::Bgerror");
TclSetBgErrorHandler(interp, bgerrorObj);
assocPtr = (ErrAssocData *)Tcl_GetAssocData(interp, "tclBgError", NULL);
}
return assocPtr->cmdPrefix;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
603 604 605 606 607 608 609 | * reports, they are canceled. * *---------------------------------------------------------------------- */ static void BgErrorDeleteProc( | | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 |
* reports, they are canceled.
*
*----------------------------------------------------------------------
*/
static void
BgErrorDeleteProc(
void *clientData, /* Pointer to ErrAssocData structure. */
TCL_UNUSED(Tcl_Interp *))
{
ErrAssocData *assocPtr = (ErrAssocData *)clientData;
BgError *errPtr;
while (assocPtr->firstBgPtr != NULL) {
errPtr = assocPtr->firstBgPtr;
|
| ︙ | ︙ | |||
642 643 644 645 646 647 648 |
*
*----------------------------------------------------------------------
*/
void
Tcl_CreateExitHandler(
Tcl_ExitProc *proc, /* Function to invoke. */
| | | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 |
*
*----------------------------------------------------------------------
*/
void
Tcl_CreateExitHandler(
Tcl_ExitProc *proc, /* Function to invoke. */
void *clientData) /* Arbitrary value to pass to proc. */
{
ExitHandler *exitPtr = (ExitHandler*)Tcl_Alloc(sizeof(ExitHandler));
exitPtr->proc = proc;
exitPtr->clientData = clientData;
Tcl_MutexLock(&exitMutex);
exitPtr->nextPtr = firstExitPtr;
|
| ︙ | ︙ | |||
675 676 677 678 679 680 681 |
*
*----------------------------------------------------------------------
*/
void
TclCreateLateExitHandler(
Tcl_ExitProc *proc, /* Function to invoke. */
| | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
*
*----------------------------------------------------------------------
*/
void
TclCreateLateExitHandler(
Tcl_ExitProc *proc, /* Function to invoke. */
void *clientData) /* Arbitrary value to pass to proc. */
{
ExitHandler *exitPtr = (ExitHandler*)Tcl_Alloc(sizeof(ExitHandler));
exitPtr->proc = proc;
exitPtr->clientData = clientData;
Tcl_MutexLock(&exitMutex);
exitPtr->nextPtr = firstLateExitPtr;
|
| ︙ | ︙ | |||
708 709 710 711 712 713 714 |
*
*----------------------------------------------------------------------
*/
void
Tcl_DeleteExitHandler(
Tcl_ExitProc *proc, /* Function that was previously registered. */
| | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 |
*
*----------------------------------------------------------------------
*/
void
Tcl_DeleteExitHandler(
Tcl_ExitProc *proc, /* Function that was previously registered. */
void *clientData) /* Arbitrary value to pass to proc. */
{
ExitHandler *exitPtr, *prevPtr;
Tcl_MutexLock(&exitMutex);
for (prevPtr = NULL, exitPtr = firstExitPtr; exitPtr != NULL;
prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
if ((exitPtr->proc == proc)
|
| ︙ | ︙ | |||
751 752 753 754 755 756 757 |
*
*----------------------------------------------------------------------
*/
void
TclDeleteLateExitHandler(
Tcl_ExitProc *proc, /* Function that was previously registered. */
| | | 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 |
*
*----------------------------------------------------------------------
*/
void
TclDeleteLateExitHandler(
Tcl_ExitProc *proc, /* Function that was previously registered. */
void *clientData) /* Arbitrary value to pass to proc. */
{
ExitHandler *exitPtr, *prevPtr;
Tcl_MutexLock(&exitMutex);
for (prevPtr = NULL, exitPtr = firstLateExitPtr; exitPtr != NULL;
prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
if ((exitPtr->proc == proc)
|
| ︙ | ︙ | |||
794 795 796 797 798 799 800 |
*
*----------------------------------------------------------------------
*/
void
Tcl_CreateThreadExitHandler(
Tcl_ExitProc *proc, /* Function to invoke. */
| | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 |
*
*----------------------------------------------------------------------
*/
void
Tcl_CreateThreadExitHandler(
Tcl_ExitProc *proc, /* Function to invoke. */
void *clientData) /* Arbitrary value to pass to proc. */
{
ExitHandler *exitPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
exitPtr = (ExitHandler*)Tcl_Alloc(sizeof(ExitHandler));
exitPtr->proc = proc;
exitPtr->clientData = clientData;
|
| ︙ | ︙ | |||
827 828 829 830 831 832 833 |
*
*----------------------------------------------------------------------
*/
void
Tcl_DeleteThreadExitHandler(
Tcl_ExitProc *proc, /* Function that was previously registered. */
| | | 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 |
*
*----------------------------------------------------------------------
*/
void
Tcl_DeleteThreadExitHandler(
Tcl_ExitProc *proc, /* Function that was previously registered. */
void *clientData) /* Arbitrary value to pass to proc. */
{
ExitHandler *exitPtr, *prevPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
for (prevPtr = NULL, exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL;
prevPtr = exitPtr, exitPtr = exitPtr->nextPtr) {
if ((exitPtr->proc == proc)
|
| ︙ | ︙ | |||
889 890 891 892 893 894 895 | } /* *---------------------------------------------------------------------- * * InvokeExitHandlers -- * | | | | | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 |
}
/*
*----------------------------------------------------------------------
*
* InvokeExitHandlers --
*
* Call the registered exit handlers.
*
* Results:
* None.
*
* Side effects:
* The exit handlers are invoked, and the ExitHandler struct is
* freed.
*
*----------------------------------------------------------------------
*/
static void
InvokeExitHandlers(void)
{
ExitHandler *exitPtr;
Tcl_MutexLock(&exitMutex);
inExit = 1;
for (exitPtr = firstExitPtr; exitPtr != NULL; exitPtr = firstExitPtr) {
/*
* Be careful to remove the handler from the list before invoking its
* callback. This protects us against double-freeing if the callback
* should call Tcl_DeleteExitHandler on itself.
*/
|
| ︙ | ︙ | |||
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 |
* returns, so critical is this dependency.
*
* If subsystems are not (yet) initialized, proper Tcl-finalization is
* impossible, so fallback to system exit, see bug-[f8a33ce3db5d8cc2].
*/
if (currentAppExitPtr) {
currentAppExitPtr(INT2PTR(status));
} else if (subsystemsInitialized) {
if (TclFullFinalizationRequested()) {
/*
* Thorough finalization for Valgrind et al.
*/
Tcl_Finalize();
} else {
/*
* Fast and deterministic exit (default behavior)
*/
InvokeExitHandlers();
/*
| > > > > > > | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 |
* returns, so critical is this dependency.
*
* If subsystems are not (yet) initialized, proper Tcl-finalization is
* impossible, so fallback to system exit, see bug-[f8a33ce3db5d8cc2].
*/
if (currentAppExitPtr) {
currentAppExitPtr(INT2PTR(status));
} else if (subsystemsInitialized) {
if (TclFullFinalizationRequested()) {
/*
* Thorough finalization for Valgrind et al.
*/
Tcl_Finalize();
} else {
/*
* Fast and deterministic exit (default behavior)
*/
InvokeExitHandlers();
/*
|
| ︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 | #if ZLIB_VER_MINOR < 10 "0" #endif STRINGIFY(ZLIB_VER_MINOR) #endif // TCL_WITH_INTERNAL_ZLIB }}; | < < < < < < < < < | | | > | < < < < < < < < < < < < < < < < < < < < < < | | | 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 |
#if ZLIB_VER_MINOR < 10
"0"
#endif
STRINGIFY(ZLIB_VER_MINOR)
#endif // TCL_WITH_INTERNAL_ZLIB
}};
const char *
Tcl_InitSubsystems(void)
{
if (inExit != 0) {
Tcl_Panic("Tcl_InitSubsystems called while exiting");
}
if (subsystemsInitialized == 0) {
/*
* Double check inside the mutex. There are definitely calls back into
* this routine from some of the functions below.
*/
TclpInitLock();
if (subsystemsInitialized == 0) {
/*
* Initialize locks used by the memory allocators before anything
* interesting happens so we can use the allocators in the
* implementation of self-initializing locks.
*/
TclInitThreadStorage(); /* Creates hash table for
* thread local storage */
#if defined(USE_TCLALLOC) && USE_TCLALLOC
TclInitAlloc(); /* Process wide mutex init */
#endif
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
TclInitThreadAlloc(); /* Setup thread allocator caches */
#endif
#ifdef TCL_MEM_DEBUG
TclInitDbCkalloc(); /* Process wide mutex init */
#endif
TclpInitPlatform(); /* Creates signal handler(s) */
TclInitDoubleConversion(); /* Initializes constants for
* converting to/from double. */
TclInitObjSubsystem(); /* Register obj types, create
* mutexes. */
TclInitIOSubsystem(); /* Inits a tsd key (noop). */
TclInitEncodingSubsystem(); /* Process wide encoding init. */
TclInitNamespaceSubsystem();/* Register ns obj type (mutexed). */
subsystemsInitialized = 1;
}
TclpInitUnlock();
}
TclInitNotifier();
return stubInfo.version;
}
/*
*----------------------------------------------------------------------
*
* Tcl_Finalize --
*
|
| ︙ | ︙ | |||
1228 1229 1230 1231 1232 1233 1234 |
/*
* Invoke exit handlers first.
*/
InvokeExitHandlers();
TclpInitLock();
| | | | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 |
/*
* Invoke exit handlers first.
*/
InvokeExitHandlers();
TclpInitLock();
if (subsystemsInitialized == 0) {
goto alreadyFinalized;
}
subsystemsInitialized = 0;
/*
* Ensure the thread-specific data is initialised as it is used in
* Tcl_FinalizeThread()
*/
(void) TCL_TSD_INIT(&dataKey);
|
| ︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 |
if (firstExitPtr != NULL) {
Tcl_Panic("exit handlers were created during Tcl_Finalize");
}
TclFinalizePreserve();
| < < < < < < < | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 |
if (firstExitPtr != NULL) {
Tcl_Panic("exit handlers were created during Tcl_Finalize");
}
TclFinalizePreserve();
/*
* Free synchronization objects. There really should only be one thread
* alive at this moment.
*/
TclFinalizeSynchronization();
/*
* Close down the thread-specific object allocator.
*/
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
TclFinalizeThreadAlloc();
|
| ︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 |
void
Tcl_FinalizeThread(void)
{
FinalizeThread(/* quick */ 0);
}
| | | | 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 |
void
Tcl_FinalizeThread(void)
{
FinalizeThread(/* quick */ 0);
}
void
FinalizeThread(
int quick)
{
ExitHandler *exitPtr;
ThreadSpecificData *tsdPtr;
/*
* We use TclThreadDataKeyGet here, rather than Tcl_GetThreadData, because
* we don't want to initialize the data block if it hasn't been
* initialized already.
*/
tsdPtr = (ThreadSpecificData*)TclThreadDataKeyGet(&dataKey);
if (tsdPtr != NULL) {
tsdPtr->inExit = 1;
for (exitPtr = tsdPtr->firstExitPtr; exitPtr != NULL;
exitPtr = tsdPtr->firstExitPtr) {
/*
* Be careful to remove the handler from the list before invoking
* its callback. This protects us against double-freeing if the
* callback should call Tcl_DeleteThreadExitHandler on itself.
|
| ︙ | ︙ | |||
1478 1479 1480 1481 1482 1483 1484 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | < > | 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclInExit(void)
{
return inExit;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1500 1501 1502 1503 1504 1505 1506 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | < > | | 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclInThreadExit(void)
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
if (tsdPtr == NULL) {
return 0;
}
return tsdPtr->inExit;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1532 1533 1534 1535 1536 1537 1538 |
*----------------------------------------------------------------------
*/
int
Tcl_VwaitObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < | | | | 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 |
*----------------------------------------------------------------------
*/
int
Tcl_VwaitObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int i, done = 0, timedOut = 0, foundEvent, any = 1, timeout = 0;
int numItems = 0, extended = 0, result, mode, mask = TCL_ALL_EVENTS;
Tcl_InterpState saved = NULL;
Tcl_TimerToken timer = NULL;
Tcl_Time before, after;
Tcl_Channel chan;
Tcl_WideInt diff = -1;
VwaitItem localItems[32], *vwaitItems = localItems;
static const char *const vWaitOptionStrings[] = {
"-all", "-extended", "-nofileevents", "-noidleevents",
"-notimerevents", "-nowindowevents", "-readable",
"-timeout", "-variable", "-writable", "--", NULL
|
| ︙ | ︙ | |||
1635 1636 1637 1638 1639 1640 1641 |
result = Tcl_TraceVar2(interp, TclGetString(objv[i]), NULL,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VwaitVarProc, &vwaitItems[numItems]);
if (result != TCL_OK) {
goto done;
}
vwaitItems[numItems].donePtr = &done;
| | | 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 |
result = Tcl_TraceVar2(interp, TclGetString(objv[i]), NULL,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VwaitVarProc, &vwaitItems[numItems]);
if (result != TCL_OK) {
goto done;
}
vwaitItems[numItems].donePtr = &done;
vwaitItems[numItems].sequence = -1;
vwaitItems[numItems].mask = 0;
vwaitItems[numItems].sourceObj = objv[i];
numItems++;
break;
case OPT_READABLE:
if (++i >= objc) {
goto needArg;
|
| ︙ | ︙ | |||
1659 1660 1661 1662 1663 1664 1665 | TclGetString(objv[i]))); result = TCL_ERROR; goto done; } Tcl_CreateChannelHandler(chan, TCL_READABLE, VwaitChannelReadProc, &vwaitItems[numItems]); vwaitItems[numItems].donePtr = &done; | | | 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 |
TclGetString(objv[i])));
result = TCL_ERROR;
goto done;
}
Tcl_CreateChannelHandler(chan, TCL_READABLE,
VwaitChannelReadProc, &vwaitItems[numItems]);
vwaitItems[numItems].donePtr = &done;
vwaitItems[numItems].sequence = -1;
vwaitItems[numItems].mask = TCL_READABLE;
vwaitItems[numItems].sourceObj = objv[i];
numItems++;
break;
case OPT_WRITABLE:
if (++i >= objc) {
goto needArg;
|
| ︙ | ︙ | |||
1683 1684 1685 1686 1687 1688 1689 | TclGetString(objv[i]))); result = TCL_ERROR; goto done; } Tcl_CreateChannelHandler(chan, TCL_WRITABLE, VwaitChannelWriteProc, &vwaitItems[numItems]); vwaitItems[numItems].donePtr = &done; | | | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | TclGetString(objv[i]))); result = TCL_ERROR; goto done; } Tcl_CreateChannelHandler(chan, TCL_WRITABLE, VwaitChannelWriteProc, &vwaitItems[numItems]); vwaitItems[numItems].donePtr = &done; vwaitItems[numItems].sequence = -1; vwaitItems[numItems].mask = TCL_WRITABLE; vwaitItems[numItems].sourceObj = objv[i]; numItems++; break; default: TCL_UNREACHABLE(); } |
| ︙ | ︙ | |||
1719 1720 1721 1722 1723 1724 1725 |
result = Tcl_TraceVar2(interp, TclGetString(objv[i]), NULL,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VwaitVarProc, &vwaitItems[numItems]);
if (result != TCL_OK) {
break;
}
vwaitItems[numItems].donePtr = &done;
| | | 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 |
result = Tcl_TraceVar2(interp, TclGetString(objv[i]), NULL,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VwaitVarProc, &vwaitItems[numItems]);
if (result != TCL_OK) {
break;
}
vwaitItems[numItems].donePtr = &done;
vwaitItems[numItems].sequence = -1;
vwaitItems[numItems].mask = 0;
vwaitItems[numItems].sourceObj = objv[i];
numItems++;
}
if (result != TCL_OK) {
result = TCL_ERROR;
goto done;
|
| ︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 |
goto done;
}
}
}
if (timeout > 0) {
vwaitItems[numItems].donePtr = &timedOut;
| | | | | 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 |
goto done;
}
}
}
if (timeout > 0) {
vwaitItems[numItems].donePtr = &timedOut;
vwaitItems[numItems].sequence = -1;
vwaitItems[numItems].mask = 0;
vwaitItems[numItems].sourceObj = NULL;
timer = Tcl_CreateTimerHandler(timeout, VwaitTimeoutProc,
&vwaitItems[numItems]);
Tcl_GetTime(&before);
} else {
timeout = 0;
}
if ((numItems == 0) && (timeout == 0)) {
/*
* "vwait" is equivalent to "update",
* "vwait -nofileevents -notimerevents -nowindowevents"
* is equivalent to "update idletasks"
*/
any = 1;
mask |= TCL_DONT_WAIT;
}
foundEvent = 1;
while (!timedOut && foundEvent &&
((!any && (done < numItems)) || (any && !done))) {
foundEvent = Tcl_DoOneEvent(mask);
if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
break;
}
if (Tcl_LimitExceeded(interp)) {
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1));
|
| ︙ | ︙ | |||
1823 1824 1825 1826 1827 1828 1829 |
/*
* When timeout was specified, report milliseconds left or -1 on timeout.
*/
if (timedOut) {
diff = -1;
} else {
| | | | | 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 |
/*
* When timeout was specified, report milliseconds left or -1 on timeout.
*/
if (timedOut) {
diff = -1;
} else {
Tcl_GetTime(&after);
diff = after.sec * 1000 + after.usec / 1000;
diff -= before.sec * 1000 + before.usec / 1000;
diff = timeout - diff;
if (diff < 0) {
diff = 0;
}
}
done:
|
| ︙ | ︙ | |||
1861 1862 1863 1864 1865 1866 1867 |
NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VwaitVarProc, &vwaitItems[i]);
}
}
if (result == TCL_OK) {
if (extended) {
| | | 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 |
NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
VwaitVarProc, &vwaitItems[i]);
}
}
if (result == TCL_OK) {
if (extended) {
int k;
Tcl_Obj *listObj, *keyObj;
TclNewObj(listObj);
for (k = 0; k < done; k++) {
for (i = 0; i < numItems; i++) {
if (vwaitItems[i].sequence != k) {
continue;
|
| ︙ | ︙ | |||
1988 1989 1990 1991 1992 1993 1994 |
*----------------------------------------------------------------------
*/
int
Tcl_UpdateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 |
*----------------------------------------------------------------------
*/
int
Tcl_UpdateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int flags = 0; /* Initialized to avoid compiler warning. */
static const char *const updateOptions[] = {"idletasks", NULL};
enum updateOptionsEnum {OPT_IDLETASKS} optionIndex;
if (objc == 1) {
flags = TCL_ALL_EVENTS|TCL_DONT_WAIT;
|
| ︙ | ︙ | |||
2093 2094 2095 2096 2097 2098 2099 |
*/
int
Tcl_CreateThread(
Tcl_ThreadId *idPtr, /* Return, the ID of the thread */
Tcl_ThreadCreateProc *proc, /* Main() function of the thread */
void *clientData, /* The one argument to Main() */
| | | 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 |
*/
int
Tcl_CreateThread(
Tcl_ThreadId *idPtr, /* Return, the ID of the thread */
Tcl_ThreadCreateProc *proc, /* Main() function of the thread */
void *clientData, /* The one argument to Main() */
size_t stackSize, /* Size of stack for the new thread */
int flags) /* Flags controlling behaviour of the new
* thread. */
{
#if TCL_THREADS
ThreadClientData *cdPtr = (ThreadClientData *)Tcl_Alloc(sizeof(ThreadClientData));
int result;
|
| ︙ | ︙ |
Changes to generic/tclExecute.c.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | * Copyright © 2006-2008 Joe Mistachkin. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < < < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | * Copyright © 2006-2008 Joe Mistachkin. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" #include "tclOOInt.h" #include "tclTomMath.h" #include <math.h> #if defined(__GNUC__) && (__GNUC__ > 4) && defined(_WIN32) && defined(TCL_COMPILE_DEBUG) // These are FAR too noisy when we're using the MSVC runtime. |
| ︙ | ︙ | |||
69 70 71 72 73 74 75 | * 0: no execution tracing * 1: trace invocations of Tcl procs only * 2: trace invocations of all (not compiled away) commands * 3: display each instruction executed * This variable is linked to the Tcl variable "tcl_traceExec". */ | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | * 0: no execution tracing * 1: trace invocations of Tcl procs only * 2: trace invocations of all (not compiled away) commands * 3: display each instruction executed * This variable is linked to the Tcl variable "tcl_traceExec". */ int tclTraceExec = 0; #endif /* * Mapping from expression instruction opcodes to strings; used for error * messages. Note that these entries must match the order and number of the * expression opcodes (e.g., INST_LOR) in tclCompile.h. * |
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
typedef struct {
ByteCode *codePtr; /* Constant until the BC returns */
/* -----------------------------------------*/
Tcl_Obj **catchTop; /* These fields are used on return TO this */
Tcl_Obj *auxObjList; /* level: they record the state when a new */
CmdFrame cmdFrame; /* codePtr was received for NR execution. */
| < < < | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
typedef struct {
ByteCode *codePtr; /* Constant until the BC returns */
/* -----------------------------------------*/
Tcl_Obj **catchTop; /* These fields are used on return TO this */
Tcl_Obj *auxObjList; /* level: they record the state when a new */
CmdFrame cmdFrame; /* codePtr was received for NR execution. */
Tcl_Obj *stack[1]; /* Start of the actual combined catch and obj
* stacks; the struct will be expanded as
* necessary */
} TEBCdata;
#define TEBC_YIELD() \
do { \
|
| ︙ | ︙ | |||
227 228 229 230 231 232 233 |
if ((resultHandling) > 0) { \
Tcl_IncrRefCount(objResultPtr); \
} \
pc += (pcAdjustment); \
switch (nCleanup) { \
case 1: goto cleanup1_pushObjResultPtr; \
case 2: goto cleanup2_pushObjResultPtr; \
| | < | | < < < < < < < < < < < < < < < | > | > | | > | | > > < > > | > | > | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
if ((resultHandling) > 0) { \
Tcl_IncrRefCount(objResultPtr); \
} \
pc += (pcAdjustment); \
switch (nCleanup) { \
case 1: goto cleanup1_pushObjResultPtr; \
case 2: goto cleanup2_pushObjResultPtr; \
case 0: break; \
} \
} else { \
pc += (pcAdjustment); \
switch (nCleanup) { \
case 1: goto cleanup1; \
case 2: goto cleanup2; \
default: break; \
} \
} \
} while (0)
#define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \
CHECK_STACK(); \
do { \
pc += (pcAdjustment); \
cleanup = (nCleanup); \
if (resultHandling) { \
if ((resultHandling) > 0) { \
Tcl_IncrRefCount(objResultPtr); \
} \
goto cleanupV_pushObjResultPtr; \
} else { \
goto cleanupV; \
} \
} while (0)
#ifndef TCL_COMPILE_DEBUG
#define JUMP_PEEPHOLE_F(condition, pcAdjustment, cleanup) \
do { \
pc += (pcAdjustment); \
switch (*pc) { \
case INST_JUMP_FALSE1: \
NEXT_INST_F(((condition)? 2 : TclGetInt1AtPtr(pc + 1)), (cleanup), 0); \
break; \
case INST_JUMP_TRUE1: \
NEXT_INST_F(((condition)? TclGetInt1AtPtr(pc + 1) : 2), (cleanup), 0); \
break; \
case INST_JUMP_FALSE4: \
NEXT_INST_F(((condition)? 5 : TclGetInt4AtPtr(pc + 1)), (cleanup), 0); \
break; \
case INST_JUMP_TRUE4: \
NEXT_INST_F(((condition)? TclGetInt4AtPtr(pc + 1) : 5), (cleanup), 0); \
break; \
default: \
if ((condition) < 0) { \
TclNewIntObj(objResultPtr, -1); \
} else { \
objResultPtr = TCONST((condition) > 0); \
} \
NEXT_INST_F(0, (cleanup), 1); \
break; \
} \
} while (0)
#define JUMP_PEEPHOLE_V(condition, pcAdjustment, cleanup) \
do { \
pc += (pcAdjustment); \
switch (*pc) { \
case INST_JUMP_FALSE1: \
NEXT_INST_V(((condition)? 2 : TclGetInt1AtPtr(pc + 1)), (cleanup), 0); \
break; \
case INST_JUMP_TRUE1: \
NEXT_INST_V(((condition)? TclGetInt1AtPtr(pc + 1) : 2), (cleanup), 0); \
break; \
case INST_JUMP_FALSE4: \
NEXT_INST_V(((condition)? 5 : TclGetInt4AtPtr(pc + 1)), (cleanup), 0); \
break; \
case INST_JUMP_TRUE4: \
NEXT_INST_V(((condition)? TclGetInt4AtPtr(pc + 1) : 5), (cleanup), 0); \
break; \
default: \
if ((condition) < 0) { \
TclNewIntObj(objResultPtr, -1); \
} else { \
objResultPtr = TCONST((condition) > 0); \
} \
NEXT_INST_V(0, (cleanup), 1); \
break; \
} \
} while (0)
#else /* TCL_COMPILE_DEBUG */
#define JUMP_PEEPHOLE_F(condition, pcAdjustment, cleanup) \
do{ \
if ((condition) < 0) { \
TclNewIntObj(objResultPtr, -1); \
} else { \
objResultPtr = TCONST((condition) > 0); \
} \
NEXT_INST_F((pcAdjustment), (cleanup), 1); \
} while (0)
#define JUMP_PEEPHOLE_V(condition, pcAdjustment, cleanup) \
do{ \
if ((condition) < 0) { \
TclNewIntObj(objResultPtr, -1); \
} else { \
objResultPtr = TCONST((condition) > 0); \
} \
NEXT_INST_V((pcAdjustment), (cleanup), 1); \
} while (0)
#endif
/*
* Macros used to cache often-referenced Tcl evaluation stack information
* in local variables. Note that a DECACHE_STACK_INFO()-CACHE_STACK_INFO()
* pair must surround any call inside TclNRExecuteByteCode (and a few other
* procedures that use this scheme) that could result in a recursive call
* to TclNRExecuteByteCode.
|
| ︙ | ︙ | |||
410 411 412 413 414 415 416 |
*/
#define PUSH_OBJECT(objPtr) \
Tcl_IncrRefCount(*(++tosPtr) = (objPtr))
#define POP_OBJECT() *(tosPtr--)
| | < < < < < | | | | | | | | | < < < < < | > > > > > > > > > > > > > > | < < > | < | < | < | < < | < < < | < | | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
*/
#define PUSH_OBJECT(objPtr) \
Tcl_IncrRefCount(*(++tosPtr) = (objPtr))
#define POP_OBJECT() *(tosPtr--)
#define OBJ_AT_TOS *tosPtr
#define OBJ_UNDER_TOS tosPtr[-1]
#define OBJ_AT_DEPTH(n) tosPtr[-(n)]
#define CURR_DEPTH (tosPtr - initTosPtr)
#define STACK_BASE(esPtr) ((esPtr)->stackWords - 1)
/*
* Macros used to trace instruction execution. The macros TRACE,
* TRACE_WITH_OBJ, and O2S are only used inside TclNRExecuteByteCode. O2S is
* only used in TRACE* calls to get a string from an object.
*/
#ifdef TCL_COMPILE_DEBUG
# define TRACE(a) \
while (traceInstructions) { \
fprintf(stdout, "%2" TCL_SIZE_MODIFIER "d: %2" TCL_SIZE_MODIFIER \
"d (%" TCL_SIZE_MODIFIER "d) %s ", iPtr->numLevels, \
CURR_DEPTH, \
(pc - codePtr->codeStart), \
GetOpcodeName(pc)); \
printf a; \
break; \
}
# define TRACE_APPEND(a) \
while (traceInstructions) { \
printf a; \
break; \
}
# define TRACE_ERROR(interp) \
TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp))));
# define TRACE_WITH_OBJ(a, objPtr) \
while (traceInstructions) { \
fprintf(stdout, "%2" TCL_SIZE_MODIFIER "d: %2" TCL_SIZE_MODIFIER \
"d (%" TCL_SIZE_MODIFIER "d) %s ", iPtr->numLevels, \
CURR_DEPTH, \
(pc - codePtr->codeStart), \
GetOpcodeName(pc)); \
printf a; \
TclPrintObject(stdout, objPtr, 30); \
fprintf(stdout, "\n"); \
break; \
}
# define O2S(objPtr) \
(objPtr ? TclGetString(objPtr) : "")
#else /* !TCL_COMPILE_DEBUG */
# define TRACE(a)
# define TRACE_APPEND(a)
# define TRACE_ERROR(interp)
# define TRACE_WITH_OBJ(a, objPtr)
# define O2S(objPtr)
#endif /* TCL_COMPILE_DEBUG */
/*
* DTrace instruction probe macros.
*/
#define TCL_DTRACE_INST_NEXT() \
do { \
if (TCL_DTRACE_INST_DONE_ENABLED()) { \
if (curInstName) { \
TCL_DTRACE_INST_DONE(curInstName, CURR_DEPTH, \
tosPtr); \
} \
curInstName = tclInstructionTable[*pc].name; \
if (TCL_DTRACE_INST_START_ENABLED()) { \
TCL_DTRACE_INST_START(curInstName, CURR_DEPTH, \
tosPtr); \
} \
} else if (TCL_DTRACE_INST_START_ENABLED()) { \
TCL_DTRACE_INST_START(tclInstructionTable[*pc].name, \
CURR_DEPTH, tosPtr); \
} \
} while (0)
#define TCL_DTRACE_INST_LAST() \
do { \
if (TCL_DTRACE_INST_DONE_ENABLED() && curInstName) { \
TCL_DTRACE_INST_DONE(curInstName, CURR_DEPTH, tosPtr); \
} \
|
| ︙ | ︙ | |||
670 671 672 673 674 675 676 | #define OUT_OF_MEMORY ((Tcl_Obj *) -4) /* * Declarations for local procedures to this file: */ #ifdef TCL_COMPILE_STATS | | < < | | 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 |
#define OUT_OF_MEMORY ((Tcl_Obj *) -4)
/*
* Declarations for local procedures to this file:
*/
#ifdef TCL_COMPILE_STATS
static Tcl_ObjCmdProc EvalStatsCmd;
#endif /* TCL_COMPILE_STATS */
#ifdef TCL_COMPILE_DEBUG
static const char * GetOpcodeName(const unsigned char *pc);
static void PrintByteCodeInfo(ByteCode *codePtr);
static const char * StringForResultCode(int result);
static void ValidatePcAndStackTop(ByteCode *codePtr,
const unsigned char *pc, size_t stackTop,
int checkStack);
#endif /* TCL_COMPILE_DEBUG */
static ByteCode * CompileExprObj(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void DeleteExecStack(ExecStack *esPtr);
static void DupExprCodeInternalRep(Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr);
static Tcl_Obj * ExecuteExtendedBinaryMathOp(Tcl_Interp *interp,
int opcode, Tcl_Obj **constants,
Tcl_Obj *valuePtr, Tcl_Obj *value2Ptr);
static Tcl_Obj * ExecuteExtendedUnaryMathOp(int opcode,
Tcl_Obj *valuePtr);
static void FreeExprCodeInternalRep(Tcl_Obj *objPtr);
static ExceptionRange * GetExceptRangeForPc(const unsigned char *pc,
int searchMode, ByteCode *codePtr);
static const char * GetSrcInfoForPc(const unsigned char *pc,
ByteCode *codePtr, Tcl_Size *lengthPtr,
const unsigned char **pcBeg, Tcl_Size *cmdIdxPtr);
static Tcl_Obj ** GrowEvaluationStack(ExecEnv *eePtr, size_t growth,
int move);
static void IllegalExprOperandType(Tcl_Interp *interp, const char *ord,
const unsigned char *pc, Tcl_Obj *opndPtr);
static void InitByteCodeExecution(Tcl_Interp *interp);
static inline int WordSkip(void *ptr);
static void ReleaseDictIterator(Tcl_Obj *objPtr);
/* Useful elsewhere, make available in tclInt.h or stubs? */
static Tcl_Obj ** StackAllocWords(Tcl_Interp *interp, size_t numWords);
static Tcl_Obj ** StackReallocWords(Tcl_Interp *interp, size_t numWords);
static Tcl_NRPostProc CopyCallback;
static Tcl_NRPostProc ExprObjCallback;
static Tcl_NRPostProc FinalizeOONext;
static Tcl_NRPostProc FinalizeOONextFilter;
static Tcl_NRPostProc TEBCresume;
/*
* The structure below defines a bytecode Tcl object type to hold the
* compiled bytecode for Tcl expressions.
*/
const Tcl_ObjType tclExprCodeType = {
|
| ︙ | ︙ | |||
813 814 815 816 817 818 819 |
#ifdef TCL_COMPILE_DEBUG
if (Tcl_LinkVar(interp, "tcl_traceExec", &tclTraceExec,
TCL_LINK_INT) != TCL_OK) {
Tcl_Panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
}
#endif
#ifdef TCL_COMPILE_STATS
| | | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
#ifdef TCL_COMPILE_DEBUG
if (Tcl_LinkVar(interp, "tcl_traceExec", &tclTraceExec,
TCL_LINK_INT) != TCL_OK) {
Tcl_Panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
}
#endif
#ifdef TCL_COMPILE_STATS
Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd, NULL, NULL);
#endif /* TCL_COMPILE_STATS */
}
#else
static void
InitByteCodeExecution(
|
| ︙ | ︙ | |||
853 854 855 856 857 858 859 |
*/
ExecEnv *
TclCreateExecEnv(
Tcl_Interp *interp, /* Interpreter for which the execution
* environment is being created. */
size_t size) /* The initial stack size, in number of words
| | | 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
*/
ExecEnv *
TclCreateExecEnv(
Tcl_Interp *interp, /* Interpreter for which the execution
* environment is being created. */
size_t size) /* The initial stack size, in number of words
* [sizeof(Tcl_Obj*)] */
{
ExecEnv *eePtr = (ExecEnv *)Tcl_Alloc(sizeof(ExecEnv));
ExecStack *esPtr = (ExecStack *)Tcl_Alloc(offsetof(ExecStack, stackWords)
+ size * sizeof(Tcl_Obj *));
eePtr->execStackPtr = esPtr;
TclNewIntObj(eePtr->constants[0], 0);
|
| ︙ | ︙ | |||
990 991 992 993 994 995 996 |
* multiple of the wordsize 'sizeof(Tcl_Obj *)'.
*/
#define WALLOCALIGN \
(TCL_ALLOCALIGN/sizeof(Tcl_Obj *))
/*
| < < < < | | | < < | | 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 |
* multiple of the wordsize 'sizeof(Tcl_Obj *)'.
*/
#define WALLOCALIGN \
(TCL_ALLOCALIGN/sizeof(Tcl_Obj *))
/*
* WordSkip computes how many words have to be skipped until the next aligned
* word. Note that we are only interested in the low order bits of ptr, so
* that any possible information loss in PTR2INT is of no consequence.
*/
static inline int
WordSkip(
void *ptr)
{
int mask = TCL_ALLOCALIGN - 1;
int base = (int)PTR2INT(ptr) & mask;
return (TCL_ALLOCALIGN - base) / (int)sizeof(Tcl_Obj *);
}
/*
* Given a marker, compute where the following aligned memory starts.
*/
#define MEMSTART(markerPtr) \
((markerPtr) + WordSkip(markerPtr))
/*
*----------------------------------------------------------------------
*
* GrowEvaluationStack --
*
* This procedure grows a Tcl evaluation stack stored in an ExecEnv,
* copying over the words since the last mark if so requested. A mark is
|
| ︙ | ︙ | |||
1347 1348 1349 1350 1351 1352 1353 |
int
Tcl_ExprObj(
Tcl_Interp *interp, /* Context in which to evaluate the
* expression. */
Tcl_Obj *objPtr, /* Points to Tcl object containing expression
* to evaluate. */
| | | 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 |
int
Tcl_ExprObj(
Tcl_Interp *interp, /* Context in which to evaluate the
* expression. */
Tcl_Obj *objPtr, /* Points to Tcl object containing expression
* to evaluate. */
Tcl_Obj **resultPtrPtr) /* Where the Tcl_Obj* that is the expression
* result is stored if no errors occur. */
{
NRE_callback *rootPtr = TOP_CB(interp);
Tcl_Obj *resultPtr;
TclNewObj(resultPtr);
TclNRAddCallback(interp, CopyCallback, resultPtrPtr, resultPtr,
|
| ︙ | ︙ | |||
1411 1412 1413 1414 1415 1416 1417 |
Tcl_Obj *objPtr,
Tcl_Obj *resultPtr)
{
Tcl_InterpState state = Tcl_SaveInterpState(interp, TCL_OK);
Tcl_ResetResult(interp);
ByteCode *codePtr = CompileExprObj(interp, objPtr);
| | > | 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 |
Tcl_Obj *objPtr,
Tcl_Obj *resultPtr)
{
Tcl_InterpState state = Tcl_SaveInterpState(interp, TCL_OK);
Tcl_ResetResult(interp);
ByteCode *codePtr = CompileExprObj(interp, objPtr);
Tcl_NRAddCallback(interp, ExprObjCallback, state, resultPtr,
NULL, NULL);
return TclNRExecuteByteCode(interp, codePtr);
}
static int
ExprObjCallback(
void *data[],
Tcl_Interp *interp,
|
| ︙ | ︙ | |||
1491 1492 1493 1494 1495 1496 1497 | * TIP #280: No invoker (yet) - Expression compilation. */ Tcl_Size length; const char *string = TclGetStringFromObj(objPtr, &length); TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0); | | | > | 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 |
* TIP #280: No invoker (yet) - Expression compilation.
*/
Tcl_Size length;
const char *string = TclGetStringFromObj(objPtr, &length);
TclInitCompileEnv(interp, &compEnv, string, length, NULL, 0);
TclCompileExpr(interp, string, length, &compEnv, 0);
/*
* Successful compilation. If the expression yielded no instructions,
* push an zero object as the expression's result.
*/
if (compEnv.codeNext == compEnv.codeStart) {
TclEmitPush(TclRegisterLiteral(&compEnv, "0", 1, 0),
&compEnv);
}
/*
* Add a "done" instruction as the last instruction and change the
* object into a ByteCode object. Ownership of the literal objects and
* aux data items is given to the ByteCode object.
*/
|
| ︙ | ︙ | |||
1605 1606 1607 1608 1609 1610 1611 |
*/
ByteCode *
TclCompileObj(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
const CmdFrame *invoker,
| | | 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 |
*/
ByteCode *
TclCompileObj(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
const CmdFrame *invoker,
int word)
{
Interp *iPtr = (Interp *) interp;
ByteCode *codePtr; /* Tcl Internal type of bytecode. */
Namespace *namespacePtr = iPtr->varFramePtr->nsPtr;
/*
* If the object is not already of tclByteCodeType, compile it (and reset
|
| ︙ | ︙ | |||
1891 1892 1893 1894 1895 1896 1897 |
Tcl_Size objc,
Tcl_Obj **objv)
{
Tcl_Size cmd;
if (GetSrcInfoForPc(pc, codePtr, NULL, NULL, &cmd)) {
TclArgumentBCEnter(interp, objv, objc, codePtr, &tdPtr->cmdFrame, cmd,
| < < < | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 |
Tcl_Size objc,
Tcl_Obj **objv)
{
Tcl_Size cmd;
if (GetSrcInfoForPc(pc, codePtr, NULL, NULL, &cmd)) {
TclArgumentBCEnter(interp, objv, objc, codePtr, &tdPtr->cmdFrame, cmd,
pc - codePtr->codeStart);
}
}
/*
*----------------------------------------------------------------------
*
* TclNRExecuteByteCode --
*
* This procedure executes the instructions of a ByteCode structure. It
* returns when a "done" instruction is executed or an error occurs.
*
* Results:
* The return value is one of the return codes defined in tcl.h (such as
* TCL_OK), and interp->objResultPtr refers to a Tcl object that either
* contains the result of executing the code or an error message.
*
* Side effects:
* Almost certainly, depending on the ByteCode's instructions.
*
*----------------------------------------------------------------------
*/
#define bcFramePtr (&TD->cmdFrame)
#define initCatchTop (TD->stack-1)
#define initTosPtr (initCatchTop+codePtr->maxExceptDepth)
#define esPtr (iPtr->execEnvPtr->execStackPtr)
int
TclNRExecuteByteCode(
Tcl_Interp *interp, /* Token for command interpreter. */
ByteCode *codePtr) /* The bytecode sequence to interpret. */
{
|
| ︙ | ︙ | |||
2013 2014 2015 2016 2017 2018 2019 |
TEBCdata *TD = (TEBCdata *) GrowEvaluationStack(iPtr->execEnvPtr, numWords, 0);
esPtr->tosPtr = initTosPtr;
TD->codePtr = codePtr;
TD->catchTop = initCatchTop;
TD->auxObjList = NULL;
| < < < | 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 |
TEBCdata *TD = (TEBCdata *) GrowEvaluationStack(iPtr->execEnvPtr, numWords, 0);
esPtr->tosPtr = initTosPtr;
TD->codePtr = codePtr;
TD->catchTop = initCatchTop;
TD->auxObjList = NULL;
/*
* TIP #280: Initialize the frame. Do not push it yet: it will be pushed
* every time that we call out from this TD, popped when we return to it.
*/
bcFramePtr->type = ((codePtr->flags & TCL_BYTECODE_PRECOMPILED)
|
| ︙ | ︙ | |||
2063 2064 2065 2066 2067 2068 2069 |
* and should not affect all the nested invocations may return result.
*/
iPtr->evalFlags &= ~TCL_EVAL_DISCARD_RESULT;
return TCL_OK;
}
| < < < < < < < < < < | 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
* and should not affect all the nested invocations may return result.
*/
iPtr->evalFlags &= ~TCL_EVAL_DISCARD_RESULT;
return TCL_OK;
}
static int
TEBCresume(
void *data[],
Tcl_Interp *interp,
int result)
{
/*
|
| ︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 |
#endif
Var *compiledLocals = iPtr->varFramePtr->compiledLocals;
Tcl_Obj **constants = &iPtr->execEnvPtr->constants[0];
#define LOCAL(i) (&compiledLocals[(i)])
#define TCONST(i) (constants[(i)])
| < < | | < | > > > | | | | 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 |
#endif
Var *compiledLocals = iPtr->varFramePtr->compiledLocals;
Tcl_Obj **constants = &iPtr->execEnvPtr->constants[0];
#define LOCAL(i) (&compiledLocals[(i)])
#define TCONST(i) (constants[(i)])
/*
* These macros are just meant to save some global variables that are not
* used too frequently
*/
TEBCdata *TD = (TEBCdata *)data[0];
#define auxObjList (TD->auxObjList)
#define catchTop (TD->catchTop)
#define codePtr (TD->codePtr)
#define curEvalFlags PTR2INT(data[3]) /* calling iPtr->evalFlags */
/*
* Globals: variables that store state, must remain valid at all times.
*/
Tcl_Obj **tosPtr; /* Cached pointer to top of evaluation
* stack. */
const unsigned char *pc = (const unsigned char *)data[1];
/* The current program counter. */
unsigned char inst; /* The currently running instruction */
/*
* Transfer variables - needed only between opcodes, but not while
* executing an instruction.
*/
int cleanup = PTR2INT(data[2]);
Tcl_Obj *objResultPtr;
int checkInterp = 0; /* Indicates when a check of interp readyness
* is necessary. Set by CACHE_STACK_INFO() */
/*
* Locals - variables that are used within opcodes or bounded sections of
* the file (jumps between opcodes within a family).
* NOTE: These are now mostly defined locally where needed.
*/
Tcl_Obj *objPtr, *valuePtr, *value2Ptr, *part1Ptr, *part2Ptr, *tmpPtr;
Tcl_Obj **objv = NULL;
Tcl_Size length, objc = 0;
int opnd, pcAdjustment;
Var *varPtr, *arrayPtr;
#ifdef TCL_COMPILE_DEBUG
char cmdNameBuf[21];
#endif
#ifdef TCL_COMPILE_DEBUG
int starting = 1;
traceInstructions = (tclTraceExec == 3);
#endif
TEBC_DATA_DIG();
#ifdef TCL_COMPILE_DEBUG
if (!pc && (tclTraceExec >= 2)) {
PrintByteCodeInfo(codePtr);
fprintf(stdout, " Starting stack top=%" TCL_SIZE_MODIFIER "d\n", CURR_DEPTH);
fflush(stdout);
}
#endif
if (!pc) {
/* bytecode is starting from scratch */
pc = codePtr->codeStart;
|
| ︙ | ︙ | |||
2237 2238 2239 2240 2241 2242 2243 | } /* * Push the call's object result and continue execution with the next * instruction. */ | | | < | 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 |
}
/*
* Push the call's object result and continue execution with the next
* instruction.
*/
TRACE_WITH_OBJ(("%" TCL_SIZE_MODIFIER "d => ... after \"%.20s\": TCL_OK, result=",
objc, cmdNameBuf), Tcl_GetObjResult(interp));
/*
* Obtain and reset interp's result to avoid possible duplications of
* objects [Bug 781585]. We do not call Tcl_ResetResult to avoid any
* side effects caused by the resetting of errorInfo and errorCode
* [Bug 804681], which are not needed here. We chose instead to
* manipulate the interp's object result directly.
|
| ︙ | ︙ | |||
2285 2286 2287 2288 2289 2290 2291 |
goto cleanup0;
default:
cleanup -= 2;
while (cleanup--) {
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
}
| | | | | | | 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 |
goto cleanup0;
default:
cleanup -= 2;
while (cleanup--) {
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
}
/* FALLTHRU */
case 2:
cleanup2_pushObjResultPtr:
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
/* FALLTHRU */
case 1:
cleanup1_pushObjResultPtr:
objPtr = OBJ_AT_TOS;
TclDecrRefCount(objPtr);
}
OBJ_AT_TOS = objResultPtr;
goto cleanup0;
cleanupV:
switch (cleanup) {
default:
cleanup -= 2;
while (cleanup--) {
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
}
/* FALLTHRU */
case 2:
cleanup2:
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
/* FALLTHRU */
case 1:
cleanup1:
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
/* FALLTHRU */
case 0:
/*
* We really want to do nothing now, but this is needed for some
* compilers (SunPro CC).
*/
break;
|
| ︙ | ︙ | |||
2383 2384 2385 2386 2387 2388 2389 |
#ifdef TCL_COMPILE_DEBUG
/*
* Skip the stack depth check if an expansion is in progress.
*/
CHECK_STACK();
if (traceInstructions) {
| | | | | < | | | | 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 |
#ifdef TCL_COMPILE_DEBUG
/*
* Skip the stack depth check if an expansion is in progress.
*/
CHECK_STACK();
if (traceInstructions) {
fprintf(stdout, "%2" TCL_SIZE_MODIFIER "d: %2" TCL_SIZE_MODIFIER "d ", iPtr->numLevels, CURR_DEPTH);
TclPrintInstruction(codePtr, pc);
fflush(stdout);
}
#endif /* TCL_COMPILE_DEBUG */
TCL_DTRACE_INST_NEXT();
if (inst == INST_LOAD_SCALAR1) {
goto instLoadScalar1;
} else if (inst == INST_PUSH1) {
PUSH_OBJECT(codePtr->objArrayPtr[TclGetUInt1AtPtr(pc + 1)]);
TRACE_WITH_OBJ(("%u => ", TclGetUInt1AtPtr(pc + 1)), OBJ_AT_TOS);
inst = *(pc += 2);
goto peepholeStart;
} else if (inst == INST_START_CMD) {
/*
* Peephole: do not run INST_START_CMD, just skip it
*/
iPtr->cmdCount += TclGetUInt4AtPtr(pc + 5);
|
| ︙ | ︙ | |||
2435 2436 2437 2438 2439 2440 2441 | int code = TclGetInt4AtPtr(pc + 1); int level = TclGetUInt4AtPtr(pc + 5); /* * OBJ_AT_TOS is returnOpts, OBJ_UNDER_TOS is resultObjPtr. */ | | | | | | | | | | | | | | | | > | | < | > | > < < < < < < < < < < < | < | | | > | < > | | 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 |
int code = TclGetInt4AtPtr(pc + 1);
int level = TclGetUInt4AtPtr(pc + 5);
/*
* OBJ_AT_TOS is returnOpts, OBJ_UNDER_TOS is resultObjPtr.
*/
TRACE(("%u %u => ", code, level));
result = TclProcessReturn(interp, code, level, OBJ_AT_TOS);
if (result == TCL_OK) {
TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")\n",
O2S(objResultPtr)));
NEXT_INST_F(9, 1, 0);
}
Tcl_SetObjResult(interp, OBJ_UNDER_TOS);
if (*pc == INST_SYNTAX) {
iPtr->flags &= ~ERR_ALREADY_LOGGED;
}
cleanup = 2;
TRACE_APPEND(("\n"));
goto processExceptionReturn;
}
case INST_RETURN_STK:
TRACE(("=> "));
objResultPtr = POP_OBJECT();
result = Tcl_SetReturnOptions(interp, OBJ_AT_TOS);
if (result == TCL_OK) {
Tcl_DecrRefCount(OBJ_AT_TOS);
OBJ_AT_TOS = objResultPtr;
TRACE_APPEND(("continuing to next instruction (result=\"%.30s\")\n",
O2S(objResultPtr)));
NEXT_INST_F(1, 0, 0);
} else if (result == TCL_ERROR) {
/*
* BEWARE! Must do this in this order, because an error in the
* option dictionary overrides the result (and can be verified by
* test).
*/
Tcl_SetObjResult(interp, objResultPtr);
Tcl_SetReturnOptions(interp, OBJ_AT_TOS);
Tcl_DecrRefCount(OBJ_AT_TOS);
OBJ_AT_TOS = objResultPtr;
} else {
Tcl_DecrRefCount(OBJ_AT_TOS);
OBJ_AT_TOS = objResultPtr;
Tcl_SetObjResult(interp, objResultPtr);
}
cleanup = 1;
TRACE_APPEND(("\n"));
goto processExceptionReturn;
{
CoroutineData *corPtr;
void *yieldParameter;
case INST_YIELD:
corPtr = iPtr->execEnvPtr->corPtr;
TRACE(("%.30s => ", O2S(OBJ_AT_TOS)));
if (!corPtr) {
TRACE_APPEND(("ERROR: yield outside coroutine\n"));
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"yield can only be called in a coroutine", -1));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD",
(char *)NULL);
CACHE_STACK_INFO();
goto gotError;
}
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 2) {
if (traceInstructions) {
TRACE_APPEND(("YIELD...\n"));
} else {
fprintf(stdout, "%" TCL_SIZE_MODIFIER "d: (%" TCL_T_MODIFIER "d) yielding value \"%.30s\"\n",
iPtr->numLevels, (pc - codePtr->codeStart),
Tcl_GetString(OBJ_AT_TOS));
}
fflush(stdout);
}
#endif
yieldParameter = NULL; /*==CORO_ACTIVATE_YIELD*/
Tcl_SetObjResult(interp, OBJ_AT_TOS);
goto doYield;
case INST_YIELD_TO_INVOKE:
corPtr = iPtr->execEnvPtr->corPtr;
valuePtr = OBJ_AT_TOS;
if (!corPtr) {
TRACE(("[%.30s] => ERROR: yield outside coroutine\n",
O2S(valuePtr)));
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"yieldto can only be called in a coroutine", -1));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "ILLEGAL_YIELD",
(char *)NULL);
CACHE_STACK_INFO();
goto gotError;
}
if (((Namespace *)TclGetCurrentNamespace(interp))->flags & NS_DYING) {
TRACE(("[%.30s] => ERROR: yield in deleted\n",
O2S(valuePtr)));
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"yieldto called in deleted namespace", -1));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "COROUTINE", "YIELDTO_IN_DELETED",
(char *)NULL);
CACHE_STACK_INFO();
goto gotError;
}
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 2) {
if (traceInstructions) {
TRACE(("[%.30s] => YIELD...\n", O2S(valuePtr)));
} else {
/* FIXME: What is the right thing to trace? */
fprintf(stdout, "%" TCL_SIZE_MODIFIER "d: (%" TCL_T_MODIFIER "d) yielding to [%.30s]\n",
iPtr->numLevels, (pc - codePtr->codeStart),
TclGetString(valuePtr));
}
fflush(stdout);
}
#endif
/*
* Install a tailcall record in the caller and continue with the
* yield. The yield is switched into multi-return mode (via the
* 'yieldParameter').
*/
iPtr->execEnvPtr = corPtr->callerEEPtr;
Tcl_IncrRefCount(valuePtr);
TclSetTailcall(interp, valuePtr);
corPtr->yieldPtr = valuePtr;
iPtr->execEnvPtr = corPtr->eePtr;
yieldParameter = INT2PTR(1); /*==CORO_ACTIVATE_YIELDM*/
doYield:
/* TIP #280: Record the last piece of info needed by
* 'TclGetSrcInfoForPc', and push the frame.
*/
bcFramePtr->data.tebc.pc = (char *) pc;
|
| ︙ | ︙ | |||
2597 2598 2599 2600 2601 2602 2603 |
cleanup = 1;
TEBC_YIELD();
TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
yieldParameter, NULL, NULL);
return TCL_OK;
}
| < > < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | > > | | < > > > | < < < < < < < < < > | | < > > > < < < < | < < | < | | < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | < < | < < < < < | < < > | < | > < | > | < | | > > > | < | | | | | < < < < < > | < | < > > | | > | | < | | | > | | > | | > > > > | | | | | | | < < | | | | < | | | > > > > | | 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 |
cleanup = 1;
TEBC_YIELD();
TclNRAddCallback(interp, TclNRCoroutineActivateCallback, corPtr,
yieldParameter, NULL, NULL);
return TCL_OK;
}
case INST_TAILCALL: {
Tcl_Obj *listPtr;
opnd = TclGetUInt1AtPtr(pc + 1);
if (!(iPtr->varFramePtr->isProcCallFrame & 1)) {
TRACE(("%d => ERROR: tailcall in non-proc context\n", opnd));
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"tailcall can only be called from a proc or lambda", -1));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "TAILCALL", "ILLEGAL", (char *)NULL);
CACHE_STACK_INFO();
goto gotError;
}
#ifdef TCL_COMPILE_DEBUG
/* FIXME: What is the right thing to trace? */
{
int i;
TRACE(("%d [", opnd));
for (i=opnd-1 ; i>=0 ; i--) {
TRACE_APPEND(("\"%.30s\"", O2S(OBJ_AT_DEPTH(i))));
if (i > 0) {
TRACE_APPEND((" "));
}
}
TRACE_APPEND(("] => RETURN..."));
}
#endif
/*
* Push the evaluation of the called command into the NR callback
* stack.
*/
listPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1));
TclListObjSetElement(NULL, listPtr, 0, TclNewNamespaceObj(
(Tcl_Namespace *) iPtr->varFramePtr->nsPtr));
if (iPtr->varFramePtr->tailcallPtr) {
Tcl_DecrRefCount(iPtr->varFramePtr->tailcallPtr);
}
iPtr->varFramePtr->tailcallPtr = listPtr;
result = TCL_RETURN;
cleanup = opnd;
goto processExceptionReturn;
}
case INST_DONE:
if (tosPtr > initTosPtr) {
if ((curEvalFlags & TCL_EVAL_DISCARD_RESULT) && (result == TCL_OK)) {
/* simulate pop & fast done (like it does continue in loop) */
TRACE_WITH_OBJ(("=> discarding "), OBJ_AT_TOS);
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
goto abnormalReturn;
}
/*
* Set the interpreter's object result to point to the topmost
* object from the stack, and check for a possible [catch]. The
* stackTop's level and refCount will be handled by "processCatch"
* or "abnormalReturn".
*/
Tcl_SetObjResult(interp, OBJ_AT_TOS);
#ifdef TCL_COMPILE_DEBUG
TRACE_WITH_OBJ(("=> return code=%d, result=", result),
iPtr->objResultPtr);
if (traceInstructions) {
fprintf(stdout, "\n");
}
#endif
goto checkForCatch;
}
(void) POP_OBJECT();
goto abnormalReturn;
case INST_PUSH4:
objResultPtr = codePtr->objArrayPtr[TclGetUInt4AtPtr(pc + 1)];
TRACE_WITH_OBJ(("%u => ", TclGetUInt4AtPtr(pc + 1)), objResultPtr);
NEXT_INST_F(5, 0, 1);
break;
case INST_POP:
TRACE_WITH_OBJ(("=> discarding "), OBJ_AT_TOS);
objPtr = POP_OBJECT();
TclDecrRefCount(objPtr);
NEXT_INST_F(1, 0, 0);
break;
case INST_DUP:
objResultPtr = OBJ_AT_TOS;
TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(1, 0, 1);
break;
case INST_OVER:
opnd = TclGetUInt4AtPtr(pc + 1);
objResultPtr = OBJ_AT_DEPTH(opnd);
TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
NEXT_INST_F(5, 0, 1);
break;
case INST_REVERSE: {
Tcl_Obj **a, **b;
opnd = TclGetUInt4AtPtr(pc + 1);
a = tosPtr - (opnd - 1);
b = tosPtr;
while (a < b) {
tmpPtr = *a;
*a = *b;
*b = tmpPtr;
a++;
b--;
}
TRACE(("%u => OK\n", opnd));
NEXT_INST_F(5, 0, 0);
}
break;
case INST_STR_CONCAT1:
opnd = TclGetUInt1AtPtr(pc + 1);
DECACHE_STACK_INFO();
objResultPtr = TclStringCat(interp, opnd, &OBJ_AT_DEPTH(opnd-1),
TCL_STRING_IN_PLACE);
if (objResultPtr == NULL) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
CACHE_STACK_INFO();
TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
NEXT_INST_V(2, opnd, 1);
break;
case INST_CONCAT_STK:
/*
* Pop the opnd (objc) top stack elements, run through Tcl_ConcatObj,
* and then decrement their ref counts.
*/
opnd = TclGetUInt4AtPtr(pc + 1);
objResultPtr = Tcl_ConcatObj(opnd, &OBJ_AT_DEPTH(opnd - 1));
TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
NEXT_INST_V(5, opnd, 1);
break;
case INST_EXPAND_START:
/*
* Push an element to the auxObjList. This records the current
* stack depth - i.e., the point in the stack where the expanded
* command starts.
*
* Use a Tcl_Obj as linked list element; slight mem waste, but faster
* allocation than Tcl_Alloc. This also abuses the Tcl_Obj structure, as
* we do not define a special tclObjType for it. It is not dangerous
* as the obj is never passed anywhere, so that all manipulations are
* performed here and in INST_INVOKE_EXPANDED (in case of an expansion
* error, also in INST_EXPAND_STKTOP).
*/
TclNewObj(objPtr);
objPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(CURR_DEPTH);
objPtr->length = 0;
PUSH_TAUX_OBJ(objPtr);
TRACE(("=> mark depth as %" TCL_SIZE_MODIFIER "d\n", CURR_DEPTH));
NEXT_INST_F(1, 0, 0);
break;
case INST_EXPAND_DROP:
/*
* Drops an element of the auxObjList, popping stack elements to
* restore the stack to the state before the point where the aux
* element was created.
*/
CLANG_ASSERT(auxObjList);
objc = CURR_DEPTH - PTR2INT(auxObjList->internalRep.twoPtrValue.ptr2);
POP_TAUX_OBJ();
#ifdef TCL_COMPILE_DEBUG
/* Ugly abuse! */
starting = 1;
#endif
TRACE(("=> drop %" TCL_SIZE_MODIFIER "d items\n", objc));
NEXT_INST_V(1, objc, 0);
case INST_EXPAND_STKTOP: {
Tcl_Size i;
TEBCdata *newTD;
Tcl_Size oldCatchTopOff, oldTosPtrOff;
/*
* Make sure that the element at stackTop is a list; if not, just
* leave with an error. Note that the element from the expand list
* will be removed at checkForCatch.
*/
objPtr = OBJ_AT_TOS;
TRACE(("\"%.30s\" => ", O2S(objPtr)));
if (TclListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
(void) POP_OBJECT();
/*
* Make sure there is enough room in the stack to expand this list
* *and* process the rest of the command (at least up to the next
* argument expansion or command end). The operand is the current
* stack depth, as seen by the compiler.
*/
auxObjList->length += objc - 1;
if ((objc > 1) && (auxObjList->length > 0)) {
length = auxObjList->length /* Total expansion room we need */
+ codePtr->maxStackDepth /* Beyond the original max */
- CURR_DEPTH; /* Relative to where we are */
DECACHE_STACK_INFO();
oldCatchTopOff = catchTop - initCatchTop;
oldTosPtrOff = tosPtr - initTosPtr;
newTD = (TEBCdata *)
GrowEvaluationStack(iPtr->execEnvPtr, length, 1);
if (newTD != TD) {
/*
* Change the global data to point to the new stack: move the
* TEBCdataPtr TD, recompute the position of every other
* stack-allocated parameter, update the stack pointers.
*/
TD = newTD;
catchTop = initCatchTop + oldCatchTopOff;
tosPtr = initTosPtr + oldTosPtrOff;
}
}
/*
* Expand the list at stacktop onto the stack; free the list. Knowing
* that it has a freeIntRepProc we use Tcl_DecrRefCount().
*/
for (i = 0; i < objc; i++) {
PUSH_OBJECT(objv[i]);
}
TRACE_APPEND(("OK\n"));
Tcl_DecrRefCount(objPtr);
NEXT_INST_F(5, 0, 0);
}
break;
case INST_EXPR_STK: {
ByteCode *newCodePtr;
bcFramePtr->data.tebc.pc = (char *) pc;
iPtr->cmdFramePtr = bcFramePtr;
DECACHE_STACK_INFO();
newCodePtr = CompileExprObj(interp, OBJ_AT_TOS);
CACHE_STACK_INFO();
cleanup = 1;
pc++;
TEBC_YIELD();
return TclNRExecuteByteCode(interp, newCodePtr);
}
|
| ︙ | ︙ | |||
3012 3013 3014 3015 3016 3017 3018 3019 |
/*
* Nothing was expanded, return {}.
*/
TclNewObj(objResultPtr);
NEXT_INST_F(1, 0, 1);
| > | < < < < | > > | > > > > > | < < | 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 |
/*
* Nothing was expanded, return {}.
*/
TclNewObj(objResultPtr);
NEXT_INST_F(1, 0, 1);
break;
case INST_INVOKE_STK4:
objc = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
goto doInvocation;
case INST_INVOKE_STK1:
objc = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
doInvocation:
objv = &OBJ_AT_DEPTH(objc - 1);
cleanup = objc;
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 2) {
Tcl_Size i;
if (traceInstructions) {
strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
TRACE(("%" TCL_SIZE_MODIFIER "d => call ", objc));
} else {
fprintf(stdout, "%" TCL_SIZE_MODIFIER "d: (%" TCL_T_MODIFIER "d) invoking ", iPtr->numLevels,
(pc - codePtr->codeStart));
}
for (i = 0; i < objc; i++) {
TclPrintObject(stdout, objv[i], 15);
fprintf(stdout, " ");
}
fprintf(stdout, "\n");
fflush(stdout);
}
#endif /*TCL_COMPILE_DEBUG*/
/*
* Finally, let TclEvalObjv handle the command.
|
| ︙ | ︙ | |||
3063 3064 3065 3066 3067 3068 3069 | ArgumentBCEnter(interp, codePtr, TD, pc, objc, objv); } DECACHE_STACK_INFO(); pc += pcAdjustment; TEBC_YIELD(); | > > > | > | | | > > | | > | < | | | | | 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 |
ArgumentBCEnter(interp, codePtr, TD, pc, objc, objv);
}
DECACHE_STACK_INFO();
pc += pcAdjustment;
TEBC_YIELD();
if (objc > INT_MAX) {
return TclCommandWordLimitError(interp, objc);
} else {
return TclNREvalObjv(interp, objc, objv,
TCL_EVAL_NOERR | TCL_EVAL_SOURCE_IN_FRAME, NULL);
}
case INST_INVOKE_REPLACE:
objc = TclGetUInt4AtPtr(pc + 1);
opnd = TclGetUInt1AtPtr(pc + 5);
objPtr = POP_OBJECT();
objv = &OBJ_AT_DEPTH(objc-1);
cleanup = objc;
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 2) {
Tcl_Size i;
if (traceInstructions) {
strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
TRACE(("%" TCL_SIZE_MODIFIER "u => call (implementation %s) ", objc, O2S(objPtr)));
} else {
fprintf(stdout,
"%" TCL_SIZE_MODIFIER "d: (%" TCL_T_MODIFIER "u) invoking (using implementation %s) ",
iPtr->numLevels, (pc - codePtr->codeStart),
O2S(objPtr));
}
for (i = 0; i < objc; i++) {
if (i < opnd) {
fprintf(stdout, "<");
TclPrintObject(stdout, objv[i], 15);
fprintf(stdout, ">");
} else {
TclPrintObject(stdout, objv[i], 15);
}
fprintf(stdout, " ");
}
fprintf(stdout, "\n");
fflush(stdout);
}
#endif /*TCL_COMPILE_DEBUG*/
bcFramePtr->data.tebc.pc = (char *) pc;
iPtr->cmdFramePtr = bcFramePtr;
if (iPtr->flags & INTERP_DEBUG_FRAME) {
ArgumentBCEnter(interp, codePtr, TD, pc, objc, objv);
}
TclInitRewriteEnsemble(interp, opnd, 1, objv);
{
Tcl_Obj *copyPtr = Tcl_NewListObj(objc - opnd + 1, NULL);
Tcl_ListObjAppendElement(NULL, copyPtr, objPtr);
Tcl_ListObjReplace(NULL, copyPtr, LIST_MAX, 0,
objc - opnd, objv + opnd);
Tcl_DecrRefCount(objPtr);
objPtr = copyPtr;
}
DECACHE_STACK_INFO();
pc += 6;
TEBC_YIELD();
|
| ︙ | ︙ | |||
3135 3136 3137 3138 3139 3140 3141 |
* Start of INST_LOAD instructions.
*
* WARNING: more 'goto' here than your doctor recommended! The different
* instructions set the value of some variables and then jump to some
* common execution code.
*/
| < < > | < | > > > > | < | < | < | > > > > | | | < < | < < | > > > > | | | < < < | | | | | < | < | | < | | | < < > | | > | > < | < | | < | | | < < < | > > > > | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 |
* Start of INST_LOAD instructions.
*
* WARNING: more 'goto' here than your doctor recommended! The different
* instructions set the value of some variables and then jump to some
* common execution code.
*/
case INST_LOAD_SCALAR1:
instLoadScalar1:
opnd = TclGetUInt1AtPtr(pc + 1);
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u => ", opnd));
if (TclIsVarDirectReadable(varPtr)) {
/*
* No errors, no traces: just get the value.
*/
objResultPtr = varPtr->value.objPtr;
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(2, 0, 1);
}
pcAdjustment = 2;
cleanup = 0;
arrayPtr = NULL;
part1Ptr = part2Ptr = NULL;
goto doCallPtrGetVar;
case INST_LOAD_SCALAR4:
opnd = TclGetUInt4AtPtr(pc + 1);
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u => ", opnd));
if (TclIsVarDirectReadable(varPtr)) {
/*
* No errors, no traces: just get the value.
*/
objResultPtr = varPtr->value.objPtr;
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(5, 0, 1);
}
pcAdjustment = 5;
cleanup = 0;
arrayPtr = NULL;
part1Ptr = part2Ptr = NULL;
goto doCallPtrGetVar;
case INST_LOAD_ARRAY4:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
goto doLoadArray;
case INST_LOAD_ARRAY1:
opnd = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
doLoadArray:
part1Ptr = NULL;
part2Ptr = OBJ_AT_TOS;
arrayPtr = LOCAL(opnd);
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
if (varPtr && TclIsVarDirectReadable(varPtr)) {
/*
* No errors, no traces: just get the value.
*/
objResultPtr = varPtr->value.objPtr;
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(pcAdjustment, 1, 1);
}
}
varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
TCL_LEAVE_ERR_MSG, "read", 0, 1, arrayPtr, opnd);
if (varPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
cleanup = 1;
goto doCallPtrGetVar;
case INST_LOAD_ARRAY_STK:
cleanup = 2;
part2Ptr = OBJ_AT_TOS; /* element name */
objPtr = OBJ_UNDER_TOS; /* array name */
TRACE(("\"%.30s(%.30s)\" => ", O2S(objPtr), O2S(part2Ptr)));
goto doLoadStk;
case INST_LOAD_STK:
case INST_LOAD_SCALAR_STK:
cleanup = 1;
part2Ptr = NULL;
objPtr = OBJ_AT_TOS; /* variable name */
TRACE(("\"%.30s\" => ", O2S(objPtr)));
doLoadStk:
part1Ptr = objPtr;
varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr,
TCL_LEAVE_ERR_MSG, "read", /*createPart1*/0, /*createPart2*/1,
&arrayPtr);
if (!varPtr) {
TRACE_ERROR(interp);
goto gotError;
}
if (TclIsVarDirectReadable2(varPtr, arrayPtr)) {
/*
* No errors, no traces: just get the value.
*/
objResultPtr = varPtr->value.objPtr;
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(1, cleanup, 1);
}
pcAdjustment = 1;
opnd = -1;
doCallPtrGetVar:
/*
* There are either errors or the variable is traced: call
* TclPtrGetVar to process fully.
*/
DECACHE_STACK_INFO();
objResultPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr,
part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (!objResultPtr) {
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(pcAdjustment, cleanup, 1);
/*
* End of INST_LOAD instructions.
* -----------------------------------------------------------------
* Start of INST_STORE and related instructions.
*
* WARNING: more 'goto' here than your doctor recommended! The different
* instructions set the value of some variables and then jump to somme
* common execution code.
*/
{
int storeFlags;
Tcl_Size len;
case INST_STORE_ARRAY4:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
goto doStoreArrayDirect;
case INST_STORE_ARRAY1:
opnd = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
doStoreArrayDirect:
valuePtr = OBJ_AT_TOS;
part2Ptr = OBJ_UNDER_TOS;
arrayPtr = LOCAL(opnd);
TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
O2S(valuePtr)));
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
if (TclIsVarArray(arrayPtr) && !WriteTraced(arrayPtr)) {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
if (varPtr && TclIsVarDirectWritable(varPtr)) {
tosPtr--;
Tcl_DecrRefCount(OBJ_AT_TOS);
OBJ_AT_TOS = valuePtr;
goto doStoreVarDirect;
}
}
cleanup = 2;
storeFlags = TCL_LEAVE_ERR_MSG;
part1Ptr = NULL;
goto doStoreArrayDirectFailed;
case INST_STORE_SCALAR4:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
goto doStoreScalarDirect;
case INST_STORE_SCALAR1:
opnd = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
doStoreScalarDirect:
valuePtr = OBJ_AT_TOS;
varPtr = LOCAL(opnd);
TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
if (!TclIsVarDirectWritable(varPtr)) {
storeFlags = TCL_LEAVE_ERR_MSG;
part1Ptr = NULL;
goto doStoreScalar;
}
/*
|
| ︙ | ︙ | |||
3359 3360 3361 3362 3363 3364 3365 |
TclDecrRefCount(valuePtr);
}
objResultPtr = OBJ_AT_TOS;
varPtr->value.objPtr = objResultPtr;
#ifndef TCL_COMPILE_DEBUG
if (pc[pcAdjustment] == INST_POP) {
tosPtr--;
| | | | | 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 |
TclDecrRefCount(valuePtr);
}
objResultPtr = OBJ_AT_TOS;
varPtr->value.objPtr = objResultPtr;
#ifndef TCL_COMPILE_DEBUG
if (pc[pcAdjustment] == INST_POP) {
tosPtr--;
NEXT_INST_F((pcAdjustment + 1), 0, 0);
}
#else
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
#endif
Tcl_IncrRefCount(objResultPtr);
NEXT_INST_F(pcAdjustment, 0, 0);
case INST_LAPPEND_STK:
valuePtr = OBJ_AT_TOS; /* value to append */
part2Ptr = NULL;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
| TCL_LIST_ELEMENT);
goto doStoreStk;
|
| ︙ | ︙ | |||
3400 3401 3402 3403 3404 3405 3406 |
case INST_STORE_ARRAY_STK:
valuePtr = OBJ_AT_TOS;
part2Ptr = OBJ_UNDER_TOS;
storeFlags = TCL_LEAVE_ERR_MSG;
goto doStoreStk;
case INST_STORE_STK:
| < < < | | | | | | < < | < | | < < | < > | | > | > | | | < < | < | | < < | < < | > > > > | | | | < | > > > > | | < < | > > > > > | | | | | | | | > | 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 |
case INST_STORE_ARRAY_STK:
valuePtr = OBJ_AT_TOS;
part2Ptr = OBJ_UNDER_TOS;
storeFlags = TCL_LEAVE_ERR_MSG;
goto doStoreStk;
case INST_STORE_STK:
case INST_STORE_SCALAR_STK:
valuePtr = OBJ_AT_TOS;
part2Ptr = NULL;
storeFlags = TCL_LEAVE_ERR_MSG;
doStoreStk:
objPtr = OBJ_AT_DEPTH(1 + (part2Ptr != NULL)); /* variable name */
part1Ptr = objPtr;
#ifdef TCL_COMPILE_DEBUG
if (part2Ptr == NULL) {
TRACE(("\"%.30s\" <- \"%.30s\" =>", O2S(part1Ptr),O2S(valuePtr)));
} else {
TRACE(("\"%.30s(%.30s)\" <- \"%.30s\" => ",
O2S(part1Ptr), O2S(part2Ptr), O2S(valuePtr)));
}
#endif
varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr, TCL_LEAVE_ERR_MSG,
"set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
if (!varPtr) {
TRACE_ERROR(interp);
goto gotError;
}
cleanup = ((part2Ptr == NULL)? 2 : 3);
pcAdjustment = 1;
opnd = -1;
goto doCallPtrSetVar;
case INST_LAPPEND_ARRAY4:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
| TCL_LIST_ELEMENT);
goto doStoreArray;
case INST_LAPPEND_ARRAY1:
opnd = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
| TCL_LIST_ELEMENT);
goto doStoreArray;
case INST_APPEND_ARRAY4:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreArray;
case INST_APPEND_ARRAY1:
opnd = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreArray;
doStoreArray:
valuePtr = OBJ_AT_TOS;
part2Ptr = OBJ_UNDER_TOS;
arrayPtr = LOCAL(opnd);
TRACE(("%u \"%.30s\" <- \"%.30s\" => ", opnd, O2S(part2Ptr),
O2S(valuePtr)));
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
cleanup = 2;
part1Ptr = NULL;
doStoreArrayDirectFailed:
varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr, opnd);
if (!varPtr) {
TRACE_ERROR(interp);
goto gotError;
}
goto doCallPtrSetVar;
case INST_LAPPEND_SCALAR4:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
| TCL_LIST_ELEMENT);
goto doStoreScalar;
case INST_LAPPEND_SCALAR1:
opnd = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE
| TCL_LIST_ELEMENT);
goto doStoreScalar;
case INST_APPEND_SCALAR4:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreScalar;
case INST_APPEND_SCALAR1:
opnd = TclGetUInt1AtPtr(pc + 1);
pcAdjustment = 2;
storeFlags = (TCL_LEAVE_ERR_MSG | TCL_APPEND_VALUE);
goto doStoreScalar;
doStoreScalar:
valuePtr = OBJ_AT_TOS;
varPtr = LOCAL(opnd);
TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
cleanup = 1;
arrayPtr = NULL;
part1Ptr = part2Ptr = NULL;
doCallPtrSetVar:
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVarIdx(interp, varPtr, arrayPtr,
part1Ptr, part2Ptr, valuePtr, storeFlags, opnd);
CACHE_STACK_INFO();
if (!objResultPtr) {
TRACE_ERROR(interp);
goto gotError;
}
#ifndef TCL_COMPILE_DEBUG
if (pc[pcAdjustment] == INST_POP) {
NEXT_INST_V((pcAdjustment + 1), cleanup, 0);
}
#endif
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(pcAdjustment, cleanup, 1);
case INST_LAPPEND_LIST:
opnd = TclGetUInt4AtPtr(pc + 1);
valuePtr = OBJ_AT_TOS;
varPtr = LOCAL(opnd);
cleanup = 1;
pcAdjustment = 5;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u <- \"%.30s\" => ", opnd, O2S(valuePtr)));
if (TclListObjGetElements(interp, valuePtr, &objc, &objv)
!= TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
if (TclIsVarDirectReadable(varPtr)
&& TclIsVarDirectWritable(varPtr)) {
goto lappendListDirect;
}
arrayPtr = NULL;
part1Ptr = part2Ptr = NULL;
goto lappendListPtr;
case INST_LAPPEND_LIST_ARRAY:
opnd = TclGetUInt4AtPtr(pc + 1);
valuePtr = OBJ_AT_TOS;
part1Ptr = NULL;
part2Ptr = OBJ_UNDER_TOS;
arrayPtr = LOCAL(opnd);
cleanup = 2;
pcAdjustment = 5;
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
TRACE(("%u \"%.30s\" \"%.30s\" => ",
opnd, O2S(part2Ptr), O2S(valuePtr)));
if (TclListObjGetElements(interp, valuePtr, &objc, &objv)
!= TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)
&& !WriteTraced(arrayPtr)) {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
if (varPtr && TclIsVarDirectReadable(varPtr)
&& TclIsVarDirectWritable(varPtr)) {
goto lappendListDirect;
}
}
varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
TCL_LEAVE_ERR_MSG, "set", 1, 1, arrayPtr, opnd);
if (varPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
goto lappendListPtr;
case INST_LAPPEND_LIST_ARRAY_STK:
pcAdjustment = 1;
cleanup = 3;
valuePtr = OBJ_AT_TOS;
part2Ptr = OBJ_UNDER_TOS; /* element name */
part1Ptr = OBJ_AT_DEPTH(2); /* array name */
TRACE(("\"%.30s(%.30s)\" \"%.30s\" => ",
O2S(part1Ptr), O2S(part2Ptr), O2S(valuePtr)));
goto lappendList;
case INST_LAPPEND_LIST_STK:
pcAdjustment = 1;
cleanup = 2;
valuePtr = OBJ_AT_TOS;
part2Ptr = NULL;
part1Ptr = OBJ_UNDER_TOS; /* variable name */
TRACE(("\"%.30s\" \"%.30s\" => ", O2S(part1Ptr), O2S(valuePtr)));
goto lappendList;
lappendListDirect:
objResultPtr = varPtr->value.objPtr;
if (TclListObjLength(interp, objResultPtr, &len) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
if (Tcl_IsShared(objResultPtr)) {
Tcl_Obj *newValue = Tcl_DuplicateObj(objResultPtr);
TclDecrRefCount(objResultPtr);
varPtr->value.objPtr = objResultPtr = newValue;
Tcl_IncrRefCount(newValue);
}
if (TclListObjAppendElements(interp, objResultPtr, objc, objv)
!= TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(pcAdjustment, cleanup, 1);
lappendList:
opnd = -1;
if (TclListObjGetElements(interp, valuePtr, &objc, &objv)
!= TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
DECACHE_STACK_INFO();
varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr,
TCL_LEAVE_ERR_MSG, "set", 1, 1, &arrayPtr);
CACHE_STACK_INFO();
|
| ︙ | ︙ | |||
3652 3653 3654 3655 3656 3657 3658 |
VarHashRefCount(varPtr)++;
}
if (arrayPtr && TclIsVarInHash(arrayPtr)) {
VarHashRefCount(arrayPtr)++;
}
DECACHE_STACK_INFO();
objResultPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr,
| | > < < < < < < < | < > | < < > | > | > | < < | | > > | > | < < < < < | < < < < < < < < < < < < < < < < < < < | | | | < < | < < < < < < < < < < < | > > > > | < < | < < < < < < < < < | > > > < > > | 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 |
VarHashRefCount(varPtr)++;
}
if (arrayPtr && TclIsVarInHash(arrayPtr)) {
VarHashRefCount(arrayPtr)++;
}
DECACHE_STACK_INFO();
objResultPtr = TclPtrGetVarIdx(interp, varPtr, arrayPtr,
part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (TclIsVarInHash(varPtr)) {
VarHashRefCount(varPtr)--;
}
if (arrayPtr && TclIsVarInHash(arrayPtr)) {
VarHashRefCount(arrayPtr)--;
}
{
int createdNewObj = 0;
Tcl_Obj *valueToAssign;
if (!objResultPtr) {
valueToAssign = valuePtr;
} else if (TclListObjLength(interp, objResultPtr, &len)!=TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
} else {
if (Tcl_IsShared(objResultPtr)) {
valueToAssign = Tcl_DuplicateObj(objResultPtr);
createdNewObj = 1;
} else {
valueToAssign = objResultPtr;
}
if (TclListObjAppendElements(interp, valueToAssign,
objc, objv) != TCL_OK) {
if (createdNewObj) {
TclDecrRefCount(valueToAssign);
}
goto errorInLappendListPtr;
}
}
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVarIdx(interp, varPtr, arrayPtr, part1Ptr,
part2Ptr, valueToAssign, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (!objResultPtr) {
errorInLappendListPtr:
TRACE_ERROR(interp);
goto gotError;
}
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(pcAdjustment, cleanup, 1);
}
/*
* End of INST_STORE and related instructions.
* -----------------------------------------------------------------
* Start of INST_INCR instructions.
*
* WARNING: more 'goto' here than your doctor recommended! The different
* instructions set the value of some variables and then jump to some
* common execution code.
*/
/*TODO: Consider more untangling here; merge with LOAD and STORE ? */
{
Tcl_Obj *incrPtr;
Tcl_WideInt w;
long increment;
case INST_INCR_SCALAR1:
case INST_INCR_ARRAY1:
case INST_INCR_ARRAY_STK:
case INST_INCR_SCALAR_STK:
case INST_INCR_STK:
opnd = TclGetUInt1AtPtr(pc + 1);
incrPtr = POP_OBJECT();
switch (*pc) {
case INST_INCR_SCALAR1:
pcAdjustment = 2;
goto doIncrScalar;
case INST_INCR_ARRAY1:
pcAdjustment = 2;
goto doIncrArray;
default:
pcAdjustment = 1;
goto doIncrStk;
}
case INST_INCR_ARRAY_STK_IMM:
case INST_INCR_SCALAR_STK_IMM:
case INST_INCR_STK_IMM:
increment = TclGetInt1AtPtr(pc + 1);
TclNewIntObj(incrPtr, increment);
Tcl_IncrRefCount(incrPtr);
pcAdjustment = 2;
doIncrStk:
if ((*pc == INST_INCR_ARRAY_STK_IMM)
|| (*pc == INST_INCR_ARRAY_STK)) {
part2Ptr = OBJ_AT_TOS;
objPtr = OBJ_UNDER_TOS;
TRACE(("\"%.30s(%.30s)\" (by %ld) => ",
O2S(objPtr), O2S(part2Ptr), increment));
} else {
part2Ptr = NULL;
objPtr = OBJ_AT_TOS;
TRACE(("\"%.30s\" (by %ld) => ", O2S(objPtr), increment));
}
part1Ptr = objPtr;
opnd = -1;
varPtr = TclObjLookupVarEx(interp, objPtr, part2Ptr,
TCL_LEAVE_ERR_MSG, "read", 1, 1, &arrayPtr);
if (!varPtr) {
DECACHE_STACK_INFO();
Tcl_AddErrorInfo(interp,
"\n (reading value of variable to increment)");
CACHE_STACK_INFO();
TRACE_ERROR(interp);
Tcl_DecrRefCount(incrPtr);
goto gotError;
}
cleanup = ((part2Ptr == NULL)? 1 : 2);
goto doIncrVar;
case INST_INCR_ARRAY1_IMM:
opnd = TclGetUInt1AtPtr(pc + 1);
increment = TclGetInt1AtPtr(pc + 2);
TclNewIntObj(incrPtr, increment);
Tcl_IncrRefCount(incrPtr);
pcAdjustment = 3;
doIncrArray:
part1Ptr = NULL;
part2Ptr = OBJ_AT_TOS;
arrayPtr = LOCAL(opnd);
cleanup = 1;
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
TRACE(("%u \"%.30s\" (by %ld) => ", opnd, O2S(part2Ptr), increment));
varPtr = TclLookupArrayElement(interp, part1Ptr, part2Ptr,
TCL_LEAVE_ERR_MSG, "read", 1, 1, arrayPtr, opnd);
if (!varPtr) {
TRACE_ERROR(interp);
Tcl_DecrRefCount(incrPtr);
goto gotError;
}
goto doIncrVar;
case INST_INCR_SCALAR1_IMM:
opnd = TclGetUInt1AtPtr(pc + 1);
increment = TclGetInt1AtPtr(pc + 2);
pcAdjustment = 3;
cleanup = 0;
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
if (TclIsVarDirectModifyable(varPtr)) {
void *ptr;
int type;
objPtr = varPtr->value.objPtr;
if (GetNumberFromObj(NULL, objPtr, &ptr, &type) == TCL_OK) {
if (type == TCL_NUMBER_INT) {
Tcl_WideInt augend = *((const Tcl_WideInt *)ptr);
Tcl_WideInt sum = (Tcl_WideInt)((Tcl_WideUInt)augend + (Tcl_WideUInt)increment);
/*
* Overflow when (augend and sum have different sign) and
* (augend and increment have the same sign). This is
* encapsulated in the Overflowing macro.
*/
if (!Overflowing(augend, increment, sum)) {
TRACE(("%u %ld => ", opnd, increment));
if (Tcl_IsShared(objPtr)) {
objPtr->refCount--; /* We know it's shared. */
TclNewIntObj(objResultPtr, sum);
Tcl_IncrRefCount(objResultPtr);
varPtr->value.objPtr = objResultPtr;
} else {
objResultPtr = objPtr;
TclSetIntObj(objPtr, sum);
}
goto doneIncr;
}
w = (Tcl_WideInt)augend;
TRACE(("%u %ld => ", opnd, increment));
if (Tcl_IsShared(objPtr)) {
objPtr->refCount--; /* We know it's shared. */
TclNewIntObj(objResultPtr, w + increment);
Tcl_IncrRefCount(objResultPtr);
varPtr->value.objPtr = objResultPtr;
} else {
objResultPtr = objPtr;
|
| ︙ | ︙ | |||
3926 3927 3928 3929 3930 3931 3932 |
* All other cases, flow through to generic handling.
*/
TclNewIntObj(incrPtr, increment);
Tcl_IncrRefCount(incrPtr);
doIncrScalar:
| < | > > > > | 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 |
* All other cases, flow through to generic handling.
*/
TclNewIntObj(incrPtr, increment);
Tcl_IncrRefCount(incrPtr);
doIncrScalar:
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
arrayPtr = NULL;
part1Ptr = part2Ptr = NULL;
cleanup = 0;
TRACE(("%u %s => ", opnd, TclGetString(incrPtr)));
doIncrVar:
if (TclIsVarDirectModifyable2(varPtr, arrayPtr)) {
objPtr = varPtr->value.objPtr;
if (Tcl_IsShared(objPtr)) {
objPtr->refCount--; /* We know it's shared */
objResultPtr = Tcl_DuplicateObj(objPtr);
|
| ︙ | ︙ | |||
3952 3953 3954 3955 3956 3957 3958 |
TRACE_ERROR(interp);
goto gotError;
}
Tcl_DecrRefCount(incrPtr);
} else {
DECACHE_STACK_INFO();
objResultPtr = TclPtrIncrObjVarIdx(interp, varPtr, arrayPtr,
| | | | | < | > > > > | | < | > > > > | | | | | 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 |
TRACE_ERROR(interp);
goto gotError;
}
Tcl_DecrRefCount(incrPtr);
} else {
DECACHE_STACK_INFO();
objResultPtr = TclPtrIncrObjVarIdx(interp, varPtr, arrayPtr,
part1Ptr, part2Ptr, incrPtr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
Tcl_DecrRefCount(incrPtr);
if (objResultPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
}
doneIncr:
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
#ifndef TCL_COMPILE_DEBUG
if (pc[pcAdjustment] == INST_POP) {
NEXT_INST_V((pcAdjustment + 1), cleanup, 0);
}
#endif
NEXT_INST_V(pcAdjustment, cleanup, 1);
}
/*
* End of INST_INCR instructions.
* -----------------------------------------------------------------
* Start of INST_EXIST instructions.
*/
case INST_EXIST_SCALAR:
cleanup = 0;
pcAdjustment = 5;
opnd = TclGetUInt4AtPtr(pc + 1);
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u => ", opnd));
if (ReadTraced(varPtr)) {
DECACHE_STACK_INFO();
TclObjCallVarTraces(iPtr, NULL, varPtr, NULL, NULL,
TCL_TRACE_READS, 0, opnd);
CACHE_STACK_INFO();
if (TclIsVarUndefined(varPtr)) {
TclCleanupVar(varPtr, NULL);
varPtr = NULL;
}
}
goto afterExistsPeephole;
case INST_EXIST_ARRAY:
cleanup = 1;
pcAdjustment = 5;
opnd = TclGetUInt4AtPtr(pc + 1);
part2Ptr = OBJ_AT_TOS;
arrayPtr = LOCAL(opnd);
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
TRACE(("%u \"%.30s\" => ", opnd, O2S(part2Ptr)));
if (TclIsVarArray(arrayPtr) && !ReadTraced(arrayPtr)) {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
if (!varPtr || !ReadTraced(varPtr)) {
goto afterExistsPeephole;
}
}
varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, 0, "access",
0, 1, arrayPtr, opnd);
if (varPtr) {
if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
DECACHE_STACK_INFO();
TclObjCallVarTraces(iPtr, arrayPtr, varPtr, NULL, part2Ptr,
TCL_TRACE_READS, 0, opnd);
CACHE_STACK_INFO();
}
if (TclIsVarUndefined(varPtr)) {
TclCleanupVar(varPtr, arrayPtr);
varPtr = NULL;
}
}
goto afterExistsPeephole;
case INST_EXIST_ARRAY_STK:
cleanup = 2;
pcAdjustment = 1;
part2Ptr = OBJ_AT_TOS; /* element name */
part1Ptr = OBJ_UNDER_TOS; /* array name */
TRACE(("\"%.30s(%.30s)\" => ", O2S(part1Ptr), O2S(part2Ptr)));
goto doExistStk;
case INST_EXIST_STK:
cleanup = 1;
pcAdjustment = 1;
part2Ptr = NULL;
part1Ptr = OBJ_AT_TOS; /* variable name */
TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
doExistStk:
varPtr = TclObjLookupVarEx(interp, part1Ptr, part2Ptr, 0, "access",
/*createPart1*/0, /*createPart2*/1, &arrayPtr);
if (varPtr) {
if (ReadTraced(varPtr) || (arrayPtr && ReadTraced(arrayPtr))) {
DECACHE_STACK_INFO();
|
| ︙ | ︙ | |||
4061 4062 4063 4064 4065 4066 4067 |
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
*/
afterExistsPeephole: {
int found = (varPtr && !TclIsVarUndefined(varPtr));
| | | < | > > > > | | | | | > > > > | | < | | | | | | < | | | | | | > | | | > > > | | | | | | | < < | | | > > > | | | | | | | > > > | | | | | | | | 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 |
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
*/
afterExistsPeephole: {
int found = (varPtr && !TclIsVarUndefined(varPtr));
TRACE_APPEND(("%d\n", found ? 1 : 0));
JUMP_PEEPHOLE_V(found, pcAdjustment, cleanup);
}
/*
* End of INST_EXIST instructions.
* -----------------------------------------------------------------
* Start of INST_UNSET instructions.
*/
{
int flags;
case INST_UNSET_SCALAR:
flags = TclGetUInt1AtPtr(pc + 1) ? TCL_LEAVE_ERR_MSG : 0;
opnd = TclGetUInt4AtPtr(pc + 2);
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%s %u => ", (flags ? "normal" : "noerr"), opnd));
if (TclIsVarDirectUnsettable(varPtr) && !TclIsVarInHash(varPtr)) {
/*
* No errors, no traces, no searches: just make the variable cease
* to exist.
*/
if (!TclIsVarUndefined(varPtr)) {
TclDecrRefCount(varPtr->value.objPtr);
} else if (flags & TCL_LEAVE_ERR_MSG) {
goto slowUnsetScalar;
}
varPtr->value.objPtr = NULL;
TRACE_APPEND(("OK\n"));
NEXT_INST_F(6, 0, 0);
}
slowUnsetScalar:
DECACHE_STACK_INFO();
if (TclPtrUnsetVarIdx(interp, varPtr, NULL, NULL, NULL, flags,
opnd) != TCL_OK && flags) {
goto errorInUnset;
}
CACHE_STACK_INFO();
NEXT_INST_F(6, 0, 0);
case INST_UNSET_ARRAY:
flags = TclGetUInt1AtPtr(pc + 1) ? TCL_LEAVE_ERR_MSG : 0;
opnd = TclGetUInt4AtPtr(pc + 2);
part2Ptr = OBJ_AT_TOS;
arrayPtr = LOCAL(opnd);
while (TclIsVarLink(arrayPtr)) {
arrayPtr = arrayPtr->value.linkPtr;
}
TRACE(("%s %u \"%.30s\" => ",
(flags ? "normal" : "noerr"), opnd, O2S(part2Ptr)));
if (TclIsVarArray(arrayPtr) && !UnsetTraced(arrayPtr)
&& !(arrayPtr->flags & VAR_SEARCH_ACTIVE)) {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, part2Ptr);
if (varPtr && TclIsVarDirectUnsettable(varPtr)) {
/*
* No nasty traces and element exists, so we can proceed to
* unset it. Might still not exist though...
*/
if (!TclIsVarUndefined(varPtr)) {
TclDecrRefCount(varPtr->value.objPtr);
TclSetVarUndefined(varPtr);
TclClearVarNamespaceVar(varPtr);
TclCleanupVar(varPtr, arrayPtr);
} else if (flags & TCL_LEAVE_ERR_MSG) {
goto slowUnsetArray;
}
TRACE_APPEND(("OK\n"));
NEXT_INST_F(6, 1, 0);
} else if (!varPtr && !(flags & TCL_LEAVE_ERR_MSG)) {
/*
* Don't need to do anything here.
*/
TRACE_APPEND(("OK\n"));
NEXT_INST_F(6, 1, 0);
}
}
slowUnsetArray:
DECACHE_STACK_INFO();
varPtr = TclLookupArrayElement(interp, NULL, part2Ptr, flags, "unset",
0, 0, arrayPtr, opnd);
if (!varPtr) {
if (flags & TCL_LEAVE_ERR_MSG) {
goto errorInUnset;
}
} else if (TclPtrUnsetVarIdx(interp, varPtr, arrayPtr, NULL, part2Ptr,
flags, opnd) != TCL_OK && (flags & TCL_LEAVE_ERR_MSG)) {
goto errorInUnset;
}
CACHE_STACK_INFO();
NEXT_INST_F(6, 1, 0);
case INST_UNSET_ARRAY_STK:
flags = TclGetUInt1AtPtr(pc + 1) ? TCL_LEAVE_ERR_MSG : 0;
cleanup = 2;
part2Ptr = OBJ_AT_TOS; /* element name */
part1Ptr = OBJ_UNDER_TOS; /* array name */
TRACE(("%s \"%.30s(%.30s)\" => ", (flags ? "normal" : "noerr"),
O2S(part1Ptr), O2S(part2Ptr)));
goto doUnsetStk;
case INST_UNSET_STK:
flags = TclGetUInt1AtPtr(pc + 1) ? TCL_LEAVE_ERR_MSG : 0;
cleanup = 1;
part2Ptr = NULL;
part1Ptr = OBJ_AT_TOS; /* variable name */
TRACE(("%s \"%.30s\" => ", (flags ? "normal" : "noerr"),
O2S(part1Ptr)));
doUnsetStk:
DECACHE_STACK_INFO();
if (TclObjUnsetVar2(interp, part1Ptr, part2Ptr, flags) != TCL_OK
&& (flags & TCL_LEAVE_ERR_MSG)) {
goto errorInUnset;
}
CACHE_STACK_INFO();
TRACE_APPEND(("OK\n"));
NEXT_INST_V(2, cleanup, 0);
errorInUnset:
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
break;
/*
* End of INST_UNSET instructions.
* -----------------------------------------------------------------
* Start of INST_CONST instructions.
*/
{
const char *msgPart;
case INST_CONST_IMM:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
cleanup = 1;
part1Ptr = NULL;
objPtr = OBJ_AT_TOS;
TRACE(("%u \"%.30s\" => \n", opnd, O2S(objPtr)));
varPtr = LOCAL(opnd);
arrayPtr = NULL;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
goto doConst;
case INST_CONST_STK:
opnd = -1;
pcAdjustment = 1;
cleanup = 2;
part1Ptr = OBJ_UNDER_TOS;
objPtr = OBJ_AT_TOS;
TRACE(("\"%.30s\" \"%.30s\" => ", O2S(part1Ptr), O2S(objPtr)));
varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, TCL_LEAVE_ERR_MSG, "const",
/*createPart1*/1, /*createPart2*/0, &arrayPtr);
doConst:
if (varPtr == NULL) {
if (Tcl_GetCharLength(Tcl_GetObjResult(interp)) == 0) {
Tcl_SetResult(interp, "variable not found", TCL_STATIC);
}
TRACE_ERROR(interp);
goto gotError;
}
if (TclIsVarConstant(varPtr)) {
TRACE_APPEND(("\n"));
NEXT_INST_V(pcAdjustment, cleanup, 0);
}
if (TclIsVarArray(varPtr)) {
msgPart = "variable is array";
goto constError;
} else if (TclIsVarArrayElement(varPtr)) {
msgPart = "name refers to an element in an array";
goto constError;
} else if (!TclIsVarUndefined(varPtr)) {
msgPart = "variable already exists";
goto constError;
}
if (TclIsVarDirectModifyable(varPtr)) {
varPtr->value.objPtr = objPtr;
Tcl_IncrRefCount(objPtr);
} else {
DECACHE_STACK_INFO();
Tcl_Obj *resPtr = TclPtrSetVarIdx(interp, varPtr, arrayPtr,
part1Ptr, NULL, objPtr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (resPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
}
TclSetVarConstant(varPtr);
TRACE_APPEND(("\n"));
NEXT_INST_V(pcAdjustment, cleanup, 0);
constError:
TclObjVarErrMsg(interp, part1Ptr, NULL, "make constant", msgPart, opnd);
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CONST", (char *)NULL);
TRACE_ERROR(interp);
goto gotError;
}
/*
* End of INST_CONST instructions.
* -----------------------------------------------------------------
* Start of INST_ARRAY instructions.
*/
case INST_ARRAY_EXISTS_IMM:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
cleanup = 0;
part1Ptr = NULL;
arrayPtr = NULL;
TRACE(("%u => ", opnd));
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
goto doArrayExists;
case INST_ARRAY_EXISTS_STK:
opnd = -1;
pcAdjustment = 1;
cleanup = 1;
part1Ptr = OBJ_AT_TOS;
TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, 0, NULL,
/*createPart1*/0, /*createPart2*/0, &arrayPtr);
doArrayExists:
DECACHE_STACK_INFO();
result = TclCheckArrayTraces(interp, varPtr, arrayPtr, part1Ptr, opnd);
CACHE_STACK_INFO();
if (result == TCL_ERROR) {
TRACE_ERROR(interp);
goto gotError;
}
if (varPtr && TclIsVarArray(varPtr) && !TclIsVarUndefined(varPtr)) {
objResultPtr = TCONST(1);
} else {
objResultPtr = TCONST(0);
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(pcAdjustment, cleanup, 1);
case INST_ARRAY_MAKE_IMM:
opnd = TclGetUInt4AtPtr(pc + 1);
pcAdjustment = 5;
cleanup = 0;
part1Ptr = NULL;
arrayPtr = NULL;
TRACE(("%u => ", opnd));
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
goto doArrayMake;
case INST_ARRAY_MAKE_STK:
opnd = -1;
pcAdjustment = 1;
cleanup = 1;
part1Ptr = OBJ_AT_TOS;
TRACE(("\"%.30s\" => ", O2S(part1Ptr)));
varPtr = TclObjLookupVarEx(interp, part1Ptr, NULL, TCL_LEAVE_ERR_MSG,
"set", /*createPart1*/1, /*createPart2*/0, &arrayPtr);
if (varPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
doArrayMake:
if (varPtr && !TclIsVarArray(varPtr)) {
if (TclIsVarArrayElement(varPtr) || !TclIsVarUndefined(varPtr)) {
/*
* Either an array element, or a scalar: lose!
*/
TclObjVarErrMsg(interp, part1Ptr, NULL, "array set",
"variable isn't array", opnd);
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "WRITE", "ARRAY", (char *)NULL);
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
TclInitArrayVar(varPtr);
#ifdef TCL_COMPILE_DEBUG
TRACE_APPEND(("done\n"));
} else {
TRACE_APPEND(("nothing to do\n"));
#endif
}
NEXT_INST_V(pcAdjustment, cleanup, 0);
/*
* End of INST_ARRAY instructions.
* -----------------------------------------------------------------
* Start of variable linking instructions.
*/
{
Var *otherPtr;
CallFrame *framePtr, *savedFramePtr;
Tcl_Namespace *nsPtr;
Namespace *savedNsPtr;
case INST_UPVAR:
TRACE(("%d %.30s %.30s => ", TclGetInt4AtPtr(pc + 1),
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS)));
if (TclObjGetFrame(interp, OBJ_UNDER_TOS, &framePtr) == -1) {
TRACE_ERROR(interp);
goto gotError;
}
/*
|
| ︙ | ︙ | |||
4385 4386 4387 4388 4389 4390 4391 |
if (!otherPtr) {
TRACE_ERROR(interp);
goto gotError;
}
goto doLinkVars;
case INST_NSUPVAR:
| | | | 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 |
if (!otherPtr) {
TRACE_ERROR(interp);
goto gotError;
}
goto doLinkVars;
case INST_NSUPVAR:
TRACE(("%d %.30s %.30s => ", TclGetInt4AtPtr(pc + 1),
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS)));
if (TclGetNamespaceFromObj(interp, OBJ_UNDER_TOS, &nsPtr) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
/*
* Locate the other variable.
|
| ︙ | ︙ | |||
4409 4410 4411 4412 4413 4414 4415 |
if (!otherPtr) {
TRACE_ERROR(interp);
goto gotError;
}
goto doLinkVars;
case INST_VARIABLE:
| | | 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 |
if (!otherPtr) {
TRACE_ERROR(interp);
goto gotError;
}
goto doLinkVars;
case INST_VARIABLE:
TRACE(("%d, %.30s => ", TclGetInt4AtPtr(pc + 1), O2S(OBJ_AT_TOS)));
otherPtr = TclObjLookupVarEx(interp, OBJ_AT_TOS, NULL,
(TCL_NAMESPACE_ONLY | TCL_LEAVE_ERR_MSG), "access",
/*createPart1*/ 1, /*createPart2*/ 1, &varPtr);
if (!otherPtr) {
TRACE_ERROR(interp);
goto gotError;
}
|
| ︙ | ︙ | |||
4432 4433 4434 4435 4436 4437 4438 | /* * If we are here, the local variable has already been created: do the * little work of TclPtrMakeUpvar that remains to be done right here * if there are no errors; otherwise, let it handle the case. */ | | | | | | | | > < < | | < > | | | | | < > | > > > > | | > > > > | < < < < < < < < < < < < < < < < > > | < < < < | | | | < < < < | | | | | | > < | < | | < | < < < < < < < < < < < < < < < < < < < < < < | | | | | | | > > < | > | > | < < | | | | < | > > < | > | | | | 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 |
/*
* If we are here, the local variable has already been created: do the
* little work of TclPtrMakeUpvar that remains to be done right here
* if there are no errors; otherwise, let it handle the case.
*/
opnd = TclGetInt4AtPtr(pc + 1);
varPtr = LOCAL(opnd);
if ((varPtr != otherPtr) && !TclIsVarTraced(varPtr)
&& (TclIsVarUndefined(varPtr) || TclIsVarLink(varPtr))) {
if (!TclIsVarUndefined(varPtr)) {
/*
* Then it is a defined link.
*/
Var *linkPtr = varPtr->value.linkPtr;
if (linkPtr == otherPtr) {
TRACE_APPEND(("already linked\n"));
NEXT_INST_F(5, 1, 0);
}
if (TclIsVarInHash(linkPtr)) {
VarHashRefCount(linkPtr)--;
if (TclIsVarUndefined(linkPtr)) {
TclCleanupVar(linkPtr, NULL);
}
}
}
TclSetVarLink(varPtr);
varPtr->value.linkPtr = otherPtr;
if (TclIsVarInHash(otherPtr)) {
VarHashRefCount(otherPtr)++;
}
} else if (TclPtrObjMakeUpvarIdx(interp, otherPtr, NULL, 0,
opnd) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
/*
* Do not pop the namespace or frame index, it may be needed for other
* variables - and [variable] did not push it at all.
*/
TRACE_APPEND(("link made\n"));
NEXT_INST_F(5, 1, 0);
}
break;
/*
* End of variable linking instructions.
* -----------------------------------------------------------------
*/
case INST_JUMP1:
opnd = TclGetInt1AtPtr(pc + 1);
TRACE(("%d => new pc %" TCL_Z_MODIFIER "u\n", opnd,
(size_t)(pc + opnd - codePtr->codeStart)));
NEXT_INST_F(opnd, 0, 0);
break;
case INST_JUMP4:
opnd = TclGetInt4AtPtr(pc + 1);
TRACE(("%d => new pc %" TCL_Z_MODIFIER "u\n", opnd,
(size_t)(pc + opnd - codePtr->codeStart)));
NEXT_INST_F(opnd, 0, 0);
{
int jmpOffset[2], b;
/* TODO: consider rewrite so we don't compute the offset we're not
* going to take. */
case INST_JUMP_FALSE4:
jmpOffset[0] = TclGetInt4AtPtr(pc + 1); /* FALSE offset */
jmpOffset[1] = 5; /* TRUE offset */
goto doCondJump;
case INST_JUMP_TRUE4:
jmpOffset[0] = 5;
jmpOffset[1] = TclGetInt4AtPtr(pc + 1);
goto doCondJump;
case INST_JUMP_FALSE1:
jmpOffset[0] = TclGetInt1AtPtr(pc + 1);
jmpOffset[1] = 2;
goto doCondJump;
case INST_JUMP_TRUE1:
jmpOffset[0] = 2;
jmpOffset[1] = TclGetInt1AtPtr(pc + 1);
doCondJump:
valuePtr = OBJ_AT_TOS;
TRACE(("%d => ", jmpOffset[
(*pc==INST_JUMP_FALSE1 || *pc==INST_JUMP_FALSE4) ? 0 : 1]));
/* TODO - check claim that taking address of b harms performance */
/* TODO - consider optimization search for constants */
if (TclGetBooleanFromObj(interp, valuePtr, &b) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
#ifdef TCL_COMPILE_DEBUG
if (b) {
if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
TRACE_APPEND(("%.20s true, new pc %" TCL_Z_MODIFIER "u\n", O2S(valuePtr),
(size_t)(pc + jmpOffset[1] - codePtr->codeStart)));
} else {
TRACE_APPEND(("%.20s true\n", O2S(valuePtr)));
}
} else {
if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
TRACE_APPEND(("%.20s false\n", O2S(valuePtr)));
} else {
TRACE_APPEND(("%.20s false, new pc %" TCL_Z_MODIFIER "u\n", O2S(valuePtr),
(size_t)(pc + jmpOffset[0] - codePtr->codeStart)));
}
}
#endif
NEXT_INST_F(jmpOffset[b], 1, 0);
}
break;
case INST_JUMP_TABLE: {
Tcl_HashEntry *hPtr;
JumptableInfo *jtPtr;
/*
* Jump to location looked up in a hashtable; fall through to next
* instr if lookup fails.
*/
opnd = TclGetInt4AtPtr(pc + 1);
jtPtr = (JumptableInfo *) codePtr->auxDataArrayPtr[opnd].clientData;
TRACE(("%d \"%.20s\" => ", opnd, O2S(OBJ_AT_TOS)));
hPtr = Tcl_FindHashEntry(&jtPtr->hashTable, TclGetString(OBJ_AT_TOS));
if (hPtr != NULL) {
Tcl_Size jumpOffset = PTR2INT(Tcl_GetHashValue(hPtr));
TRACE_APPEND(("found in table, new pc %" TCL_Z_MODIFIER "u\n",
(size_t)(pc - codePtr->codeStart + jumpOffset)));
NEXT_INST_F(jumpOffset, 1, 0);
} else {
TRACE_APPEND(("not found in table\n"));
NEXT_INST_F(5, 1, 0);
}
}
break;
/*
* -----------------------------------------------------------------
* Start of general introspector instructions.
*/
case INST_NS_CURRENT:
objResultPtr = TclNewNamespaceObj(TclGetCurrentNamespace(interp));
TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(1, 0, 1);
break;
case INST_COROUTINE_NAME: {
CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
TclNewObj(objResultPtr);
if (corPtr && !(corPtr->cmdPtr->flags & CMD_DYING)) {
Tcl_GetCommandFullName(interp, (Tcl_Command) corPtr->cmdPtr,
objResultPtr);
}
TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(1, 0, 1);
}
break;
case INST_INFO_LEVEL_NUM:
TclNewIntObj(objResultPtr, (int)iPtr->varFramePtr->level);
TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(1, 0, 1);
break;
case INST_INFO_LEVEL_ARGS: {
int level;
CallFrame *framePtr = iPtr->varFramePtr;
CallFrame *rootFramePtr = iPtr->rootFramePtr;
TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
if (TclGetIntFromObj(interp, OBJ_AT_TOS, &level) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
if (level <= 0) {
level += framePtr->level;
}
for (; ((int)framePtr->level!=level) && (framePtr!=rootFramePtr) ;
|
| ︙ | ︙ | |||
4668 4669 4670 4671 4672 4673 4674 | DECACHE_STACK_INFO(); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_LEVEL", TclGetString(OBJ_AT_TOS), (char *)NULL); CACHE_STACK_INFO(); goto gotError; } objResultPtr = Tcl_NewListObj(framePtr->objc, framePtr->objv); | | < | | | | | | | > > > | > > > | | < | | < < < < < < < < < < < < < | < | < < | < < < < < < < < | | < < > > > > > > > | | < < > | > | | > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | < < < < < < < < < < < < < < < | < | < < | < < < < < | < < < < > > > > > > > | | < < > | > | > | > > > > > > | | > > > > > > > | > > | | > | > > > | > | | > > > < < < | | < < | | | | < | < < < < < | | < | | < < | < < < < < < < < | | < | < | < < < < < < < < < | < < < < < > | < < | < < < < | | < < > | < < < < > > < < < < < < < < < < | | | < < < < < < | < < | < > > | | < < | > | < < | > > | | | | < | | | | | | | | 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 |
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "STACK_LEVEL",
TclGetString(OBJ_AT_TOS), (char *)NULL);
CACHE_STACK_INFO();
goto gotError;
}
objResultPtr = Tcl_NewListObj(framePtr->objc, framePtr->objv);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
}
{
Tcl_Command cmd, origCmd;
case INST_RESOLVE_COMMAND:
cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS);
TclNewObj(objResultPtr);
if (cmd != NULL) {
Tcl_GetCommandFullName(interp, cmd, objResultPtr);
}
TRACE_WITH_OBJ(("\"%.20s\" => ", O2S(OBJ_AT_TOS)), objResultPtr);
NEXT_INST_F(1, 1, 1);
case INST_ORIGIN_COMMAND:
TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
cmd = Tcl_GetCommandFromObj(interp, OBJ_AT_TOS);
if (cmd == NULL) {
goto instOriginError;
}
origCmd = TclGetOriginalCommand(cmd);
if (origCmd == NULL) {
origCmd = cmd;
}
TclNewObj(objResultPtr);
Tcl_GetCommandFullName(interp, origCmd, objResultPtr);
if (TclCheckEmptyString(objResultPtr) == TCL_EMPTYSTRING_YES ) {
Tcl_DecrRefCount(objResultPtr);
instOriginError:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"invalid command name \"%s\"", TclGetString(OBJ_AT_TOS)));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND",
TclGetString(OBJ_AT_TOS), (char *)NULL);
CACHE_STACK_INFO();
TRACE_APPEND(("ERROR: not command\n"));
goto gotError;
}
TRACE_APPEND(("\"%.30s\"", O2S(OBJ_AT_TOS)));
NEXT_INST_F(1, 1, 1);
}
/*
* -----------------------------------------------------------------
* Start of TclOO support instructions.
*/
{
Object *oPtr;
CallFrame *framePtr;
CallContext *contextPtr;
Tcl_Size skip, newDepth;
case INST_TCLOO_SELF:
framePtr = iPtr->varFramePtr;
if (framePtr == NULL ||
!(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
TRACE(("=> ERROR: no TclOO call context\n"));
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"self may only be called from inside a method",
-1));
DECACHE_STACK_INFO();
OO_ERROR(interp, CONTEXT_REQUIRED);
CACHE_STACK_INFO();
goto gotError;
}
contextPtr = (CallContext *)framePtr->clientData;
/*
* Call out to get the name; it's expensive to compute but cached.
*/
objResultPtr = TclOOObjectName(interp, contextPtr->oPtr);
TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(1, 0, 1);
case INST_TCLOO_NEXT_CLASS:
opnd = TclGetUInt1AtPtr(pc + 1);
framePtr = iPtr->varFramePtr;
valuePtr = OBJ_AT_DEPTH(opnd - 2);
objv = &OBJ_AT_DEPTH(opnd - 1);
skip = 2;
TRACE(("%d => ", opnd));
if (framePtr == NULL ||
!(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
TRACE_APPEND(("ERROR: no TclOO call context\n"));
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"nextto may only be called from inside a method",
-1));
DECACHE_STACK_INFO();
OO_ERROR(interp, CONTEXT_REQUIRED);
CACHE_STACK_INFO();
goto gotError;
}
contextPtr = (CallContext *)framePtr->clientData;
oPtr = (Object *) Tcl_GetObjectFromObj(interp, valuePtr);
if (oPtr == NULL) {
TRACE_APPEND(("ERROR: \"%.30s\" not object\n", O2S(valuePtr)));
goto gotError;
} else {
Class *classPtr = oPtr->classPtr;
struct MInvoke *miPtr;
Tcl_Size i;
const char *methodType;
if (classPtr == NULL) {
TRACE_APPEND(("ERROR: \"%.30s\" not class\n", O2S(valuePtr)));
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" is not a class", TclGetString(valuePtr)));
DECACHE_STACK_INFO();
OO_ERROR(interp, CLASS_REQUIRED);
CACHE_STACK_INFO();
goto gotError;
}
for (i=contextPtr->index + 1 ; i<contextPtr->callPtr->numChain ; i++) {
miPtr = contextPtr->callPtr->chain + i;
if (!miPtr->isFilter &&
miPtr->mPtr->declaringClassPtr == classPtr) {
newDepth = i;
#ifdef TCL_COMPILE_DEBUG
if (tclTraceExec >= 2) {
if (traceInstructions) {
strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
} else {
fprintf(stdout, "%" TCL_SIZE_MODIFIER "d: (%" TCL_T_MODIFIER "d) invoking ",
iPtr->numLevels,
(size_t)(pc - codePtr->codeStart));
}
for (i = 0; i < opnd; i++) {
TclPrintObject(stdout, objv[i], 15);
fprintf(stdout, " ");
}
fprintf(stdout, "\n");
fflush(stdout);
}
#endif /*TCL_COMPILE_DEBUG*/
goto doInvokeNext;
}
}
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
methodType = "constructor";
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
methodType = "destructor";
} else {
methodType = "method";
}
TRACE_APPEND(("ERROR: \"%.30s\" not on reachable chain\n",
O2S(valuePtr)));
for (i = contextPtr->index ; i != TCL_INDEX_NONE ; i--) {
miPtr = contextPtr->callPtr->chain + i;
if (miPtr->isFilter
|| miPtr->mPtr->declaringClassPtr != classPtr) {
continue;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s implementation by \"%s\" not reachable from here",
methodType, TclGetString(valuePtr)));
DECACHE_STACK_INFO();
OO_ERROR(interp, CLASS_NOT_REACHABLE);
CACHE_STACK_INFO();
goto gotError;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s has no non-filter implementation by \"%s\"",
methodType, TclGetString(valuePtr)));
DECACHE_STACK_INFO();
OO_ERROR(interp, CLASS_NOT_THERE);
CACHE_STACK_INFO();
goto gotError;
}
case INST_TCLOO_NEXT:
opnd = TclGetUInt1AtPtr(pc + 1);
objv = &OBJ_AT_DEPTH(opnd - 1);
framePtr = iPtr->varFramePtr;
skip = 1;
TRACE(("%d => ", opnd));
if (framePtr == NULL ||
!(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
TRACE_APPEND(("ERROR: no TclOO call context\n"));
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"next may only be called from inside a method",
-1));
DECACHE_STACK_INFO();
OO_ERROR(interp, CONTEXT_REQUIRED);
CACHE_STACK_INFO();
goto gotError;
}
contextPtr = (CallContext *)framePtr->clientData;
newDepth = contextPtr->index + 1;
if (newDepth >= contextPtr->callPtr->numChain) {
/*
* We're at the end of the chain; generate an error message unless
* the interpreter is being torn down, in which case we might be
* getting here because of methods/destructors doing a [next] (or
* equivalent) unexpectedly.
*/
const char *methodType;
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
methodType = "constructor";
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
methodType = "destructor";
} else {
methodType = "method";
}
TRACE_APPEND(("ERROR: no TclOO next impl\n"));
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"no next %s implementation", methodType));
DECACHE_STACK_INFO();
OO_ERROR(interp, NOTHING_NEXT);
CACHE_STACK_INFO();
goto gotError;
#ifdef TCL_COMPILE_DEBUG
} else if (tclTraceExec >= 2) {
int i;
if (traceInstructions) {
strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
} else {
fprintf(stdout, "%" TCL_SIZE_MODIFIER "d: (%" TCL_Z_MODIFIER "u) invoking ",
iPtr->numLevels, (pc - codePtr->codeStart));
}
for (i = 0; i < opnd; i++) {
TclPrintObject(stdout, objv[i], 15);
fprintf(stdout, " ");
}
fprintf(stdout, "\n");
fflush(stdout);
#endif /*TCL_COMPILE_DEBUG*/
}
doInvokeNext:
bcFramePtr->data.tebc.pc = (char *) pc;
iPtr->cmdFramePtr = bcFramePtr;
if (iPtr->flags & INTERP_DEBUG_FRAME) {
ArgumentBCEnter(interp, codePtr, TD, pc, opnd, objv);
}
pcAdjustment = 2;
cleanup = opnd;
DECACHE_STACK_INFO();
iPtr->varFramePtr = framePtr->callerVarPtr;
pc += pcAdjustment;
TEBC_YIELD();
TclPushTailcallPoint(interp);
oPtr = contextPtr->oPtr;
if (oPtr->flags & FILTER_HANDLING) {
TclNRAddCallback(interp, FinalizeOONextFilter,
framePtr, contextPtr, INT2PTR(contextPtr->index),
INT2PTR(contextPtr->skip));
} else {
TclNRAddCallback(interp, FinalizeOONext,
framePtr, contextPtr, INT2PTR(contextPtr->index),
INT2PTR(contextPtr->skip));
}
contextPtr->skip = skip;
contextPtr->index = newDepth;
if (contextPtr->callPtr->chain[newDepth].isFilter
|| contextPtr->callPtr->flags & FILTER_HANDLING) {
oPtr->flags |= FILTER_HANDLING;
} else {
oPtr->flags &= ~FILTER_HANDLING;
}
{
Method *const mPtr =
contextPtr->callPtr->chain[newDepth].mPtr;
if (mPtr->typePtr->version < TCL_OO_METHOD_VERSION_2) {
return mPtr->typePtr->callProc(mPtr->clientData, interp,
(Tcl_ObjectContext) contextPtr, opnd, objv);
}
return ((Tcl_MethodCallProc2 *)(void *)(mPtr->typePtr->callProc))(mPtr->clientData, interp,
(Tcl_ObjectContext) contextPtr, opnd, objv);
}
case INST_TCLOO_IS_OBJECT:
oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
objResultPtr = TCONST(oPtr != NULL ? 1 : 0);
TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
NEXT_INST_F(1, 1, 1);
case INST_TCLOO_CLASS:
oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
if (oPtr == NULL) {
TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS)));
goto gotError;
}
objResultPtr = TclOOObjectName(interp, oPtr->selfCls->thisPtr);
TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
NEXT_INST_F(1, 1, 1);
case INST_TCLOO_NS:
oPtr = (Object *) Tcl_GetObjectFromObj(interp, OBJ_AT_TOS);
if (oPtr == NULL) {
TRACE(("%.30s => ERROR: not object\n", O2S(OBJ_AT_TOS)));
goto gotError;
}
objResultPtr = TclNewNamespaceObj(oPtr->namespacePtr);
TRACE_WITH_OBJ(("%.30s => ", O2S(OBJ_AT_TOS)), objResultPtr);
NEXT_INST_F(1, 1, 1);
}
/*
* End of TclOO support instructions.
* -----------------------------------------------------------------
* Start of INST_LIST and related instructions.
*/
{
int numIndices, nocase, match, cflags;
Tcl_Size slength, length2, fromIdx, toIdx, index, s1len, s2len;
const char *s1, *s2;
case INST_LIST:
/*
* Pop the opnd (objc) top stack elements into a new list obj and then
* decrement their ref counts.
*/
opnd = TclGetUInt4AtPtr(pc + 1);
objResultPtr = Tcl_NewListObj(opnd, &OBJ_AT_DEPTH(opnd-1));
TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
NEXT_INST_V(5, opnd, 1);
case INST_LIST_LENGTH:
TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
if (TclListObjLength(interp, OBJ_AT_TOS, &length) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
TclNewIntObj(objResultPtr, length);
TRACE_APPEND(("%" TCL_SIZE_MODIFIER "d\n", length));
NEXT_INST_F(1, 1, 1);
case INST_LIST_INDEX: /* lindex with objc == 3 */
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
TRACE(("\"%.30s\" \"%.30s\" => ", O2S(valuePtr), O2S(value2Ptr)));
/* special case for AbstractList */
if (TclObjTypeHasProc(valuePtr, indexProc)) {
DECACHE_STACK_INFO();
length = TclObjTypeLength(valuePtr);
if (TclGetIntForIndexM(NULL, value2Ptr, length-1, &index)!=TCL_OK) {
CACHE_STACK_INFO();
/* Could be list of indices. Let TclLindexList handle it below */
} else {
if (TclObjTypeIndex(interp, valuePtr, index, &objResultPtr) !=
TCL_OK) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
CACHE_STACK_INFO();
if (objResultPtr == NULL) {
/* Index is out of range, return empty result. */
|
| ︙ | ︙ | |||
5092 5093 5094 5095 5096 5097 5098 | goto gotError; } /* * Stash the list element on the stack. */ | | | < | | | | | | | | | | | | | | | < | | | > | | | | | | | | | | | | | < | > < | | | | | | | | | 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 |
goto gotError;
}
/*
* Stash the list element on the stack.
*/
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, -1); /* Already has the correct refCount */
case INST_LIST_INDEX_IMM: /* lindex with objc==3 and index in bytecode
* stream */
/*
* Pop the list and get the index.
*/
valuePtr = OBJ_AT_TOS;
opnd = TclGetInt4AtPtr(pc + 1);
TRACE(("\"%.30s\" %d => ", O2S(valuePtr), opnd));
/*
* Get the contents of the list, making sure that it really is a list
* in the process.
*/
/* special case for AbstractList */
if (TclObjTypeHasProc(valuePtr, indexProc)) {
length = TclObjTypeLength(valuePtr);
/* Decode end-offset index values. */
index = TclIndexDecode(opnd, length-1);
if (index >= 0 && index < length) {
/* Compute value @ index */
DECACHE_STACK_INFO();
if (TclObjTypeIndex(interp, valuePtr, index, &objResultPtr)!=TCL_OK) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
CACHE_STACK_INFO();
} else {
TclNewObj(objResultPtr);
}
pcAdjustment = 5;
goto lindexFastPath2;
}
/* List case */
if (TclListObjGetElements(interp, valuePtr, &objc, &objv) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
/* Decode end-offset index values. */
index = TclIndexDecode(opnd, objc - 1);
pcAdjustment = 5;
lindexFastPath:
if (index >= 0 && index < objc) {
objResultPtr = objv[index];
} else {
TclNewObj(objResultPtr);
}
lindexFastPath2:
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_F(pcAdjustment, 1, 1);
case INST_LIST_INDEX_MULTI: /* 'lindex' with multiple index args */
/*
* Determine the count of index args.
*/
opnd = TclGetUInt4AtPtr(pc + 1);
numIndices = opnd - 1;
/*
* Do the 'lindex' operation.
*/
TRACE(("%d => ", opnd));
objResultPtr = TclLindexFlat(interp, OBJ_AT_DEPTH(numIndices),
numIndices, &OBJ_AT_DEPTH(numIndices - 1));
if (!objResultPtr) {
TRACE_ERROR(interp);
goto gotError;
}
/*
* Set result.
*/
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd, -1);
case INST_LSET_FLAT:
/*
* Lset with 3, 5, or more args. Get the number of index args.
*/
opnd = TclGetUInt4AtPtr(pc + 1);
numIndices = opnd - 2;
TRACE(("%d => ", opnd));
/*
* Get the old value of variable, and remove the stack ref. This is
* safe because the variable still references the object; the ref
* count will never go zero here - we can use the smaller macro
* Tcl_DecrRefCount.
*/
|
| ︙ | ︙ | |||
5228 5229 5230 5231 5232 5233 5234 | TRACE_ERROR(interp); goto gotError; } /* * Set result. */ | | | | | | | | > | | | | | | | | | | | | | > > > > > > > | < > | 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 |
TRACE_ERROR(interp);
goto gotError;
}
/*
* Set result.
*/
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_V(5, numIndices + 1, -1);
case INST_LSET_LIST: /* 'lset' with 4 args */
/*
* Get the old value of variable, and remove the stack ref. This is
* safe because the variable still references the object; the ref
* count will never go zero here - we can use the smaller macro
* Tcl_DecrRefCount.
*/
objPtr = POP_OBJECT();
Tcl_DecrRefCount(objPtr); /* This one should be done here. */
/*
* Get the new element value, and the index list.
*/
valuePtr = OBJ_AT_TOS;
value2Ptr = OBJ_UNDER_TOS;
TRACE(("\"%.30s\" \"%.30s\" \"%.30s\" => ",
O2S(value2Ptr), O2S(valuePtr), O2S(objPtr)));
/*
* Compute the new variable value.
*/
objResultPtr = TclLsetList(interp, objPtr, value2Ptr, valuePtr);
if (!objResultPtr) {
TRACE_ERROR(interp);
goto gotError;
}
/*
* Set result.
*/
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, -1);
case INST_LIST_RANGE_IMM: /* lrange with objc==4 and both indices in
* bytecode stream */
/*
* Pop the list and get the indices.
*/
valuePtr = OBJ_AT_TOS;
fromIdx = TclGetInt4AtPtr(pc + 1);
toIdx = TclGetInt4AtPtr(pc + 5);
TRACE(("\"%.30s\" %d %d => ", O2S(valuePtr), TclGetInt4AtPtr(pc + 1),
TclGetInt4AtPtr(pc + 5)));
/*
* Get the length of the list, making sure that it really is a list
* in the process.
*/
if (TclListObjLength(interp, valuePtr, &objc) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
/*
* Skip a lot of work if we're about to throw the result away (common
* with uses of [lassign]).
*/
#ifndef TCL_COMPILE_DEBUG
if (pc[9] == INST_POP) {
NEXT_INST_F(10, 1, 0);
}
#endif
/* Every range of an empty list is an empty list */
if (objc == 0) {
/* avoid return of not canonical list (e. g. spaces in string repr.) */
if (!valuePtr->bytes || !valuePtr->length) {
TRACE_APPEND(("\n"));
NEXT_INST_F(9, 0, 0);
}
goto emptyList;
}
/* Decode index value operands. */
if (toIdx == TCL_INDEX_NONE) {
emptyList:
TclNewObj(objResultPtr);
TRACE_APPEND(("\"%.30s\"", O2S(objResultPtr)));
NEXT_INST_F(9, 1, 1);
}
toIdx = TclIndexDecode(toIdx, objc - 1);
if (toIdx == TCL_INDEX_NONE) {
goto emptyList;
} else if (toIdx >= objc) {
toIdx = objc - 1;
}
assert (toIdx >= 0 && toIdx < objc);
/*
assert ( fromIdx != TCL_INDEX_NONE );
*
* Extra safety for legacy bytecodes:
*/
if (fromIdx == TCL_INDEX_NONE) {
fromIdx = TCL_INDEX_START;
}
fromIdx = TclIndexDecode(fromIdx, objc - 1);
DECACHE_STACK_INFO();
if (TclObjTypeHasProc(valuePtr, sliceProc)) {
if (TclObjTypeSlice(interp, valuePtr, fromIdx, toIdx, &objResultPtr) != TCL_OK) {
objResultPtr = NULL;
}
} else {
objResultPtr = TclListObjRange(interp, valuePtr, fromIdx, toIdx);
}
if (objResultPtr == NULL) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
CACHE_STACK_INFO();
TRACE_APPEND(("\"%.30s\"", O2S(objResultPtr)));
NEXT_INST_F(9, 1, 1);
case INST_LIST_IN:
case INST_LIST_NOT_IN: /* Basic list containment operators. */
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
s1 = TclGetStringFromObj(valuePtr, &s1len);
TRACE(("\"%.30s\" \"%.30s\" => ", O2S(valuePtr), O2S(value2Ptr)));
if (TclObjTypeHasProc(value2Ptr, inOperProc) != NULL) {
int status = TclObjTypeInOperator(interp, valuePtr, value2Ptr, &match);
if (status != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
|
| ︙ | ︙ | |||
5420 5421 5422 5423 5424 5425 5426 |
}
}
if (*pc == INST_LIST_NOT_IN) {
match = !match;
}
| | | | | | | | > > > > | | | | | | | | < < < > | < < < < < < < < < < < | | | 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 |
}
}
if (*pc == INST_LIST_NOT_IN) {
match = !match;
}
TRACE_APPEND(("%d\n", match));
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
* We're saving the effort of pushing a boolean value only to pop it
* for branching.
*/
JUMP_PEEPHOLE_F(match, 1, 2);
case INST_LIST_CONCAT:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
TRACE(("\"%.30s\" \"%.30s\" => ", O2S(valuePtr), O2S(value2Ptr)));
if (Tcl_IsShared(valuePtr)) {
objResultPtr = Tcl_DuplicateObj(valuePtr);
if (Tcl_ListObjAppendList(interp, objResultPtr,
value2Ptr) != TCL_OK) {
TRACE_ERROR(interp);
TclDecrRefCount(objResultPtr);
goto gotError;
}
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else {
if (Tcl_ListObjAppendList(interp, valuePtr, value2Ptr) != TCL_OK){
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("\"%.30s\"\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
}
case INST_LREPLACE4: {
size_t numToDelete, numNewElems;
int end_indicator;
int haveSecondIndex, flags;
Tcl_Obj *fromIdxObj, *toIdxObj;
opnd = TclGetInt4AtPtr(pc + 1);
flags = TclGetInt1AtPtr(pc + 5);
/* Stack: ... listobj index1 ?index2? new1 ... newN */
valuePtr = OBJ_AT_DEPTH(opnd-1);
/* haveSecondIndex==0 => pure insert */
haveSecondIndex = (flags & TCL_LREPLACE4_SINGLE_INDEX) == 0;
numNewElems = opnd - 2 - haveSecondIndex;
/* end_indicator==1 => "end" is last element's index, 0=>index beyond */
end_indicator = (flags & TCL_LREPLACE4_END_IS_LAST) != 0;
fromIdxObj = OBJ_AT_DEPTH(opnd - 2);
toIdxObj = haveSecondIndex ? OBJ_AT_DEPTH(opnd - 3) : NULL;
if (Tcl_ListObjLength(interp, valuePtr, &length) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
DECACHE_STACK_INFO();
if (TclGetIntForIndexM(interp, fromIdxObj, length - end_indicator,
&fromIdx) != TCL_OK) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
if (fromIdx == TCL_INDEX_NONE) {
fromIdx = 0;
} else if (fromIdx > length) {
fromIdx = length;
}
numToDelete = 0;
if (toIdxObj) {
if (TclGetIntForIndexM(interp, toIdxObj, length - end_indicator,
&toIdx) != TCL_OK) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
if (toIdx != TCL_INDEX_NONE) {
if (toIdx > length) {
|
| ︙ | ︙ | |||
5527 5528 5529 5530 5531 5532 5533 |
objResultPtr = Tcl_DuplicateObj(valuePtr);
if (Tcl_ListObjReplace(interp, objResultPtr, fromIdx, numToDelete,
numNewElems, &OBJ_AT_DEPTH(numNewElems - 1)) != TCL_OK) {
TRACE_ERROR(interp);
Tcl_DecrRefCount(objResultPtr);
goto gotError;
}
| | | | | | < < < < < < < < < < < < < < < < < < < < < > < < | 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 |
objResultPtr = Tcl_DuplicateObj(valuePtr);
if (Tcl_ListObjReplace(interp, objResultPtr, fromIdx, numToDelete,
numNewElems, &OBJ_AT_DEPTH(numNewElems - 1)) != TCL_OK) {
TRACE_ERROR(interp);
Tcl_DecrRefCount(objResultPtr);
goto gotError;
}
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_V(6, opnd, 1);
} else {
if (Tcl_ListObjReplace(interp, valuePtr, fromIdx, numToDelete,
numNewElems, &OBJ_AT_DEPTH(numNewElems - 1)) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("\"%.30s\"\n", O2S(valuePtr)));
NEXT_INST_V(6, opnd - 1, 0);
}
}
/*
* End of INST_LIST and related instructions.
* -----------------------------------------------------------------
* Start of string-related instructions.
*/
case INST_STR_EQ:
case INST_STR_NEQ: /* String (in)equality check */
case INST_STR_CMP: /* String compare. */
case INST_STR_LT:
case INST_STR_GT:
case INST_STR_LE:
case INST_STR_GE:
stringCompare:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
{
int checkEq = ((*pc == INST_EQ) || (*pc == INST_NEQ)
|| (*pc == INST_STR_EQ) || (*pc == INST_STR_NEQ));
match = TclStringCmp(valuePtr, value2Ptr, checkEq, 0, -1);
}
/*
|
| ︙ | ︙ | |||
5623 5624 5625 5626 5627 5628 5629 | case INST_GE: case INST_STR_GE: match = (match >= 0); break; } } | > | < < > < < < > > > > > | > > > > | > > > > > > > > > > | > > > > | > > > > > < < | < | | | | | < | < | | < | | | < > | | | | | > > > > | | | | | | | | | | | | | | | | | | | < < | 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 |
case INST_GE:
case INST_STR_GE:
match = (match >= 0);
break;
}
}
TRACE(("\"%.20s\" \"%.20s\" => %d\n", O2S(valuePtr), O2S(value2Ptr),
(match < 0 ? -1 : match > 0 ? 1 : 0)));
JUMP_PEEPHOLE_F(match, 1, 2);
case INST_STR_LEN:
valuePtr = OBJ_AT_TOS;
slength = Tcl_GetCharLength(valuePtr);
TclNewIntObj(objResultPtr, slength);
TRACE(("\"%.20s\" => %" TCL_Z_MODIFIER "u\n", O2S(valuePtr), slength));
NEXT_INST_F(1, 1, 1);
case INST_STR_UPPER:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.20s\" => ", O2S(valuePtr)));
if (Tcl_IsShared(valuePtr)) {
s1 = TclGetStringFromObj(valuePtr, &slength);
TclNewStringObj(objResultPtr, s1, slength);
slength = Tcl_UtfToUpper(TclGetString(objResultPtr));
Tcl_SetObjLength(objResultPtr, slength);
TRACE_APPEND(("\"%.20s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
slength = Tcl_UtfToUpper(TclGetString(valuePtr));
Tcl_SetObjLength(valuePtr, slength);
TclFreeInternalRep(valuePtr);
TRACE_APPEND(("\"%.20s\"\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_STR_LOWER:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.20s\" => ", O2S(valuePtr)));
if (Tcl_IsShared(valuePtr)) {
s1 = TclGetStringFromObj(valuePtr, &slength);
TclNewStringObj(objResultPtr, s1, slength);
slength = Tcl_UtfToLower(TclGetString(objResultPtr));
Tcl_SetObjLength(objResultPtr, slength);
TRACE_APPEND(("\"%.20s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
slength = Tcl_UtfToLower(TclGetString(valuePtr));
Tcl_SetObjLength(valuePtr, slength);
TclFreeInternalRep(valuePtr);
TRACE_APPEND(("\"%.20s\"\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_STR_TITLE:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.20s\" => ", O2S(valuePtr)));
if (Tcl_IsShared(valuePtr)) {
s1 = TclGetStringFromObj(valuePtr, &slength);
TclNewStringObj(objResultPtr, s1, slength);
slength = Tcl_UtfToTitle(TclGetString(objResultPtr));
Tcl_SetObjLength(objResultPtr, slength);
TRACE_APPEND(("\"%.20s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
slength = Tcl_UtfToTitle(TclGetString(valuePtr));
Tcl_SetObjLength(valuePtr, slength);
TclFreeInternalRep(valuePtr);
TRACE_APPEND(("\"%.20s\"\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_STR_INDEX:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
TRACE(("\"%.20s\" %.20s => ", O2S(valuePtr), O2S(value2Ptr)));
/*
* Get char length to calculate what 'end' means.
*/
slength = Tcl_GetCharLength(valuePtr);
DECACHE_STACK_INFO();
if (TclGetIntForIndexM(interp, value2Ptr, slength-1, &index)!=TCL_OK) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
CACHE_STACK_INFO();
if (index < 0 || index >= slength) {
TclNewObj(objResultPtr);
} else if (TclIsPureByteArray(valuePtr)) {
objResultPtr = Tcl_NewByteArrayObj(
Tcl_GetBytesFromObj(NULL, valuePtr, (Tcl_Size *)NULL)+index, 1);
} else if (valuePtr->bytes && slength == valuePtr->length) {
objResultPtr = Tcl_NewStringObj((const char *)
valuePtr->bytes+index, 1);
} else {
char buf[4] = "";
int ch = Tcl_GetUniChar(valuePtr, index);
/*
* This could be: Tcl_NewUnicodeObj((const Tcl_UniChar *)&ch, 1)
* but creating the object as a string seems to be faster in
* practical use.
*/
if (ch == -1) {
TclNewObj(objResultPtr);
} else {
slength = Tcl_UniCharToUtf(ch, buf);
objResultPtr = Tcl_NewStringObj(buf, slength);
}
}
TRACE_APPEND(("\"%s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
case INST_STR_RANGE:
TRACE(("\"%.20s\" %.20s %.20s =>",
O2S(OBJ_AT_DEPTH(2)), O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS)));
slength = Tcl_GetCharLength(OBJ_AT_DEPTH(2)) - 1;
DECACHE_STACK_INFO();
if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, slength, &fromIdx) != TCL_OK) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
if (TclGetIntForIndexM(interp, OBJ_AT_TOS, slength, &toIdx) != TCL_OK) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
CACHE_STACK_INFO();
if (toIdx == TCL_INDEX_NONE) {
TclNewObj(objResultPtr);
} else {
objResultPtr = Tcl_GetRange(OBJ_AT_DEPTH(2), fromIdx, toIdx);
}
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_V(1, 3, 1);
case INST_STR_RANGE_IMM:
valuePtr = OBJ_AT_TOS;
fromIdx = TclGetInt4AtPtr(pc + 1);
toIdx = TclGetInt4AtPtr(pc + 5);
slength = Tcl_GetCharLength(valuePtr);
TRACE(("\"%.20s\" %d %d => ", O2S(valuePtr), (int)(fromIdx), (int)(toIdx)));
/* Every range of an empty value is an empty value */
if (slength == 0) {
TRACE_APPEND(("\n"));
NEXT_INST_F(9, 0, 0);
}
/* Decode index operands. */
toIdx = TclIndexDecode(toIdx, slength - 1);
fromIdx = TclIndexDecode(fromIdx, slength - 1);
if (toIdx == TCL_INDEX_NONE) {
TclNewObj(objResultPtr);
} else {
objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(9, 1, 1);
{
Tcl_UniChar *ustring1, *ustring2, *ustring3, *end, *p;
Tcl_Size length3;
Tcl_Obj *value3Ptr;
case INST_STR_REPLACE:
value3Ptr = POP_OBJECT();
valuePtr = OBJ_AT_DEPTH(2);
slength = Tcl_GetCharLength(valuePtr) - 1;
TRACE(("\"%.20s\" %s %s \"%.20s\" => ", O2S(valuePtr),
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), O2S(value3Ptr)));
DECACHE_STACK_INFO();
if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, slength, &fromIdx) != TCL_OK
|| TclGetIntForIndexM(interp, OBJ_AT_TOS, slength, &toIdx) != TCL_OK) {
CACHE_STACK_INFO();
TclDecrRefCount(value3Ptr);
TRACE_ERROR(interp);
goto gotError;
}
CACHE_STACK_INFO();
TclDecrRefCount(OBJ_AT_TOS);
(void) POP_OBJECT();
TclDecrRefCount(OBJ_AT_TOS);
(void) POP_OBJECT();
if ((toIdx < 0) || (fromIdx > slength) || (toIdx < fromIdx)) {
TRACE_APPEND(("\"%.30s\"\n", O2S(valuePtr)));
TclDecrRefCount(value3Ptr);
NEXT_INST_F(1, 0, 0);
}
if (fromIdx < 0) {
fromIdx = 0;
}
if (toIdx > slength) {
toIdx = slength;
}
if ((fromIdx == 0) && (toIdx == slength)) {
TclDecrRefCount(OBJ_AT_TOS);
OBJ_AT_TOS = value3Ptr;
TRACE_APPEND(("\"%.30s\"\n", O2S(value3Ptr)));
NEXT_INST_F(1, 0, 0);
}
objResultPtr = TclStringReplace(interp, valuePtr, fromIdx,
toIdx - fromIdx + 1, value3Ptr, TCL_STRING_IN_PLACE);
if (objResultPtr == value3Ptr) {
/* See [Bug 82e7f67325] */
TclDecrRefCount(OBJ_AT_TOS);
OBJ_AT_TOS = value3Ptr;
TRACE_APPEND(("\"%.30s\"\n", O2S(value3Ptr)));
NEXT_INST_F(1, 0, 0);
}
TclDecrRefCount(value3Ptr);
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
case INST_STR_MAP:
valuePtr = OBJ_AT_TOS; /* "Main" string. */
value3Ptr = OBJ_UNDER_TOS; /* "Target" string. */
value2Ptr = OBJ_AT_DEPTH(2); /* "Source" string. */
if (value3Ptr == value2Ptr) {
objResultPtr = valuePtr;
goto doneStringMap;
} else if (valuePtr == value2Ptr) {
objResultPtr = value3Ptr;
goto doneStringMap;
}
|
| ︙ | ︙ | |||
5880 5881 5882 5883 5884 5885 5886 |
/*
* Put the rest of the unmapped chars onto result.
*/
Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1 - p);
}
doneStringMap:
| > | < | > > < | > > | | | > | | | < | 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 |
/*
* Put the rest of the unmapped chars onto result.
*/
Tcl_AppendUnicodeToObj(objResultPtr, p, ustring1 - p);
}
doneStringMap:
TRACE_WITH_OBJ(("%.20s %.20s %.20s => ",
O2S(value2Ptr), O2S(value3Ptr), O2S(valuePtr)), objResultPtr);
NEXT_INST_V(1, 3, 1);
case INST_STR_FIND:
objResultPtr = TclStringFirst(OBJ_UNDER_TOS, OBJ_AT_TOS, 0);
TRACE(("%.20s %.20s => %s\n",
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
case INST_STR_FIND_LAST:
objResultPtr = TclStringLast(OBJ_UNDER_TOS, OBJ_AT_TOS, TCL_SIZE_MAX - 1);
TRACE(("%.20s %.20s => %s\n",
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
case INST_STR_CLASS:
opnd = TclGetInt1AtPtr(pc + 1);
valuePtr = OBJ_AT_TOS;
TRACE(("%s \"%.30s\" => ", tclStringClassTable[opnd].name,
O2S(valuePtr)));
ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &slength);
match = 1;
if (slength > 0) {
int ch;
end = ustring1 + slength;
for (p=ustring1 ; p<end ; ) {
ch = *p++;
if (!tclStringClassTable[opnd].comparator(ch)) {
match = 0;
break;
}
}
}
TRACE_APPEND(("%d\n", match));
JUMP_PEEPHOLE_F(match, 2, 1);
}
case INST_STR_MATCH:
nocase = TclGetInt1AtPtr(pc + 1);
valuePtr = OBJ_AT_TOS; /* String */
value2Ptr = OBJ_UNDER_TOS; /* Pattern */
/*
* Check that at least one of the objects is Unicode before promoting
* both.
*/
if (TclHasInternalRep(valuePtr, &tclStringType)
|
| ︙ | ︙ | |||
5943 5944 5945 5946 5947 5948 5949 |
unsigned char *bytes2 = Tcl_GetBytesFromObj(NULL, value2Ptr, &wlen2);
match = TclByteArrayMatch(bytes1, wlen1, bytes2, wlen2, 0);
} else {
match = Tcl_StringCaseMatch(TclGetString(valuePtr),
TclGetString(value2Ptr), nocase);
}
| > > > > | > | 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 |
unsigned char *bytes2 = Tcl_GetBytesFromObj(NULL, value2Ptr, &wlen2);
match = TclByteArrayMatch(bytes1, wlen1, bytes2, wlen2, 0);
} else {
match = Tcl_StringCaseMatch(TclGetString(valuePtr),
TclGetString(value2Ptr), nocase);
}
/*
* Reuse value2Ptr object already on stack if possible. Adjustment is
* 2 due to the nocase byte
*/
TRACE(("%.20s %.20s => %d\n", O2S(valuePtr), O2S(value2Ptr), match));
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
*/
JUMP_PEEPHOLE_F(match, 2, 2);
|
| ︙ | ︙ | |||
5985 5986 5987 5988 5989 5990 5991 |
/*
* Careful here; trim set often contains non-ASCII characters so we
* take care when printing. [Bug 971cb4f1db]
*/
#ifdef TCL_COMPILE_DEBUG
if (traceInstructions) {
| | | | | | < > > | > | < | | | | < | | | | > > > < < < < < < < < | < | 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 |
/*
* Careful here; trim set often contains non-ASCII characters so we
* take care when printing. [Bug 971cb4f1db]
*/
#ifdef TCL_COMPILE_DEBUG
if (traceInstructions) {
TRACE(("\"%.30s\" ", O2S(valuePtr)));
TclPrintObject(stdout, value2Ptr, 30);
printf(" => ");
}
#endif
if (trim1 == 0 && trim2 == 0) {
#ifdef TCL_COMPILE_DEBUG
if (traceInstructions) {
TclPrintObject(stdout, valuePtr, 30);
printf("\n");
}
#endif
NEXT_INST_F(1, 1, 0);
} else {
objResultPtr = Tcl_NewStringObj(string1+trim1, slength-trim1-trim2);
#ifdef TCL_COMPILE_DEBUG
if (traceInstructions) {
TclPrintObject(stdout, objResultPtr, 30);
printf("\n");
}
#endif
NEXT_INST_F(1, 2, 1);
}
}
case INST_REGEXP:
cflags = TclGetInt1AtPtr(pc + 1); /* RE compile flages like NOCASE */
valuePtr = OBJ_AT_TOS; /* String */
value2Ptr = OBJ_UNDER_TOS; /* Pattern */
TRACE(("\"%.30s\" \"%.30s\" => ", O2S(valuePtr), O2S(value2Ptr)));
/*
* Compile and match the regular expression.
*/
{
Tcl_RegExp regExpr =
Tcl_GetRegExpFromObj(interp, value2Ptr, cflags);
if (regExpr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
match = Tcl_RegExpExecObj(interp, regExpr, valuePtr, 0, 0, 0);
if (match < 0) {
TRACE_ERROR(interp);
goto gotError;
}
}
TRACE_APPEND(("%d\n", match));
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
* Adjustment is 2 due to the nocase byte.
*/
JUMP_PEEPHOLE_F(match, 2, 2);
}
/*
* End of string-related instructions.
* -----------------------------------------------------------------
* Start of numeric operator instructions.
*/
{
void *ptr1, *ptr2;
int type1, type2;
Tcl_WideInt w1, w2, wResult;
case INST_NUM_TYPE:
if (GetNumberFromObj(NULL, OBJ_AT_TOS, &ptr1, &type1) != TCL_OK) {
type1 = 0;
}
TclNewIntObj(objResultPtr, type1);
TRACE(("\"%.20s\" => %d\n", O2S(OBJ_AT_TOS), type1));
NEXT_INST_F(1, 1, 1);
case INST_EQ:
case INST_NEQ:
case INST_LT:
case INST_GT:
case INST_LE:
case INST_GE: {
int iResult = 0, compare = 0;
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;
|
| ︙ | ︙ | |||
6148 6149 6150 6151 6152 6153 6154 |
}
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
*/
foundResult:
| > | < | > > | > > | > > | > | > < > | > | > < > | < > > | | | | < | > > < | | > > < | 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 |
}
/*
* Peep-hole optimisation: if you're about to jump, do jump from here.
*/
foundResult:
TRACE(("\"%.20s\" \"%.20s\" => %d\n", O2S(valuePtr), O2S(value2Ptr),
iResult));
JUMP_PEEPHOLE_F(iResult, 1, 2);
}
case INST_MOD:
case INST_LSHIFT:
case INST_RSHIFT:
case INST_BITOR:
case INST_BITXOR:
case INST_BITAND:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
if ((GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
|| (type1==TCL_NUMBER_DOUBLE) || (type1==TCL_NUMBER_NAN)) {
TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n", O2S(valuePtr),
O2S(value2Ptr), (valuePtr->typePtr?
valuePtr->typePtr->name : "null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "left ", pc, valuePtr);
CACHE_STACK_INFO();
goto gotError;
}
if ((GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK)
|| (type2==TCL_NUMBER_DOUBLE) || (type2==TCL_NUMBER_NAN)) {
TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n", O2S(valuePtr),
O2S(value2Ptr), (value2Ptr->typePtr?
value2Ptr->typePtr->name : "null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "right ", pc, value2Ptr);
CACHE_STACK_INFO();
goto gotError;
}
/*
* Check for common, simple case.
*/
if ((type1 == TCL_NUMBER_INT) && (type2 == TCL_NUMBER_INT)) {
w1 = *((const Tcl_WideInt *)ptr1);
w2 = *((const Tcl_WideInt *)ptr2);
switch (*pc) {
case INST_MOD:
if (w2 == 0) {
TRACE(("%s %s => DIVIDE BY ZERO\n", O2S(valuePtr),
O2S(value2Ptr)));
goto divideByZero;
} else if ((w2 == 1) || (w2 == -1)) {
/*
* Div. by |1| always yields remainder of 0.
*/
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else if (w1 == 0) {
/*
* 0 % (non-zero) always yields remainder of 0.
*/
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else {
wResult = w1 / w2;
/*
* Force Tcl's integer division rules.
* TODO: examine for logic simplification
*/
if ((wResult < 0 || (wResult == 0 &&
((w1 < 0 && w2 > 0) || (w1 > 0 && w2 < 0)))) &&
(wResult * w2 != w1)) {
wResult -= 1;
}
wResult = (Tcl_WideInt)((Tcl_WideUInt)w1 -
(Tcl_WideUInt)w2*(Tcl_WideUInt)wResult);
goto wideResultOfArithmetic;
}
break;
case INST_RSHIFT:
if (w2 < 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"negative shift argument", -1));
#ifdef ERROR_CODE_FOR_EARLY_DETECTED_ARITH_ERROR
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "ARITH", "DOMAIN",
"domain error: argument not in valid range",
(char *)NULL);
CACHE_STACK_INFO();
#endif /* ERROR_CODE_FOR_EARLY_DETECTED_ARITH_ERROR */
goto gotError;
} else if (w1 == 0) {
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else {
/*
* Quickly force large right shifts to 0 or -1.
*/
if (w2 >= (Tcl_WideInt)(CHAR_BIT*sizeof(w1))) {
/*
* We assume that INT_MAX is much larger than the
* number of bits in a Tcl_WideInt. This is a pretty safe
* assumption, given that the former is usually around
* 4e9 and the latter 64...
*/
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
if (w1 > 0L) {
objResultPtr = TCONST(0);
} else {
TclNewIntObj(objResultPtr, -1);
}
TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
/*
* Handle shifts within the native Tcl_WideInt range.
*/
wResult = w1 >> ((int) w2);
goto wideResultOfArithmetic;
}
break;
case INST_LSHIFT:
if (w2 < 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"negative shift argument", -1));
#ifdef ERROR_CODE_FOR_EARLY_DETECTED_ARITH_ERROR
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "ARITH", "DOMAIN",
"domain error: argument not in valid range",
(char *)NULL);
CACHE_STACK_INFO();
#endif /* ERROR_CODE_FOR_EARLY_DETECTED_ARITH_ERROR */
goto gotError;
} else if (w1 == 0) {
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = TCONST(0);
TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
} else if (w2 > INT_MAX) {
/*
* Technically, we could hold the value (1 << (INT_MAX+1))
* in an mp_int, but since we're using mp_mul_2d() to do
* the work, and it takes only an int argument, that's a
* good place to draw the line.
*/
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"integer value too large to represent", -1));
#ifdef ERROR_CODE_FOR_EARLY_DETECTED_ARITH_ERROR
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW",
"integer value too large to represent", (char *)NULL);
CACHE_STACK_INFO();
#endif /* ERROR_CODE_FOR_EARLY_DETECTED_ARITH_ERROR */
goto gotError;
} else {
int shift = (int) w2;
/*
* Handle shifts within the native Tcl_WideInt range.
*/
if (((size_t)shift < CHAR_BIT*sizeof(w1))
&& !((w1>0 ? w1 : ~w1) &
-((Tcl_WideUInt)1<<(CHAR_BIT*sizeof(w1) - 1 - shift)))) {
wResult = (Tcl_WideUInt)w1 << shift;
goto wideResultOfArithmetic;
}
}
/*
* Too large; need to use the broken-out function.
*/
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
break;
case INST_BITAND:
wResult = w1 & w2;
goto wideResultOfArithmetic;
case INST_BITOR:
wResult = w1 | w2;
goto wideResultOfArithmetic;
case INST_BITXOR:
wResult = w1 ^ w2;
goto wideResultOfArithmetic;
}
}
/*
* DO NOT MERGE THIS WITH THE EQUIVALENT SECTION LATER! That would
* encourage the compiler to inline ExecuteExtendedBinaryMathOp, which
* is highly undesirable due to the overall impact on size.
*/
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = ExecuteExtendedBinaryMathOp(interp, *pc, &TCONST(0),
valuePtr, value2Ptr);
if (objResultPtr == DIVIDED_BY_ZERO) {
TRACE_APPEND(("DIVIDE BY ZERO\n"));
goto divideByZero;
} else if (objResultPtr == GENERAL_ARITHMETIC_ERROR) {
TRACE_ERROR(interp);
goto gotError;
} else if (objResultPtr == NULL) {
TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
} else {
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
case INST_EXPON:
case INST_ADD:
case INST_SUB:
case INST_DIV:
case INST_MULT:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
if ((GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
|| IsErroringNaNType(type1)) {
TRACE(("%.20s %.20s => ILLEGAL 1st TYPE %s\n",
O2S(value2Ptr), O2S(valuePtr),
(valuePtr->typePtr? valuePtr->typePtr->name: "null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "left ", pc, valuePtr);
CACHE_STACK_INFO();
goto gotError;
}
#ifdef ACCEPT_NAN
if (type1 == TCL_NUMBER_NAN) {
/*
* NaN first argument -> result is also NaN.
*/
NEXT_INST_F(1, 1, 0);
}
#endif
if ((GetNumberFromObj(NULL, value2Ptr, &ptr2, &type2) != TCL_OK)
|| IsErroringNaNType(type2)) {
TRACE(("%.20s %.20s => ILLEGAL 2nd TYPE %s\n",
O2S(value2Ptr), O2S(valuePtr),
(value2Ptr->typePtr? value2Ptr->typePtr->name: "null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "right ", pc, value2Ptr);
CACHE_STACK_INFO();
goto gotError;
}
#ifdef ACCEPT_NAN
if (type2 == TCL_NUMBER_NAN) {
/*
* NaN second argument -> result is also NaN.
*/
objResultPtr = value2Ptr;
NEXT_INST_F(1, 2, 1);
}
#endif
/*
* Handle Tcl_WideInt arithmetic as best we can without going out to
* an external function.
|
| ︙ | ︙ | |||
6451 6452 6453 6454 6455 6456 6457 6458 6459 |
* wResult have the same sign and there is no overflow anyway.
*/
if (Overflowing(w1, ~w2, wResult)) {
goto overflow;
}
wideResultOfArithmetic:
if (Tcl_IsShared(valuePtr)) {
TclNewIntObj(objResultPtr, wResult);
| > | | | > | > | 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 |
* wResult have the same sign and there is no overflow anyway.
*/
if (Overflowing(w1, ~w2, wResult)) {
goto overflow;
}
wideResultOfArithmetic:
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
if (Tcl_IsShared(valuePtr)) {
TclNewIntObj(objResultPtr, wResult);
TRACE(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
TclSetIntObj(valuePtr, wResult);
TRACE(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
break;
case INST_DIV:
if (w2 == 0) {
TRACE(("%s %s => DIVIDE BY ZERO\n",
O2S(valuePtr), O2S(value2Ptr)));
goto divideByZero;
} else if ((w1 == WIDE_MIN) && (w2 == -1)) {
/*
* Can't represent (-WIDE_MIN) as a Tcl_WideInt.
*/
goto overflow;
|
| ︙ | ︙ | |||
6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 |
/*
* Fall through with INST_EXPON, INST_DIV and large multiplies.
*/
}
overflow:
objResultPtr = ExecuteExtendedBinaryMathOp(interp, *pc, &TCONST(0),
valuePtr, value2Ptr);
if (objResultPtr == DIVIDED_BY_ZERO) {
| > | | | | | | > > < < | > | | | > | | | | | | | | > | | > | | | | < < | | | | | | | | | | | | | | | | > < | | > | | | | | | | | 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 |
/*
* Fall through with INST_EXPON, INST_DIV and large multiplies.
*/
}
overflow:
TRACE(("%s %s => ", O2S(valuePtr), O2S(value2Ptr)));
objResultPtr = ExecuteExtendedBinaryMathOp(interp, *pc, &TCONST(0),
valuePtr, value2Ptr);
if (objResultPtr == DIVIDED_BY_ZERO) {
TRACE_APPEND(("DIVIDE BY ZERO\n"));
goto divideByZero;
} else if (objResultPtr == EXPONENT_OF_ZERO) {
TRACE_APPEND(("EXPONENT OF ZERO\n"));
goto exponOfZero;
} else if (objResultPtr == GENERAL_ARITHMETIC_ERROR) {
TRACE_ERROR(interp);
goto gotError;
} else if (objResultPtr == OUT_OF_MEMORY) {
TRACE_APPEND(("OUT OF MEMORY\n"));
goto outOfMemory;
} else if (objResultPtr == NULL) {
TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 1, 0);
} else {
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
}
case INST_LNOT: {
int b;
valuePtr = OBJ_AT_TOS;
/* TODO - check claim that taking address of b harms performance */
/* TODO - consider optimization search for constants */
if (TclGetBooleanFromObj(NULL, valuePtr, &b) != TCL_OK) {
TRACE(("\"%.20s\" => ERROR: illegal type %s\n", O2S(valuePtr),
(valuePtr->typePtr? valuePtr->typePtr->name : "null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "", pc, valuePtr);
CACHE_STACK_INFO();
goto gotError;
}
/* TODO: Consider peephole opt. */
objResultPtr = TCONST(!b);
TRACE_WITH_OBJ(("%s => ", O2S(valuePtr)), objResultPtr);
NEXT_INST_F(1, 1, 1);
}
case INST_BITNOT:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.20s\" => ", O2S(valuePtr)));
if ((GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
|| (type1==TCL_NUMBER_NAN) || (type1==TCL_NUMBER_DOUBLE)) {
/*
* ... ~$NonInteger => raise an error.
*/
TRACE_APPEND(("ERROR: illegal type %s\n",
(valuePtr->typePtr? valuePtr->typePtr->name : "null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "", pc, valuePtr);
CACHE_STACK_INFO();
goto gotError;
}
if (type1 == TCL_NUMBER_INT) {
w1 = *((const Tcl_WideInt *) ptr1);
if (Tcl_IsShared(valuePtr)) {
TclNewIntObj(objResultPtr, ~w1);
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
}
TclSetIntObj(valuePtr, ~w1);
TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
objResultPtr = ExecuteExtendedUnaryMathOp(*pc, valuePtr);
if (objResultPtr != NULL) {
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_UMINUS:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.20s\" => ", O2S(valuePtr)));
if ((GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK)
|| IsErroringNaNType(type1)) {
TRACE_APPEND(("ERROR: illegal type %s \n",
(valuePtr->typePtr? valuePtr->typePtr->name : "null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "", pc, valuePtr);
CACHE_STACK_INFO();
goto gotError;
}
switch (type1) {
case TCL_NUMBER_NAN:
/* -NaN => NaN */
TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
break;
case TCL_NUMBER_INT:
w1 = *((const Tcl_WideInt *) ptr1);
if (w1 != WIDE_MIN) {
if (Tcl_IsShared(valuePtr)) {
TclNewIntObj(objResultPtr, -w1);
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
}
TclSetIntObj(valuePtr, -w1);
TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
/* FALLTHROUGH */
}
objResultPtr = ExecuteExtendedUnaryMathOp(*pc, valuePtr);
if (objResultPtr != NULL) {
TRACE_APPEND(("%s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
TRACE_APPEND(("%s\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_UPLUS:
case INST_TRY_CVT_TO_NUMERIC:
/*
* Try to convert the topmost stack object to numeric object. This is
* done in order to support [expr]'s policy of interpreting operands
* if at all possible as numbers first, then strings.
*/
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.20s\" => ", O2S(valuePtr)));
if (GetNumberFromObj(NULL, valuePtr, &ptr1, &type1) != TCL_OK) {
if (*pc == INST_UPLUS) {
/*
* ... +$NonNumeric => raise an error.
*/
TRACE_APPEND(("ERROR: illegal type %s\n",
(valuePtr->typePtr? valuePtr->typePtr->name:"null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "", pc, valuePtr);
CACHE_STACK_INFO();
goto gotError;
}
/* ... TryConvertToNumeric($NonNumeric) is acceptable */
TRACE_APPEND(("not numeric\n"));
NEXT_INST_F(1, 0, 0);
}
if (IsErroringNaNType(type1)) {
if (*pc == INST_UPLUS) {
/*
* ... +$NonNumeric => raise an error.
*/
TRACE_APPEND(("ERROR: illegal type %s\n",
(valuePtr->typePtr? valuePtr->typePtr->name:"null")));
DECACHE_STACK_INFO();
IllegalExprOperandType(interp, "", pc, valuePtr);
CACHE_STACK_INFO();
} else {
/*
* Numeric conversion of NaN -> error.
*/
TRACE_APPEND(("ERROR: IEEE floating pt error\n"));
DECACHE_STACK_INFO();
TclExprFloatError(interp, *((const double *) ptr1));
CACHE_STACK_INFO();
}
goto gotError;
}
/*
* Ensure that the numeric value has a string rep the same as the
* formatted version of its internal rep. This is used, e.g., to make
* sure that "expr {0001}" yields "1", not "0001". We implement this
* by _discarding_ the string rep since we know it will be
* regenerated, if needed later, by formatting the internal rep's
* value.
*/
if (valuePtr->bytes == NULL) {
TRACE_APPEND(("numeric, same Tcl_Obj\n"));
NEXT_INST_F(1, 0, 0);
}
if (Tcl_IsShared(valuePtr)) {
/*
* Here we do some surgery within the Tcl_Obj internals. We want
* to copy the internalrep, but not the string, so we temporarily hide
* the string so we do not copy it.
*/
char *savedString = valuePtr->bytes;
valuePtr->bytes = NULL;
objResultPtr = Tcl_DuplicateObj(valuePtr);
valuePtr->bytes = savedString;
TRACE_APPEND(("numeric, new Tcl_Obj\n"));
NEXT_INST_F(1, 1, 1);
}
TclInvalidateStringRep(valuePtr);
TRACE_APPEND(("numeric, same Tcl_Obj\n"));
NEXT_INST_F(1, 0, 0);
}
break;
/*
* End of numeric operator instructions.
* -----------------------------------------------------------------
*/
case INST_TRY_CVT_TO_BOOLEAN:
valuePtr = OBJ_AT_TOS;
if (TclHasInternalRep(valuePtr, &tclBooleanType)) {
objResultPtr = TCONST(1);
} else {
int res = (TclSetBooleanFromAny(NULL, valuePtr) == TCL_OK);
objResultPtr = TCONST(res);
}
TRACE_WITH_OBJ(("\"%.30s\" => ", O2S(valuePtr)), objResultPtr);
NEXT_INST_F(1, 0, 1);
break;
case INST_BREAK:
/*
DECACHE_STACK_INFO();
Tcl_ResetResult(interp);
CACHE_STACK_INFO();
*/
result = TCL_BREAK;
cleanup = 0;
TRACE(("=> BREAK!\n"));
goto processExceptionReturn;
case INST_CONTINUE:
/*
DECACHE_STACK_INFO();
Tcl_ResetResult(interp);
CACHE_STACK_INFO();
*/
result = TCL_CONTINUE;
cleanup = 0;
TRACE(("=> CONTINUE!\n"));
goto processExceptionReturn;
{
ForeachInfo *infoPtr;
Tcl_Obj *listPtr, **elements;
ForeachVarList *varListPtr;
Tcl_Size numLists, listLen, numVars, listTmpDepth;
Tcl_Size iterNum, iterMax, iterTmp;
Tcl_Size varIndex, valIndex, i, j;
case INST_FOREACH_START:
/*
* Initialize the data for the looping construct, pushing the
* corresponding Tcl_Objs to the stack.
*/
opnd = TclGetUInt4AtPtr(pc + 1);
infoPtr = (ForeachInfo *)codePtr->auxDataArrayPtr[opnd].clientData;
numLists = infoPtr->numLists;
TRACE(("%u => ", opnd));
/*
* Compute the number of iterations that will be run: iterMax
*/
iterMax = 0;
listTmpDepth = numLists - 1;
for (i = 0; i < numLists; i++) {
varListPtr = infoPtr->varLists[i];
numVars = varListPtr->numVars;
listPtr = OBJ_AT_DEPTH(listTmpDepth);
DECACHE_STACK_INFO();
if (TclListObjLength(interp, listPtr, &listLen) != TCL_OK) {
CACHE_STACK_INFO();
TRACE_APPEND(("ERROR converting list %" TCL_Z_MODIFIER "d, \"%s\": %s",
i, O2S(listPtr), O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
if (Tcl_IsShared(listPtr)) {
objPtr = TclListObjCopy(NULL, listPtr);
Tcl_IncrRefCount(objPtr);
Tcl_DecrRefCount(listPtr);
OBJ_AT_DEPTH(listTmpDepth) = objPtr;
|
| ︙ | ︙ | |||
6815 6816 6817 6818 6819 6820 6821 | * Store a pointer to the ForeachInfo struct; same dirty trick * as above */ TclNewObj(tmpPtr); tmpPtr->internalRep.twoPtrValue.ptr1 = infoPtr; PUSH_OBJECT(tmpPtr); /* infoPtr object */ | | < | | 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 |
* Store a pointer to the ForeachInfo struct; same dirty trick
* as above
*/
TclNewObj(tmpPtr);
tmpPtr->internalRep.twoPtrValue.ptr1 = infoPtr;
PUSH_OBJECT(tmpPtr); /* infoPtr object */
TRACE_APPEND(("jump to loop step\n"));
/*
* Jump directly to the INST_FOREACH_STEP instruction; the C code just
* falls through.
*/
pc += 5 - infoPtr->loopCtTemp;
case INST_FOREACH_STEP: /* TODO: address abstract list indexing here! */
/*
* "Step" a foreach loop (i.e., begin its next iteration) by assigning
* the next value list element to each loop var.
*/
tmpPtr = OBJ_AT_TOS;
infoPtr = (ForeachInfo *)tmpPtr->internalRep.twoPtrValue.ptr1;
numLists = infoPtr->numLists;
TRACE(("=> "));
tmpPtr = OBJ_AT_DEPTH(1);
iterNum = (size_t)tmpPtr->internalRep.twoPtrValue.ptr1;
iterMax = (size_t)tmpPtr->internalRep.twoPtrValue.ptr2;
/*
* If some list still has a remaining list element iterate one more
|
| ︙ | ︙ | |||
6867 6868 6869 6870 6871 6872 6873 |
listPtr = OBJ_AT_DEPTH(listTmpDepth);
hasAbstractList = TclObjTypeHasProc(listPtr, indexProc) != 0;
DECACHE_STACK_INFO();
if (hasAbstractList) {
status = Tcl_ListObjLength(interp, listPtr, &listLen);
elements = NULL;
} else {
| | | | | | > > > | | | | | | | > > > < > | | < < < < < < < < < < < < < < < < < < < < | | > | | | | > | | > < | > | > < | > < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | | > | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | < | > > > > | | | | | | | < > | | > | < | | | > | | | | | | < | > > > > | | | > | > | 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 |
listPtr = OBJ_AT_DEPTH(listTmpDepth);
hasAbstractList = TclObjTypeHasProc(listPtr, indexProc) != 0;
DECACHE_STACK_INFO();
if (hasAbstractList) {
status = Tcl_ListObjLength(interp, listPtr, &listLen);
elements = NULL;
} else {
status = TclListObjGetElements(
interp, listPtr, &listLen, &elements);
}
if (status != TCL_OK) {
CACHE_STACK_INFO();
goto gotError;
}
CACHE_STACK_INFO();
valIndex = (iterNum * numVars);
for (j = 0; j < numVars; j++) {
if (valIndex >= listLen) {
TclNewObj(valuePtr);
} else {
DECACHE_STACK_INFO();
if (elements) {
valuePtr = elements[valIndex];
} else {
status = Tcl_ListObjIndex(
interp, listPtr, valIndex, &valuePtr);
if (status != TCL_OK) {
/* Could happen for abstract lists */
CACHE_STACK_INFO();
goto gotError;
}
if (valuePtr == NULL) {
/* Permitted for Tcl_LOI to return NULL */
TclNewObj(valuePtr);
}
}
CACHE_STACK_INFO();
}
varIndex = varListPtr->varIndexes[j];
varPtr = LOCAL(varIndex);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
if (TclIsVarDirectWritable(varPtr)) {
value2Ptr = varPtr->value.objPtr;
if (valuePtr != value2Ptr) {
if (value2Ptr != NULL) {
TclDecrRefCount(value2Ptr);
}
varPtr->value.objPtr = valuePtr;
Tcl_IncrRefCount(valuePtr);
}
} else {
DECACHE_STACK_INFO();
if (TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
valuePtr, TCL_LEAVE_ERR_MSG, varIndex)==NULL){
CACHE_STACK_INFO();
TRACE_APPEND(("ERROR init. index temp %" TCL_SIZE_MODIFIER "d: %.30s",
varIndex, O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
CACHE_STACK_INFO();
}
valIndex++;
}
listTmpDepth--;
}
TRACE_APPEND(("jump to loop start\n"));
/* loopCtTemp being 'misused' for storing the jump size */
NEXT_INST_F(infoPtr->loopCtTemp, 0, 0);
}
TRACE_APPEND(("loop has no more iterations\n"));
#ifdef TCL_COMPILE_DEBUG
NEXT_INST_F(1, 0, 0);
#else
/*
* FALL THROUGH
*/
pc++;
#endif
case INST_FOREACH_END:
/* THIS INSTRUCTION IS ONLY CALLED AS A BREAK TARGET */
tmpPtr = OBJ_AT_TOS;
infoPtr = (ForeachInfo *)tmpPtr->internalRep.twoPtrValue.ptr1;
numLists = infoPtr->numLists;
TRACE(("=> loop terminated\n"));
NEXT_INST_V(1, numLists+2, 0);
case INST_LMAP_COLLECT:
/*
* This instruction is only issued by lmap. The stack is:
* - result
* - infoPtr
* - loop counters
* - valLists
* - collecting obj (unshared)
* The instruction lappends the result to the collecting obj.
*/
tmpPtr = OBJ_AT_DEPTH(1);
infoPtr = (ForeachInfo *)tmpPtr->internalRep.twoPtrValue.ptr1;
numLists = infoPtr->numLists;
TRACE_APPEND(("=> appending to list at depth %" TCL_SIZE_MODIFIER "d\n", 3 + numLists));
objPtr = OBJ_AT_DEPTH(3 + numLists);
Tcl_ListObjAppendElement(NULL, objPtr, OBJ_AT_TOS);
NEXT_INST_F(1, 1, 0);
}
break;
case INST_BEGIN_CATCH4:
/*
* Record start of the catch command with exception range index equal
* to the operand. Push the current stack depth onto the special catch
* stack.
*/
*(++catchTop) = (Tcl_Obj *)INT2PTR(CURR_DEPTH);
TRACE(("%u => catchTop=%" TCL_SIZE_MODIFIER "d, stackTop=%" TCL_SIZE_MODIFIER "d\n",
TclGetUInt4AtPtr(pc + 1), (Tcl_Size)(catchTop - initCatchTop - 1),
CURR_DEPTH));
NEXT_INST_F(5, 0, 0);
break;
case INST_END_CATCH:
catchTop--;
DECACHE_STACK_INFO();
Tcl_ResetResult(interp);
CACHE_STACK_INFO();
result = TCL_OK;
TRACE(("=> catchTop=%" TCL_SIZE_MODIFIER "u\n", (Tcl_Size)(catchTop - initCatchTop - 1)));
NEXT_INST_F(1, 0, 0);
break;
case INST_PUSH_RESULT:
objResultPtr = Tcl_GetObjResult(interp);
TRACE_WITH_OBJ(("=> "), objResultPtr);
/*
* See the comments at INST_INVOKE_STK
*/
TclNewObj(objPtr);
Tcl_IncrRefCount(objPtr);
iPtr->objResultPtr = objPtr;
NEXT_INST_F(1, 0, -1);
break;
case INST_PUSH_RETURN_CODE:
TclNewIntObj(objResultPtr, result);
TRACE(("=> %u\n", result));
NEXT_INST_F(1, 0, 1);
break;
case INST_PUSH_RETURN_OPTIONS:
DECACHE_STACK_INFO();
objResultPtr = Tcl_GetReturnOptions(interp, result);
CACHE_STACK_INFO();
TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(1, 0, 1);
break;
case INST_RETURN_CODE_BRANCH: {
int code;
if (TclGetIntFromObj(NULL, OBJ_AT_TOS, &code) != TCL_OK) {
Tcl_Panic("INST_RETURN_CODE_BRANCH: TOS not a return code!");
}
if (code == TCL_OK) {
Tcl_Panic("INST_RETURN_CODE_BRANCH: TOS is TCL_OK!");
}
if (code < TCL_ERROR || code > TCL_CONTINUE) {
code = TCL_CONTINUE + 1;
}
TRACE(("\"%s\" => jump offset %d\n", O2S(OBJ_AT_TOS), 2*code-1));
NEXT_INST_F(2*code-1, 1, 0);
}
/*
* -----------------------------------------------------------------
* Start of dictionary-related instructions.
*/
{
int opnd2, allocateDict, done, allocdict;
Tcl_Size i;
Tcl_Obj *dictPtr, *statePtr, *keyPtr, *listPtr, *varNamePtr, *keysPtr;
Tcl_Obj *emptyPtr, **keyPtrPtr;
Tcl_DictSearch *searchPtr;
DictUpdateInfo *duiPtr;
case INST_DICT_VERIFY: {
Tcl_Size size;
dictPtr = OBJ_AT_TOS;
TRACE(("\"%.30s\" => ", O2S(dictPtr)));
if (Tcl_DictObjSize(interp, dictPtr, &size) != TCL_OK) {
TRACE_APPEND(("ERROR verifying dictionary nature of \"%.30s\": %s\n",
O2S(dictPtr), O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
TRACE_APPEND(("OK\n"));
NEXT_INST_F(1, 1, 0);
}
break;
case INST_DICT_EXISTS: {
int found;
opnd = TclGetUInt4AtPtr(pc + 1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd);
if (opnd > 1) {
dictPtr = TclTraceDictPath(NULL, dictPtr, opnd - 1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_EXISTS);
if (dictPtr == NULL || dictPtr == DICT_PATH_NON_EXISTENT) {
found = 0;
goto afterDictExists;
}
}
if (Tcl_DictObjGet(NULL, dictPtr, OBJ_AT_TOS,
&objResultPtr) == TCL_OK) {
found = (objResultPtr ? 1 : 0);
} else {
found = 0;
}
afterDictExists:
TRACE_APPEND(("%d\n", found));
/*
* The INST_DICT_EXISTS instruction is usually followed by a
* conditional jump, so we can take advantage of this to do some
* peephole optimization (note that we're careful to not close out
* someone doing something else).
*/
JUMP_PEEPHOLE_V(found, 5, opnd + 1);
}
case INST_DICT_GET:
opnd = TclGetUInt4AtPtr(pc + 1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd);
if (opnd > 1) {
dictPtr = TclTraceDictPath(interp, dictPtr, opnd-1,
&OBJ_AT_DEPTH(opnd-1), DICT_PATH_READ);
if (dictPtr == NULL) {
TRACE_WITH_OBJ((
"ERROR tracing dictionary path into \"%.30s\": ",
O2S(OBJ_AT_DEPTH(opnd))),
Tcl_GetObjResult(interp));
goto gotError;
}
}
if (Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS,
&objResultPtr) != TCL_OK) {
TRACE_APPEND(("ERROR reading leaf dictionary key \"%.30s\": %s",
O2S(dictPtr), O2S(Tcl_GetObjResult(interp))));
goto gotError;
}
if (!objResultPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"key \"%s\" not known in dictionary",
TclGetString(OBJ_AT_TOS)));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "DICT",
TclGetString(OBJ_AT_TOS), (char *)NULL);
CACHE_STACK_INFO();
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd + 1, 1);
case INST_DICT_GET_DEF:
opnd = TclGetUInt4AtPtr(pc + 1);
TRACE(("%u => ", opnd));
dictPtr = OBJ_AT_DEPTH(opnd + 1);
if (opnd > 1) {
dictPtr = TclTraceDictPath(interp, dictPtr, opnd - 1,
&OBJ_AT_DEPTH(opnd), DICT_PATH_EXISTS);
if (dictPtr == NULL) {
TRACE_WITH_OBJ((
"ERROR tracing dictionary path into \"%.30s\": ",
O2S(OBJ_AT_DEPTH(opnd + 1))),
Tcl_GetObjResult(interp));
goto gotError;
} else if (dictPtr == DICT_PATH_NON_EXISTENT) {
goto dictGetDefUseDefault;
}
}
if (Tcl_DictObjGet(interp, dictPtr, OBJ_UNDER_TOS,
&objResultPtr) != TCL_OK) {
TRACE_APPEND(("ERROR reading leaf dictionary key \"%.30s\": %s",
O2S(dictPtr), O2S(Tcl_GetObjResult(interp))));
goto gotError;
} else if (!objResultPtr) {
dictGetDefUseDefault:
objResultPtr = OBJ_AT_TOS;
}
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_V(5, opnd+2, 1);
case INST_DICT_SET:
case INST_DICT_UNSET:
case INST_DICT_INCR_IMM:
opnd = TclGetUInt4AtPtr(pc + 1);
opnd2 = TclGetUInt4AtPtr(pc+5);
varPtr = LOCAL(opnd2);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u %u => ", opnd, opnd2));
if (TclIsVarDirectReadable(varPtr)) {
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL, 0,
opnd2);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
TclNewObj(dictPtr);
allocateDict = 1;
} else {
allocateDict = Tcl_IsShared(dictPtr);
if (allocateDict) {
dictPtr = Tcl_DuplicateObj(dictPtr);
}
}
switch (*pc) {
case INST_DICT_SET:
cleanup = opnd + 1;
result = Tcl_DictObjPutKeyList(interp, dictPtr, opnd,
&OBJ_AT_DEPTH(opnd), OBJ_AT_TOS);
break;
case INST_DICT_INCR_IMM:
cleanup = 1;
opnd = TclGetInt4AtPtr(pc + 1);
result = Tcl_DictObjGet(interp, dictPtr, OBJ_AT_TOS, &valuePtr);
if (result != TCL_OK) {
break;
}
if (valuePtr == NULL) {
Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS, Tcl_NewWideIntObj(opnd));
} else {
TclNewIntObj(value2Ptr, opnd);
Tcl_IncrRefCount(value2Ptr);
if (Tcl_IsShared(valuePtr)) {
valuePtr = Tcl_DuplicateObj(valuePtr);
Tcl_DictObjPut(NULL, dictPtr, OBJ_AT_TOS, valuePtr);
}
result = TclIncrObj(interp, valuePtr, value2Ptr);
if (result == TCL_OK) {
TclInvalidateStringRep(dictPtr);
}
TclDecrRefCount(value2Ptr);
}
break;
case INST_DICT_UNSET:
cleanup = opnd;
result = Tcl_DictObjRemoveKeyList(interp, dictPtr, opnd,
&OBJ_AT_DEPTH(opnd-1));
break;
default:
cleanup = 0; /* stop compiler warning */
Tcl_Panic("Should not happen!");
}
if (result != TCL_OK) {
if (allocateDict) {
TclDecrRefCount(dictPtr);
}
TRACE_APPEND(("ERROR updating dictionary: %s\n",
O2S(Tcl_GetObjResult(interp))));
goto checkForCatch;
}
if (TclIsVarDirectWritable(varPtr)) {
if (allocateDict) {
value2Ptr = varPtr->value.objPtr;
Tcl_IncrRefCount(dictPtr);
if (value2Ptr != NULL) {
TclDecrRefCount(value2Ptr);
}
varPtr->value.objPtr = dictPtr;
}
objResultPtr = dictPtr;
} else {
Tcl_IncrRefCount(dictPtr);
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
dictPtr, TCL_LEAVE_ERR_MSG, opnd2);
CACHE_STACK_INFO();
TclDecrRefCount(dictPtr);
if (objResultPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
}
#ifndef TCL_COMPILE_DEBUG
if (pc[9] == INST_POP) {
NEXT_INST_V(10, cleanup, 0);
}
#endif
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_V(9, cleanup, 1);
case INST_DICT_APPEND:
case INST_DICT_LAPPEND:
opnd = TclGetUInt4AtPtr(pc + 1);
varPtr = LOCAL(opnd);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
TRACE(("%u => ", opnd));
if (TclIsVarDirectReadable(varPtr)) {
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL, 0,
opnd);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
TclNewObj(dictPtr);
allocateDict = 1;
} else {
allocateDict = Tcl_IsShared(dictPtr);
if (allocateDict) {
dictPtr = Tcl_DuplicateObj(dictPtr);
}
}
if (Tcl_DictObjGet(interp, dictPtr, OBJ_UNDER_TOS,
&valuePtr) != TCL_OK) {
if (allocateDict) {
TclDecrRefCount(dictPtr);
}
TRACE_ERROR(interp);
goto gotError;
}
/*
* Note that a non-existent key results in a NULL valuePtr, which is a
* case handled separately below. What we *can* say at this point is
|
| ︙ | ︙ | |||
7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 |
/*
* More complex because list-append can fail.
*/
if (valuePtr == NULL) {
Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS,
Tcl_NewListObj(1, &OBJ_AT_TOS));
} else if (Tcl_IsShared(valuePtr)) {
valuePtr = Tcl_DuplicateObj(valuePtr);
if (Tcl_ListObjAppendElement(interp, valuePtr,
OBJ_AT_TOS) != TCL_OK) {
TclDecrRefCount(valuePtr);
| > > | > > | > | | | | | | | 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 |
/*
* More complex because list-append can fail.
*/
if (valuePtr == NULL) {
Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS,
Tcl_NewListObj(1, &OBJ_AT_TOS));
break;
} else if (Tcl_IsShared(valuePtr)) {
valuePtr = Tcl_DuplicateObj(valuePtr);
if (Tcl_ListObjAppendElement(interp, valuePtr,
OBJ_AT_TOS) != TCL_OK) {
TclDecrRefCount(valuePtr);
if (allocateDict) {
TclDecrRefCount(dictPtr);
}
TRACE_ERROR(interp);
goto gotError;
}
Tcl_DictObjPut(NULL, dictPtr, OBJ_UNDER_TOS, valuePtr);
} else {
if (Tcl_ListObjAppendElement(interp, valuePtr,
OBJ_AT_TOS) != TCL_OK) {
if (allocateDict) {
TclDecrRefCount(dictPtr);
}
TRACE_ERROR(interp);
goto gotError;
}
/*
* Must invalidate the string representation of dictionary
* here because we have directly updated the internal
* representation; if we don't, callers could see the wrong
* string rep despite the internal version of the dictionary
* having the correct value. [Bug 3079830]
*/
TclInvalidateStringRep(dictPtr);
}
break;
default:
Tcl_Panic("Should not happen!");
}
if (TclIsVarDirectWritable(varPtr)) {
if (allocateDict) {
value2Ptr = varPtr->value.objPtr;
Tcl_IncrRefCount(dictPtr);
if (value2Ptr != NULL) {
TclDecrRefCount(value2Ptr);
}
varPtr->value.objPtr = dictPtr;
}
objResultPtr = dictPtr;
} else {
Tcl_IncrRefCount(dictPtr);
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
dictPtr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
TclDecrRefCount(dictPtr);
if (objResultPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
}
#ifndef TCL_COMPILE_DEBUG
if (pc[5] == INST_POP) {
NEXT_INST_F(6, 2, 0);
}
#endif
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(5, 2, 1);
case INST_DICT_FIRST:
opnd = TclGetUInt4AtPtr(pc + 1);
TRACE(("%u => ", opnd));
dictPtr = POP_OBJECT();
searchPtr = (Tcl_DictSearch *)Tcl_Alloc(sizeof(Tcl_DictSearch));
if (Tcl_DictObjFirst(interp, dictPtr, searchPtr, &keyPtr,
&valuePtr, &done) != TCL_OK) {
/*
* dictPtr is no longer on the stack, and we're not
* moving it into the internalrep of an iterator. We need
|
| ︙ | ︙ | |||
7516 7517 7518 7519 7520 7521 7522 |
{
Tcl_ObjInternalRep ir;
TclNewObj(statePtr);
ir.twoPtrValue.ptr1 = searchPtr;
ir.twoPtrValue.ptr2 = dictPtr;
Tcl_StoreInternalRep(statePtr, &dictIteratorType, &ir);
}
| < | < | | < | < | | | | | | | > > > | < | > > > | | | | | | | > > > | | | | | | > > > > | 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 |
{
Tcl_ObjInternalRep ir;
TclNewObj(statePtr);
ir.twoPtrValue.ptr1 = searchPtr;
ir.twoPtrValue.ptr2 = dictPtr;
Tcl_StoreInternalRep(statePtr, &dictIteratorType, &ir);
}
varPtr = LOCAL(opnd);
if (varPtr->value.objPtr) {
if (TclHasInternalRep(varPtr->value.objPtr, &dictIteratorType)) {
Tcl_Panic("mis-issued dictFirst!");
}
TclDecrRefCount(varPtr->value.objPtr);
}
varPtr->value.objPtr = statePtr;
Tcl_IncrRefCount(statePtr);
goto pushDictIteratorResult;
case INST_DICT_NEXT:
opnd = TclGetUInt4AtPtr(pc + 1);
TRACE(("%u => ", opnd));
statePtr = (*LOCAL(opnd)).value.objPtr;
{
const Tcl_ObjInternalRep *irPtr;
if (statePtr &&
(irPtr = TclFetchInternalRep(statePtr, &dictIteratorType))) {
searchPtr = (Tcl_DictSearch *)irPtr->twoPtrValue.ptr1;
Tcl_DictObjNext(searchPtr, &keyPtr, &valuePtr, &done);
} else {
Tcl_Panic("mis-issued dictNext!");
}
}
pushDictIteratorResult:
if (done) {
TclNewObj(emptyPtr);
PUSH_OBJECT(emptyPtr);
PUSH_OBJECT(emptyPtr);
} else {
PUSH_OBJECT(valuePtr);
PUSH_OBJECT(keyPtr);
}
TRACE_APPEND(("\"%.30s\" \"%.30s\" %d\n",
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), done));
/*
* The INST_DICT_FIRST and INST_DICT_NEXT instructions are always
* followed by a conditional jump, so we can take advantage of this to
* do some peephole optimization (note that we're careful to not close
* out someone doing something else).
*/
JUMP_PEEPHOLE_F(done, 5, 0);
case INST_DICT_UPDATE_START:
opnd = TclGetUInt4AtPtr(pc + 1);
opnd2 = TclGetUInt4AtPtr(pc + 5);
TRACE(("%u => ", opnd));
varPtr = LOCAL(opnd);
duiPtr = (DictUpdateInfo *)codePtr->auxDataArrayPtr[opnd2].clientData;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
if (TclIsVarDirectReadable(varPtr)) {
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL,
TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (dictPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
}
Tcl_IncrRefCount(dictPtr);
if (TclListObjGetElements(interp, OBJ_AT_TOS, &length,
&keyPtrPtr) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
if (length != duiPtr->length) {
Tcl_Panic("dictUpdateStart argument length mismatch");
}
for (i=0 ; i<length ; i++) {
if (Tcl_DictObjGet(interp, dictPtr, keyPtrPtr[i],
&valuePtr) != TCL_OK) {
TRACE_ERROR(interp);
Tcl_DecrRefCount(dictPtr);
goto gotError;
}
varPtr = LOCAL(duiPtr->varIndices[i]);
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
DECACHE_STACK_INFO();
if (valuePtr == NULL) {
TclObjUnsetVar2(interp,
localName(iPtr->varFramePtr, duiPtr->varIndices[i]),
NULL, 0);
} else if (TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
valuePtr, TCL_LEAVE_ERR_MSG,
duiPtr->varIndices[i]) == NULL) {
CACHE_STACK_INFO();
TRACE_ERROR(interp);
Tcl_DecrRefCount(dictPtr);
goto gotError;
}
CACHE_STACK_INFO();
}
TclDecrRefCount(dictPtr);
TRACE_APPEND(("OK\n"));
NEXT_INST_F(9, 0, 0);
case INST_DICT_UPDATE_END:
opnd = TclGetUInt4AtPtr(pc + 1);
opnd2 = TclGetUInt4AtPtr(pc + 5);
TRACE(("%u => ", opnd));
varPtr = LOCAL(opnd);
duiPtr = (DictUpdateInfo *)codePtr->auxDataArrayPtr[opnd2].clientData;
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
if (TclIsVarDirectReadable(varPtr)) {
dictPtr = varPtr->value.objPtr;
} else {
DECACHE_STACK_INFO();
dictPtr = TclPtrGetVarIdx(interp, varPtr, NULL, NULL, NULL, 0,
opnd);
CACHE_STACK_INFO();
}
if (dictPtr == NULL) {
TRACE_APPEND(("storage was unset\n"));
NEXT_INST_F(9, 1, 0);
}
if (Tcl_DictObjSize(interp, dictPtr, &length) != TCL_OK
|| TclListObjGetElements(interp, OBJ_AT_TOS, &length,
&keyPtrPtr) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
allocdict = Tcl_IsShared(dictPtr);
if (allocdict) {
dictPtr = Tcl_DuplicateObj(dictPtr);
}
if (length > 0) {
TclInvalidateStringRep(dictPtr);
}
for (i=0 ; i<length ; i++) {
Var *var2Ptr = LOCAL(duiPtr->varIndices[i]);
while (TclIsVarLink(var2Ptr)) {
var2Ptr = var2Ptr->value.linkPtr;
}
if (TclIsVarDirectReadable(var2Ptr)) {
valuePtr = var2Ptr->value.objPtr;
} else {
DECACHE_STACK_INFO();
valuePtr = TclPtrGetVarIdx(interp, var2Ptr, NULL, NULL, NULL,
0, duiPtr->varIndices[i]);
CACHE_STACK_INFO();
|
| ︙ | ︙ | |||
7679 7680 7681 7682 7683 7684 7685 |
if (TclIsVarDirectWritable(varPtr)) {
Tcl_IncrRefCount(dictPtr);
TclDecrRefCount(varPtr->value.objPtr);
varPtr->value.objPtr = dictPtr;
} else {
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
| | | | | | | | | | 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 |
if (TclIsVarDirectWritable(varPtr)) {
Tcl_IncrRefCount(dictPtr);
TclDecrRefCount(varPtr->value.objPtr);
varPtr->value.objPtr = dictPtr;
} else {
DECACHE_STACK_INFO();
objResultPtr = TclPtrSetVarIdx(interp, varPtr, NULL, NULL, NULL,
dictPtr, TCL_LEAVE_ERR_MSG, opnd);
CACHE_STACK_INFO();
if (objResultPtr == NULL) {
if (allocdict) {
TclDecrRefCount(dictPtr);
}
TRACE_ERROR(interp);
goto gotError;
}
}
TRACE_APPEND(("written back\n"));
NEXT_INST_F(9, 1, 0);
case INST_DICT_EXPAND:
dictPtr = OBJ_UNDER_TOS;
listPtr = OBJ_AT_TOS;
TRACE(("\"%.30s\" \"%.30s\" =>", O2S(dictPtr), O2S(listPtr)));
if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
objResultPtr = TclDictWithInit(interp, dictPtr, objc, objv);
if (objResultPtr == NULL) {
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("\"%.30s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 2, 1);
case INST_DICT_RECOMBINE_STK:
keysPtr = POP_OBJECT();
varNamePtr = OBJ_UNDER_TOS;
listPtr = OBJ_AT_TOS;
TRACE(("\"%.30s\" \"%.30s\" \"%.30s\" => ",
O2S(varNamePtr), O2S(valuePtr), O2S(keysPtr)));
if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
TRACE_ERROR(interp);
TclDecrRefCount(keysPtr);
goto gotError;
}
varPtr = TclObjLookupVarEx(interp, varNamePtr, NULL,
TCL_LEAVE_ERR_MSG, "set", 1, 1, &arrayPtr);
|
| ︙ | ︙ | |||
7735 7736 7737 7738 7739 7740 7741 |
objc, objv, keysPtr);
CACHE_STACK_INFO();
TclDecrRefCount(keysPtr);
if (result != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
| | | | > | | < > > > | | | > | | < < | | | | | | | | | | < < < < > | > | 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 |
objc, objv, keysPtr);
CACHE_STACK_INFO();
TclDecrRefCount(keysPtr);
if (result != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("OK\n"));
NEXT_INST_F(1, 2, 0);
case INST_DICT_RECOMBINE_IMM:
opnd = TclGetUInt4AtPtr(pc + 1);
listPtr = OBJ_UNDER_TOS;
keysPtr = OBJ_AT_TOS;
varPtr = LOCAL(opnd);
TRACE(("%u <- \"%.30s\" \"%.30s\" => ", opnd, O2S(valuePtr),
O2S(keysPtr)));
if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
while (TclIsVarLink(varPtr)) {
varPtr = varPtr->value.linkPtr;
}
DECACHE_STACK_INFO();
result = TclDictWithFinish(interp, varPtr, NULL, NULL, NULL, opnd,
objc, objv, keysPtr);
CACHE_STACK_INFO();
if (result != TCL_OK) {
TRACE_ERROR(interp);
goto gotError;
}
TRACE_APPEND(("OK\n"));
NEXT_INST_F(5, 2, 0);
}
break;
/*
* End of dictionary-related instructions.
* -----------------------------------------------------------------
*/
case INST_CLOCK_READ: { /* Read the wall clock */
Tcl_WideInt wval;
Tcl_Time now;
switch (TclGetUInt1AtPtr(pc + 1)) {
case 0: /* clicks */
#ifdef TCL_WIDE_CLICKS
wval = TclpGetWideClicks();
#else
wval = (Tcl_WideInt)TclpGetClicks();
#endif
break;
case 1: /* microseconds */
Tcl_GetTime(&now);
wval = (Tcl_WideInt)now.sec * 1000000 + now.usec;
break;
case 2: /* milliseconds */
Tcl_GetTime(&now);
wval = (Tcl_WideInt)now.sec * 1000 + now.usec / 1000;
break;
case 3: /* seconds */
Tcl_GetTime(&now);
wval = (Tcl_WideInt)now.sec;
break;
default:
Tcl_Panic("clockRead instruction with unknown clock#");
break;
}
TclNewIntObj(objResultPtr, wval);
TRACE_WITH_OBJ(("=> "), objResultPtr);
NEXT_INST_F(2, 0, 1);
}
break;
default:
Tcl_Panic("TclNRExecuteByteCode: unrecognized opCode %u", *pc);
} /* end of switch on opCode */
/*
* Block for variables needed to process exception returns.
|
| ︙ | ︙ | |||
7828 7829 7830 7831 7832 7833 7834 |
* something different from TCL_OK, or else INST_BREAK or
* INST_CONTINUE were called.
*/
processExceptionReturn:
#ifdef TCL_COMPILE_DEBUG
switch (*pc) {
| < | | < | | < < < | | | | | | | | | | | | | | | | | | | | | 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 |
* something different from TCL_OK, or else INST_BREAK or
* INST_CONTINUE were called.
*/
processExceptionReturn:
#ifdef TCL_COMPILE_DEBUG
switch (*pc) {
case INST_INVOKE_STK1:
opnd = TclGetUInt1AtPtr(pc + 1);
TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
break;
case INST_INVOKE_STK4:
opnd = TclGetUInt4AtPtr(pc + 1);
TRACE(("%u => ... after \"%.20s\": ", opnd, cmdNameBuf));
break;
case INST_EVAL_STK:
/*
* Note that the object at stacktop has to be used before doing
* the cleanup.
*/
TRACE(("\"%.30s\" => ", O2S(OBJ_AT_TOS)));
break;
default:
TRACE(("=> "));
}
#endif
if ((result == TCL_CONTINUE) || (result == TCL_BREAK)) {
rangePtr = GetExceptRangeForPc(pc, result, codePtr);
if (rangePtr == NULL) {
TRACE_APPEND(("no encl. loop or catch, returning %s\n",
StringForResultCode(result)));
goto abnormalReturn;
}
if (rangePtr->type == CATCH_EXCEPTION_RANGE) {
TRACE_APPEND(("%s ...\n", StringForResultCode(result)));
goto processCatch;
}
while (cleanup--) {
valuePtr = POP_OBJECT();
TclDecrRefCount(valuePtr);
}
if (result == TCL_BREAK) {
result = TCL_OK;
pc = (codePtr->codeStart + rangePtr->breakOffset);
TRACE_APPEND(("%s, range at %" TCL_SIZE_MODIFIER "d, new pc %" TCL_SIZE_MODIFIER "d\n",
StringForResultCode(result),
rangePtr->codeOffset, rangePtr->breakOffset));
NEXT_INST_F(0, 0, 0);
}
if (rangePtr->continueOffset == TCL_INDEX_NONE) {
TRACE_APPEND(("%s, loop w/o continue, checking for catch\n",
StringForResultCode(result)));
goto checkForCatch;
}
result = TCL_OK;
pc = (codePtr->codeStart + rangePtr->continueOffset);
TRACE_APPEND(("%s, range at %" TCL_SIZE_MODIFIER "d, new pc %" TCL_SIZE_MODIFIER "d\n",
StringForResultCode(result),
rangePtr->codeOffset, rangePtr->continueOffset));
NEXT_INST_F(0, 0, 0);
}
#ifdef TCL_COMPILE_DEBUG
if (traceInstructions) {
objPtr = Tcl_GetObjResult(interp);
if ((result != TCL_ERROR) && (result != TCL_RETURN)) {
TRACE_APPEND(("OTHER RETURN CODE %d, result=\"%.30s\"\n ",
result, O2S(objPtr)));
} else {
TRACE_APPEND(("%s, result=\"%.30s\"\n",
StringForResultCode(result), O2S(objPtr)));
}
}
#endif
goto checkForCatch;
/*
* Division by zero in an expression. Control only reaches this point
* by "goto divideByZero".
*/
divideByZero:
Tcl_SetObjResult(interp, Tcl_NewStringObj("divide by zero", -1));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "ARITH", "DIVZERO", "divide by zero", (char *)NULL);
CACHE_STACK_INFO();
goto gotError;
outOfMemory:
Tcl_SetObjResult(interp, Tcl_NewStringObj("out of memory", -1));
DECACHE_STACK_INFO();
Tcl_SetErrorCode(interp, "ARITH", "OUTOFMEMORY", "out of memory", (char *)NULL);
CACHE_STACK_INFO();
goto gotError;
/*
* Exponentiation of zero by negative number in an expression. Control
* only reaches this point by "goto exponOfZero".
*/
|
| ︙ | ︙ | |||
8055 8056 8057 8058 8059 8060 8061 |
processCatch:
while (CURR_DEPTH > PTR2INT(*catchTop)) {
valuePtr = POP_OBJECT();
TclDecrRefCount(valuePtr);
}
#ifdef TCL_COMPILE_DEBUG
if (traceInstructions) {
| | | | | | 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 |
processCatch:
while (CURR_DEPTH > PTR2INT(*catchTop)) {
valuePtr = POP_OBJECT();
TclDecrRefCount(valuePtr);
}
#ifdef TCL_COMPILE_DEBUG
if (traceInstructions) {
fprintf(stdout, " ... found catch at %" TCL_SIZE_MODIFIER "d, catchTop=%" TCL_T_MODIFIER "d, "
"unwound to %" TCL_T_MODIFIER "d, new pc %" TCL_SIZE_MODIFIER "d\n",
rangePtr->codeOffset, (catchTop - initCatchTop - 1),
PTR2INT(*catchTop), rangePtr->catchOffset);
}
#endif
pc = (codePtr->codeStart + rangePtr->catchOffset);
NEXT_INST_F(0, 0, 0); /* Restart the execution loop at pc. */
/*
* end of infinite loop dispatching on instructions.
*/
/*
* Done or abnormal return code. Restore the stack to state it had when
|
| ︙ | ︙ | |||
8093 8094 8095 8096 8097 8098 8099 |
}
while (tosPtr > initTosPtr) {
objPtr = POP_OBJECT();
Tcl_DecrRefCount(objPtr);
}
if (tosPtr < initTosPtr) {
| < | | > | < | | | | | > > > > > > | | | | | | | | | | | | | < | | | | | | > | 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 |
}
while (tosPtr > initTosPtr) {
objPtr = POP_OBJECT();
Tcl_DecrRefCount(objPtr);
}
if (tosPtr < initTosPtr) {
fprintf(stderr,
"\nTclNRExecuteByteCode: abnormal return at pc %" TCL_T_MODIFIER "d: "
"stack top %" TCL_SIZE_MODIFIER "d < entry stack top %d\n",
(pc - codePtr->codeStart),
CURR_DEPTH, 0);
Tcl_Panic("TclNRExecuteByteCode execution failure: end stack top < start stack top");
}
CLANG_ASSERT(bcFramePtr);
}
iPtr->cmdFramePtr = bcFramePtr->nextPtr;
TclReleaseByteCode(codePtr);
TclStackFree(interp, TD); /* free my stack */
return result;
/*
* INST_START_CMD failure case removed where it doesn't bother that much
*
* Remark that if the interpreter is marked for deletion its
* compileEpoch is modified, so that the epoch check also verifies
* that the interp is not deleted. If no outside call has been made
* since the last check, it is safe to omit the check.
* case INST_START_CMD:
*/
instStartCmdFailed:
{
const char *bytes;
Tcl_Size xxx1length;
xxx1length = 0;
if (TclInterpReady(interp) == TCL_ERROR) {
goto gotError;
}
/*
* We used to switch to direct eval; for NRE-awareness we now
* compile and eval the command so that this evaluation does not
* add a new TEBC instance. Bug [2910748], bug [fa6bf38d07]
*
* TODO: recompile, search this command and eval a code starting from,
* so that this evaluation does not add a new TEBC instance without
* NRE-trampoline.
*/
codePtr->flags |= TCL_BYTECODE_RECOMPILE;
bytes = GetSrcInfoForPc(pc, codePtr, &xxx1length, NULL, NULL);
opnd = TclGetUInt4AtPtr(pc + 1);
pc += (opnd-1);
assert(bytes);
PUSH_OBJECT(Tcl_NewStringObj(bytes, xxx1length));
goto instEvalStk;
}
}
#undef codePtr
#undef iPtr
#undef bcFramePtr
#undef initCatchTop
#undef initTosPtr
|
| ︙ | ︙ | |||
8209 8210 8211 8212 8213 8214 8215 |
contextPtr->index = PTR2INT(data[2]);
contextPtr->skip = PTR2INT(data[3]);
contextPtr->oPtr->flags |= FILTER_HANDLING;
return result;
}
/*
| < < | < < | 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 |
contextPtr->index = PTR2INT(data[2]);
contextPtr->skip = PTR2INT(data[3]);
contextPtr->oPtr->flags |= FILTER_HANDLING;
return result;
}
/*
* WidePwrSmallExpon --
*
* Helper to calculate small powers of integers whose result is wide.
*/
static inline Tcl_WideInt
WidePwrSmallExpon(
Tcl_WideInt w1,
long exponent)
{
Tcl_WideInt wResult;
|
| ︙ | ︙ | |||
8299 8300 8301 8302 8303 8304 8305 |
wResult *= wResult; /* b**4 */
wResult *= wResult; /* b**8 */
wResult *= wResult; /* b**16 */
break;
}
return wResult;
}
| < | | 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 |
wResult *= wResult; /* b**4 */
wResult *= wResult; /* b**8 */
wResult *= wResult; /* b**16 */
break;
}
return wResult;
}
/*
*----------------------------------------------------------------------
*
* ExecuteExtendedBinaryMathOp, ExecuteExtendedUnaryMathOp --
*
* These functions do advanced math for binary and unary operators
* respectively, so that the main TEBC code does not bear the cost of
* them.
*
* Results:
* A Tcl_Obj* result, or a NULL (in which case valuePtr is updated to
* hold the result value), or one of the special flag values
* GENERAL_ARITHMETIC_ERROR, EXPONENT_OF_ZERO or DIVIDED_BY_ZERO. The
* latter two signify a zero value raised to a negative power or a value
* divided by zero, respectively. With GENERAL_ARITHMETIC_ERROR, all
* error information will have already been reported in the interpreter
* result.
*
|
| ︙ | ︙ | |||
8334 8335 8336 8337 8338 8339 8340 |
Tcl_Interp *interp, /* Where to report errors. */
int opcode, /* What operation to perform. */
Tcl_Obj **constants, /* The execution environment's constants. */
Tcl_Obj *valuePtr, /* The first operand on the stack. */
Tcl_Obj *value2Ptr) /* The second operand on the stack. */
{
#define WIDE_RESULT(w) \
| | | | | | | | | | | | | | | | | | 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 |
Tcl_Interp *interp, /* Where to report errors. */
int opcode, /* What operation to perform. */
Tcl_Obj **constants, /* The execution environment's constants. */
Tcl_Obj *valuePtr, /* The first operand on the stack. */
Tcl_Obj *value2Ptr) /* The second operand on the stack. */
{
#define WIDE_RESULT(w) \
if (Tcl_IsShared(valuePtr)) { \
return Tcl_NewWideIntObj(w); \
} else { \
TclSetIntObj(valuePtr, (w)); \
return NULL; \
}
#define BIG_RESULT(b) \
if (Tcl_IsShared(valuePtr)) { \
return Tcl_NewBignumObj(b); \
} else { \
Tcl_SetBignumObj(valuePtr, (b)); \
return NULL; \
}
#define DOUBLE_RESULT(d) \
if (Tcl_IsShared(valuePtr)) { \
TclNewDoubleObj(objResultPtr, (d)); \
return objResultPtr; \
} else { \
Tcl_SetDoubleObj(valuePtr, (d)); \
return NULL; \
}
int type1, type2;
void *ptr1, *ptr2;
double d1, d2, dResult;
Tcl_WideInt w1, w2, wResult;
mp_int big1, big2, bigResult, bigRemainder;
|
| ︙ | ︙ | |||
8486 8487 8488 8489 8490 8491 8492 | break; case TCL_NUMBER_BIG: Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2); invalid = mp_isneg(&big2); mp_clear(&big2); break; default: | | > | 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 |
break;
case TCL_NUMBER_BIG:
Tcl_TakeBignumFromObj(NULL, value2Ptr, &big2);
invalid = mp_isneg(&big2);
mp_clear(&big2);
break;
default:
/* Unused, here to silence compiler warning */
invalid = 0;
}
if (invalid) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"negative shift argument", -1));
return GENERAL_ARITHMETIC_ERROR;
}
|
| ︙ | ︙ | |||
8563 8564 8565 8566 8567 8568 8569 | break; case TCL_NUMBER_BIG: Tcl_TakeBignumFromObj(NULL, valuePtr, &big1); zero = !mp_isneg(&big1); mp_clear(&big1); break; default: | | > | 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 |
break;
case TCL_NUMBER_BIG:
Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
zero = !mp_isneg(&big1);
mp_clear(&big1);
break;
default:
/* Unused, here to silence compiler warning. */
zero = 0;
}
if (zero) {
return constants[0];
}
WIDE_RESULT(-1);
}
shift = (int)(*(const Tcl_WideInt *)ptr2);
|
| ︙ | ︙ | |||
8625 8626 8627 8628 8629 8630 8631 | break; case INST_BITOR: err = mp_or(&big1, &big2, &bigResult); break; case INST_BITXOR: err = mp_xor(&big1, &big2, &bigResult); break; | < < | 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 |
break;
case INST_BITOR:
err = mp_or(&big1, &big2, &bigResult);
break;
case INST_BITXOR:
err = mp_xor(&big1, &big2, &bigResult);
break;
}
}
if (err != MP_OKAY) {
return OUT_OF_MEMORY;
}
mp_clear(&big1);
|
| ︙ | ︙ | |||
8652 8653 8654 8655 8656 8657 8658 | case INST_BITOR: wResult = w1 | w2; break; case INST_BITXOR: wResult = w1 ^ w2; break; default: | | > | 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 |
case INST_BITOR:
wResult = w1 | w2;
break;
case INST_BITXOR:
wResult = w1 ^ w2;
break;
default:
/* Unused, here to silence compiler warning. */
wResult = 0;
}
WIDE_RESULT(wResult);
case INST_EXPON: {
int oddExponent = 0, negativeExponent = 0;
unsigned short base;
|
| ︙ | ︙ | |||
8712 8713 8714 8715 8716 8717 8718 |
*/
return EXPONENT_OF_ZERO;
case -1:
if (oddExponent) {
WIDE_RESULT(-1);
}
| < > > | | | | | | | | | | | | | | | | 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 |
*/
return EXPONENT_OF_ZERO;
case -1:
if (oddExponent) {
WIDE_RESULT(-1);
}
/* fallthrough */
case 1:
/*
* 1 to any power is 1.
*/
return constants[1];
}
}
}
if (negativeExponent) {
/*
* Integers with magnitude greater than 1 raise to a negative
* power yield the answer zero (see TIP 123).
*/
return constants[0];
}
if (type1 != TCL_NUMBER_INT) {
goto overflowExpon;
}
switch (w1) {
case 0:
/*
* Zero to a positive power is zero.
*/
return constants[0];
case 1:
/*
* 1 to any power is 1.
*/
return constants[1];
case -1:
if (!oddExponent) {
return constants[1];
}
WIDE_RESULT(-1);
}
/*
* We refuse to accept exponent arguments that exceed one mp_digit
* which means the max exponent value is 2**28-1 = 0x0FFFFFFF =
* 268435455, which fits into a signed 32 bit int which is within the
* range of the Tcl_WideInt type. This means any numeric Tcl_Obj value
|
| ︙ | ︙ | |||
8899 8900 8901 8902 8903 8904 8905 | * we're on an IEEE box. Otherwise, this statement might cause * demons to fly out our noses. */ dResult = d1 / d2; break; default: | | > | 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 | * we're on an IEEE box. Otherwise, this statement might cause * demons to fly out our noses. */ dResult = d1 / d2; break; default: /* Unused, here to silence compiler warning. */ dResult = 0; } doubleResult: #ifndef ACCEPT_NAN /* * Check now for IEEE floating-point error. */ |
| ︙ | ︙ | |||
8987 8988 8989 8990 8991 8992 8993 |
((w1 < 0 && w2 > 0) || (w1 > 0 && w2 < 0)))) &&
(wResult*w2 != w1)) {
wResult -= 1;
}
break;
default:
| > > > | > | 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 |
((w1 < 0 && w2 > 0) || (w1 > 0 && w2 < 0)))) &&
(wResult*w2 != w1)) {
wResult -= 1;
}
break;
default:
/*
* Unused, here to silence compiler warning.
*/
wResult = 0;
}
WIDE_RESULT(wResult);
}
overflowBasic:
Tcl_TakeBignumFromObj(NULL, valuePtr, &big1);
|
| ︙ | ︙ | |||
9038 9039 9040 9041 9042 9043 9044 | mp_clear(&bigRemainder); break; } } mp_clear(&big1); mp_clear(&big2); BIG_RESULT(&bigResult); | > | | < < > | 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 |
mp_clear(&bigRemainder);
break;
}
}
mp_clear(&big1);
mp_clear(&big2);
BIG_RESULT(&bigResult);
}
Tcl_Panic("unexpected opcode");
return NULL;
}
static Tcl_Obj *
ExecuteExtendedUnaryMathOp(
int opcode, /* What operation to perform. */
Tcl_Obj *valuePtr) /* The operand on the stack. */
{
|
| ︙ | ︙ | |||
9096 9097 9098 9099 9100 9101 9102 |
Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
}
err = mp_neg(&big, &big);
if (err != MP_OKAY) {
return OUT_OF_MEMORY;
}
BIG_RESULT(&big);
| > | | < < > | 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 |
Tcl_TakeBignumFromObj(NULL, valuePtr, &big);
}
err = mp_neg(&big, &big);
if (err != MP_OKAY) {
return OUT_OF_MEMORY;
}
BIG_RESULT(&big);
}
Tcl_Panic("unexpected opcode");
return NULL;
}
#undef WIDE_RESULT
#undef BIG_RESULT
#undef DOUBLE_RESULT
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
9189 9190 9191 9192 9193 9194 9195 |
bp2 = (const mp_int *)ptr2;
if (mp_isneg(bp2)) {
compare = MP_GT;
} else {
compare = MP_LT;
}
return compare;
| < < > | 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 |
bp2 = (const mp_int *)ptr2;
if (mp_isneg(bp2)) {
compare = MP_GT;
} else {
compare = MP_LT;
}
return compare;
}
break;
case TCL_NUMBER_DOUBLE:
d1 = *((const double *)ptr1);
switch (type2) {
case TCL_NUMBER_DOUBLE:
d2 = *((const double *)ptr2);
doubleCompare:
|
| ︙ | ︙ | |||
9236 9237 9238 9239 9240 9241 9242 |
&& modf(d1, &tmp) != 0.0) {
d2 = TclBignumToDouble(bp2);
goto doubleCompare;
}
Tcl_InitBignumFromDouble(NULL, d1, &blx);
bp1 = &blx;
goto bigCompare;
| < < > | 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 |
&& modf(d1, &tmp) != 0.0) {
d2 = TclBignumToDouble(bp2);
goto doubleCompare;
}
Tcl_InitBignumFromDouble(NULL, d1, &blx);
bp1 = &blx;
goto bigCompare;
}
break;
case TCL_NUMBER_BIG: {
mp_int bl;
if (ptr1 != ptr2) { /* 2nd call of GetNumberFromObj got not a bignum */
bp1 = (const mp_int *)ptr1;
} else { /* both pointers points to same place, so TSD is overwritten */
TclUnpackBignum(valuePtr, bl);
|
| ︙ | ︙ | |||
9274 9275 9276 9277 9278 9279 9280 | Tcl_InitBignumFromDouble(NULL, d2, &blx); bp2 = &blx; goto bigCompare; case TCL_NUMBER_BIG: bp2 = (const mp_int *)ptr2; bigCompare: compare = mp_cmp(bp1, bp2); | | < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 |
Tcl_InitBignumFromDouble(NULL, d2, &blx);
bp2 = &blx;
goto bigCompare;
case TCL_NUMBER_BIG:
bp2 = (const mp_int *)ptr2;
bigCompare:
compare = mp_cmp(bp1, bp2);
if (bp1 == &blx || bp2 == &blx) { mp_clear(&blx); }
return compare;
}
break;
}
default:
Tcl_Panic("unexpected number type");
}
return TCL_ERROR;
}
#ifdef TCL_COMPILE_DEBUG
/*
*----------------------------------------------------------------------
*
* PrintByteCodeInfo --
*
|
| ︙ | ︙ | |||
9467 9468 9469 9470 9471 9472 9473 |
ByteCode *codePtr) /* The bytecode whose summary is printed to
* stdout. */
{
Proc *procPtr = codePtr->procPtr;
Interp *iPtr = (Interp *) *codePtr->interpHandle;
fprintf(stdout,
| | | > | > | | | | > | | | | 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 |
ByteCode *codePtr) /* The bytecode whose summary is printed to
* stdout. */
{
Proc *procPtr = codePtr->procPtr;
Interp *iPtr = (Interp *) *codePtr->interpHandle;
fprintf(stdout,
"\nExecuting ByteCode 0x%p, refCt %" TCL_Z_MODIFIER
"u, epoch %" TCL_Z_MODIFIER "u, interp 0x%p (epoch %"
TCL_Z_MODIFIER "u)\n",
codePtr, codePtr->refCount, codePtr->compileEpoch, iPtr,
iPtr->compileEpoch);
fprintf(stdout, " Source: ");
TclPrintSource(stdout, codePtr->source, 60);
fprintf(stdout,
"\n Cmds %" TCL_Z_MODIFIER "u, src %" TCL_Z_MODIFIER
"u, inst %" TCL_Z_MODIFIER "u, litObjs %" TCL_Z_MODIFIER
"u, aux %" TCL_Z_MODIFIER "u, stkDepth %" TCL_Z_MODIFIER
"u, code/src %.2f\n",
codePtr->numCommands, codePtr->numSrcBytes,
codePtr->numCodeBytes, codePtr->numLitObjects,
codePtr->numAuxDataItems, codePtr->maxStackDepth,
#ifdef TCL_COMPILE_STATS
codePtr->numSrcBytes?
((float)codePtr->structureSize)/codePtr->numSrcBytes :
#endif
0.0);
#ifdef TCL_COMPILE_STATS
fprintf(stdout,
" Code %" TCL_Z_MODIFIER "u = header %" TCL_Z_MODIFIER
"u+inst %" TCL_Z_MODIFIER "u+litObj %" TCL_Z_MODIFIER
"u+exc %" TCL_Z_MODIFIER "u+aux %" TCL_Z_MODIFIER
"u+cmdMap %" TCL_Z_MODIFIER "u\n",
codePtr->structureSize,
offsetof(ByteCode, localCachePtr),
codePtr->numCodeBytes,
codePtr->numLitObjects * sizeof(Tcl_Obj *),
codePtr->numExceptRanges*sizeof(ExceptionRange),
codePtr->numAuxDataItems * sizeof(AuxData),
codePtr->numCmdLocBytes);
#endif /* TCL_COMPILE_STATS */
if (procPtr != NULL) {
fprintf(stdout,
" Proc 0x%p, refCt %" TCL_Z_MODIFIER "u, args %"
TCL_Z_MODIFIER "u, compiled locals %" TCL_Z_MODIFIER "u\n",
procPtr, procPtr->refCount, procPtr->numArgs,
procPtr->numCompiledLocals);
}
}
#endif /* TCL_COMPILE_DEBUG */
/*
|
| ︙ | ︙ | |||
9544 9545 9546 9547 9548 9549 9550 |
* stackLowerBound and stackUpperBound
* (inclusive). */
int checkStack) /* 0 if the stack depth check should be
* skipped. */
{
size_t stackUpperBound = codePtr->maxStackDepth;
/* Greatest legal value for stackTop. */
| | | | | | 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 |
* stackLowerBound and stackUpperBound
* (inclusive). */
int checkStack) /* 0 if the stack depth check should be
* skipped. */
{
size_t stackUpperBound = codePtr->maxStackDepth;
/* Greatest legal value for stackTop. */
size_t relativePc = (size_t)(pc - codePtr->codeStart);
size_t codeStart = (size_t)codePtr->codeStart;
size_t codeEnd = (size_t)
(codePtr->codeStart + codePtr->numCodeBytes);
unsigned char opCode = *pc;
if ((PTR2UINT(pc) < codeStart) || (PTR2UINT(pc) > codeEnd)) {
fprintf(stderr, "\nBad instruction pc 0x%p in TclNRExecuteByteCode\n",
pc);
Tcl_Panic("TclNRExecuteByteCode execution failure: bad pc");
}
if (opCode >= LAST_INST_OPCODE) {
fprintf(stderr, "\nBad opcode %u at pc %" TCL_Z_MODIFIER "u in TclNRExecuteByteCode\n",
opCode, relativePc);
Tcl_Panic("TclNRExecuteByteCode execution failure: bad opcode");
}
if (checkStack && (stackTop > stackUpperBound)) {
Tcl_Size numChars;
const char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars, NULL, NULL);
fprintf(stderr, "\nBad stack top %" TCL_Z_MODIFIER "u at pc %" TCL_Z_MODIFIER "u in "
"TclNRExecuteByteCode (min 0, max %" TCL_Z_MODIFIER "u)",
stackTop, relativePc, stackUpperBound);
if (cmd != NULL) {
Tcl_Obj *message;
TclNewLiteralStringObj(message, "\n executing ");
Tcl_IncrRefCount(message);
Tcl_AppendLimitedToObj(message, cmd, numChars, 100, NULL);
|
| ︙ | ︙ | |||
9686 9687 9688 9689 9690 9691 9692 |
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclGetSourceFromFrame(
CmdFrame *cfPtr,
Tcl_Size objc,
| | | 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 |
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclGetSourceFromFrame(
CmdFrame *cfPtr,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
if (cfPtr == NULL) {
return Tcl_NewListObj(objc, objv);
}
if (cfPtr->cmdObj == NULL) {
if (cfPtr->cmd == NULL) {
ByteCode *codePtr = (ByteCode *)cfPtr->data.tebc.codePtr;
|
| ︙ | ︙ | |||
9788 9789 9790 9791 9792 9793 9794 |
const unsigned char **pcBeg,/* If non-NULL, the bytecode location
* where the current instruction starts.
* If NULL; no pointer is stored. */
Tcl_Size *cmdIdxPtr) /* If non-NULL, the location where the index
* of the command containing the pc should
* be stored. */
{
| | | 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 |
const unsigned char **pcBeg,/* If non-NULL, the bytecode location
* where the current instruction starts.
* If NULL; no pointer is stored. */
Tcl_Size *cmdIdxPtr) /* If non-NULL, the location where the index
* of the command containing the pc should
* be stored. */
{
Tcl_Size pcOffset = pc - codePtr->codeStart;
Tcl_Size numCmds = codePtr->numCommands;
unsigned char *codeDeltaNext, *codeLengthNext;
unsigned char *srcDeltaNext, *srcLengthNext;
Tcl_Size codeOffset, codeLen, codeEnd, srcOffset, srcLen, delta, i;
Tcl_Size bestDist = TCL_SIZE_MAX; /* Distance of pc to best cmd's start pc. */
Tcl_Size bestSrcOffset = -1; /* Initialized to avoid compiler warning. */
Tcl_Size bestSrcLength = -1; /* Initialized to avoid compiler warning. */
|
| ︙ | ︙ | |||
9942 9943 9944 9945 9946 9947 9948 |
* point or a catch range. */
ByteCode *codePtr) /* Points to the ByteCode in which to search
* for the enclosing ExceptionRange. */
{
ExceptionRange *rangeArrayPtr;
size_t numRanges = codePtr->numExceptRanges;
ExceptionRange *rangePtr;
| | | 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 |
* point or a catch range. */
ByteCode *codePtr) /* Points to the ByteCode in which to search
* for the enclosing ExceptionRange. */
{
ExceptionRange *rangeArrayPtr;
size_t numRanges = codePtr->numExceptRanges;
ExceptionRange *rangePtr;
size_t pcOffset = pc - codePtr->codeStart;
size_t start;
if (numRanges == 0) {
return NULL;
}
/*
|
| ︙ | ︙ | |||
10106 10107 10108 10109 10110 10111 10112 |
*----------------------------------------------------------------------
*/
static int
EvalStatsCmd(
TCL_UNUSED(void *), /* Unused. */
Tcl_Interp *interp, /* The current interpreter. */
| | | | 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 |
*----------------------------------------------------------------------
*/
static int
EvalStatsCmd(
TCL_UNUSED(void *), /* Unused. */
Tcl_Interp *interp, /* The current interpreter. */
int objc, /* The number of arguments. */
Tcl_Obj *const objv[]) /* The argument strings. */
{
Interp *iPtr = (Interp *) interp;
LiteralTable *globalTablePtr = &iPtr->literalTable;
ByteCodeStats *statsPtr = &iPtr->stats;
double totalCodeBytes, currentCodeBytes;
double totalLiteralBytes, currentLiteralBytes;
double objBytesIfUnshared, strBytesIfUnshared, sharingBytesSaved;
|
| ︙ | ︙ | |||
10166 10167 10168 10169 10170 10171 10172 |
*/
Tcl_AppendPrintfToObj(objPtr, "\n----------------------------------------------------------------\n");
Tcl_AppendPrintfToObj(objPtr,
"Compilation and execution statistics for interpreter %p\n",
iPtr);
| | | | | | | | | | | | | | 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 |
*/
Tcl_AppendPrintfToObj(objPtr, "\n----------------------------------------------------------------\n");
Tcl_AppendPrintfToObj(objPtr,
"Compilation and execution statistics for interpreter %p\n",
iPtr);
Tcl_AppendPrintfToObj(objPtr, "\nNumber ByteCodes executed\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numExecutions);
Tcl_AppendPrintfToObj(objPtr, "Number ByteCodes compiled\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, " Mean executions/compile\t%.1f\n",
statsPtr->numExecutions / (float)statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, "\nInstructions executed\t\t%.0f\n",
numInstructions);
Tcl_AppendPrintfToObj(objPtr, " Mean inst/compile\t\t%.0f\n",
numInstructions / statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, " Mean inst/execution\t\t%.0f\n",
numInstructions / statsPtr->numExecutions);
Tcl_AppendPrintfToObj(objPtr, "\nTotal ByteCodes\t\t\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, " Source bytes\t\t\t%.6g\n",
statsPtr->totalSrcBytes);
Tcl_AppendPrintfToObj(objPtr, " Code bytes\t\t\t%.6g\n",
totalCodeBytes);
Tcl_AppendPrintfToObj(objPtr, " ByteCode bytes\t\t%.6g\n",
statsPtr->totalByteCodeBytes);
Tcl_AppendPrintfToObj(objPtr, " Literal bytes\t\t%.6g\n",
totalLiteralBytes);
Tcl_AppendPrintfToObj(objPtr, " table %" TCL_Z_MODIFIER "u + bkts %" TCL_Z_MODIFIER
"u + entries %" TCL_Z_MODIFIER "u + objects %" TCL_Z_MODIFIER "u + strings %.6g\n",
sizeof(LiteralTable),
iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
statsPtr->numLiteralsCreated * sizeof(LiteralEntry),
statsPtr->numLiteralsCreated * sizeof(Tcl_Obj),
statsPtr->totalLitStringBytes);
Tcl_AppendPrintfToObj(objPtr, " Mean code/compile\t\t%.1f\n",
totalCodeBytes / statsPtr->numCompilations);
Tcl_AppendPrintfToObj(objPtr, " Mean code/source\t\t%.1f\n",
totalCodeBytes / statsPtr->totalSrcBytes);
Tcl_AppendPrintfToObj(objPtr, "\nCurrent (active) ByteCodes\t%" TCL_Z_MODIFIER "u\n",
numCurrentByteCodes);
Tcl_AppendPrintfToObj(objPtr, " Source bytes\t\t\t%.6g\n",
statsPtr->currentSrcBytes);
Tcl_AppendPrintfToObj(objPtr, " Code bytes\t\t\t%.6g\n",
currentCodeBytes);
Tcl_AppendPrintfToObj(objPtr, " ByteCode bytes\t\t%.6g\n",
statsPtr->currentByteCodeBytes);
Tcl_AppendPrintfToObj(objPtr, " Literal bytes\t\t%.6g\n",
currentLiteralBytes);
Tcl_AppendPrintfToObj(objPtr, " table %" TCL_Z_MODIFIER "u + bkts %" TCL_Z_MODIFIER
"u + entries %" TCL_Z_MODIFIER "u + objects %" TCL_Z_MODIFIER "u + strings %.6g\n",
sizeof(LiteralTable),
iPtr->literalTable.numBuckets * sizeof(LiteralEntry *),
iPtr->literalTable.numEntries * sizeof(LiteralEntry),
iPtr->literalTable.numEntries * sizeof(Tcl_Obj),
statsPtr->currentLitStringBytes);
Tcl_AppendPrintfToObj(objPtr, " Mean code/source\t\t%.1f\n",
currentCodeBytes / statsPtr->currentSrcBytes);
Tcl_AppendPrintfToObj(objPtr, " Code + source bytes\t\t%.6g (%0.1f mean code/src)\n",
(currentCodeBytes + statsPtr->currentSrcBytes),
(currentCodeBytes / statsPtr->currentSrcBytes) + 1.0);
/*
* Tcl_IsShared statistics check
*
* This gives the refcount of each obj as Tcl_IsShared was called for it.
* Shared objects must be duplicated before they can be modified.
*/
numSharedMultX = 0;
Tcl_AppendPrintfToObj(objPtr, "\nTcl_IsShared object check (all objects):\n");
Tcl_AppendPrintfToObj(objPtr, " Object had refcount <=1 (not shared)\t%" TCL_Z_MODIFIER "u\n",
tclObjsShared[1]);
for (i = 2; i < TCL_MAX_SHARED_OBJ_STATS; i++) {
Tcl_AppendPrintfToObj(objPtr, " refcount ==%" TCL_SIZE_MODIFIER "d\t\t%" TCL_Z_MODIFIER "u\n",
i, tclObjsShared[i]);
numSharedMultX += tclObjsShared[i];
}
Tcl_AppendPrintfToObj(objPtr, " refcount >=%" TCL_SIZE_MODIFIER "d\t\t%" TCL_Z_MODIFIER "u\n",
i, tclObjsShared[0]);
numSharedMultX += tclObjsShared[0];
Tcl_AppendPrintfToObj(objPtr, " Total shared objects\t\t\t%" TCL_Z_MODIFIER "u\n",
numSharedMultX);
/*
* Literal table statistics.
*/
numByteCodeLits = 0;
|
| ︙ | ︙ | |||
10281 10282 10283 10284 10285 10286 10287 |
strBytesSharedOnce += (length + 1);
}
}
}
sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
- currentLiteralBytes;
| | | | | | | | 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 |
strBytesSharedOnce += (length + 1);
}
}
}
sharingBytesSaved = (objBytesIfUnshared + strBytesIfUnshared)
- currentLiteralBytes;
Tcl_AppendPrintfToObj(objPtr, "\nTotal objects (all interps)\t%" TCL_Z_MODIFIER "u\n",
tclObjsAlloced);
Tcl_AppendPrintfToObj(objPtr, "Current objects\t\t\t%" TCL_Z_MODIFIER "u\n",
(tclObjsAlloced - tclObjsFreed));
Tcl_AppendPrintfToObj(objPtr, "Total literal objects\t\t%" TCL_Z_MODIFIER "u\n",
statsPtr->numLiteralsCreated);
Tcl_AppendPrintfToObj(objPtr, "\nCurrent literal objects\t\t%" TCL_Z_MODIFIER "u (%0.1f%% of current objects)\n",
globalTablePtr->numEntries,
Percent(globalTablePtr->numEntries, tclObjsAlloced-tclObjsFreed));
Tcl_AppendPrintfToObj(objPtr, " ByteCode literals\t\t%" TCL_Z_MODIFIER "u (%0.1f%% of current literals)\n",
numByteCodeLits,
Percent(numByteCodeLits, globalTablePtr->numEntries));
Tcl_AppendPrintfToObj(objPtr, " Literals reused > 1x\t\t%" TCL_Z_MODIFIER "u\n",
numSharedMultX);
Tcl_AppendPrintfToObj(objPtr, " Mean reference count\t\t%.2f\n",
((double) refCountSum) / globalTablePtr->numEntries);
Tcl_AppendPrintfToObj(objPtr, " Mean len, str reused >1x \t%.2f\n",
(numSharedMultX ? strBytesSharedMultX/numSharedMultX : 0.0));
Tcl_AppendPrintfToObj(objPtr, " Mean len, str used 1x\t\t%.2f\n",
(numSharedOnce ? strBytesSharedOnce/numSharedOnce : 0.0));
|
| ︙ | ︙ | |||
10319 10320 10321 10322 10323 10324 10325 |
statsPtr->currentLitStringBytes);
Tcl_AppendPrintfToObj(objPtr, " Bytes if no sharing\t\t%.6g = objects %.6g + strings %.6g\n",
(objBytesIfUnshared + strBytesIfUnshared),
objBytesIfUnshared, strBytesIfUnshared);
Tcl_AppendPrintfToObj(objPtr, " String sharing savings \t%.6g = unshared %.6g - shared %.6g\n",
(strBytesIfUnshared - statsPtr->currentLitStringBytes),
strBytesIfUnshared, statsPtr->currentLitStringBytes);
| | | 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 |
statsPtr->currentLitStringBytes);
Tcl_AppendPrintfToObj(objPtr, " Bytes if no sharing\t\t%.6g = objects %.6g + strings %.6g\n",
(objBytesIfUnshared + strBytesIfUnshared),
objBytesIfUnshared, strBytesIfUnshared);
Tcl_AppendPrintfToObj(objPtr, " String sharing savings \t%.6g = unshared %.6g - shared %.6g\n",
(strBytesIfUnshared - statsPtr->currentLitStringBytes),
strBytesIfUnshared, statsPtr->currentLitStringBytes);
Tcl_AppendPrintfToObj(objPtr, " Literal mgmt overhead\t\t%" TCL_Z_MODIFIER "u (%0.1f%% of bytes with sharing)\n",
literalMgmtBytes,
Percent(literalMgmtBytes, currentLiteralBytes));
Tcl_AppendPrintfToObj(objPtr, " table %lu + buckets %lu + entries %lu\n",
(unsigned long) sizeof(LiteralTable),
(unsigned long) (iPtr->literalTable.numBuckets * sizeof(LiteralEntry *)),
(unsigned long) (iPtr->literalTable.numEntries * sizeof(LiteralEntry)));
|
| ︙ | ︙ | |||
10380 10381 10382 10383 10384 10385 10386 |
break;
}
}
sum = 0;
for (ui = 0; ui <= maxSizeDecade; ui++) {
decadeHigh = (1 << (ui + 1)) - 1;
sum += statsPtr->literalCount[ui];
| | | 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 |
break;
}
}
sum = 0;
for (ui = 0; ui <= maxSizeDecade; ui++) {
decadeHigh = (1 << (ui + 1)) - 1;
sum += statsPtr->literalCount[ui];
Tcl_AppendPrintfToObj(objPtr, "\t%10" TCL_Z_MODIFIER "u\t\t%8.0f%%\n",
decadeHigh, Percent(sum, statsPtr->numLiteralsCreated));
}
litTableStats = TclLiteralStats(globalTablePtr);
Tcl_AppendPrintfToObj(objPtr, "\nCurrent literal table statistics:\n%s\n",
litTableStats);
Tcl_Free(litTableStats);
|
| ︙ | ︙ | |||
10413 10414 10415 10416 10417 10418 10419 |
}
}
maxSizeDecade = i;
sum = 0;
for (ui = minSizeDecade; ui <= maxSizeDecade; ui++) {
decadeHigh = (1 << (ui + 1)) - 1;
sum += statsPtr->srcCount[ui];
| | | 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 9884 9885 9886 9887 |
}
}
maxSizeDecade = i;
sum = 0;
for (ui = minSizeDecade; ui <= maxSizeDecade; ui++) {
decadeHigh = (1 << (ui + 1)) - 1;
sum += statsPtr->srcCount[ui];
Tcl_AppendPrintfToObj(objPtr, "\t%10" TCL_Z_MODIFIER "u\t\t%8.0f%%\n",
decadeHigh, Percent(sum, statsPtr->numCompilations));
}
Tcl_AppendPrintfToObj(objPtr, "\nByteCode sizes:\n");
Tcl_AppendPrintfToObj(objPtr, "\t Up to size\t\tPercentage\n");
minSizeDecade = maxSizeDecade = 0;
for (i = 0; i < 31; i++) {
|
| ︙ | ︙ | |||
10437 10438 10439 10440 10441 10442 10443 |
}
}
maxSizeDecade = i;
sum = 0;
for (ui = minSizeDecade; ui <= maxSizeDecade; ui++) {
decadeHigh = (1 << (ui + 1)) - 1;
sum += statsPtr->byteCodeCount[ui];
| | | 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 |
}
}
maxSizeDecade = i;
sum = 0;
for (ui = minSizeDecade; ui <= maxSizeDecade; ui++) {
decadeHigh = (1 << (ui + 1)) - 1;
sum += statsPtr->byteCodeCount[ui];
Tcl_AppendPrintfToObj(objPtr, "\t%10" TCL_Z_MODIFIER "u\t\t%8.0f%%\n",
decadeHigh, Percent(sum, statsPtr->numCompilations));
}
Tcl_AppendPrintfToObj(objPtr, "\nByteCode longevity (excludes Current ByteCodes):\n");
Tcl_AppendPrintfToObj(objPtr, "\t Up to ms\t\tPercentage\n");
minSizeDecade = maxSizeDecade = 0;
for (i = 0; i < 31; i++) {
|
| ︙ | ︙ | |||
10471 10472 10473 10474 10475 10476 10477 |
/*
* Instruction counts.
*/
Tcl_AppendPrintfToObj(objPtr, "\nInstruction counts:\n");
for (i = 0; i < LAST_INST_OPCODE; i++) {
| | | 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 |
/*
* Instruction counts.
*/
Tcl_AppendPrintfToObj(objPtr, "\nInstruction counts:\n");
for (i = 0; i < LAST_INST_OPCODE; i++) {
Tcl_AppendPrintfToObj(objPtr, "%20s %8" TCL_Z_MODIFIER "u ",
tclInstructionTable[i].name, statsPtr->instructionCount[i]);
if (statsPtr->instructionCount[i]) {
Tcl_AppendPrintfToObj(objPtr, "%6.1f%%\n",
Percent(statsPtr->instructionCount[i], numInstructions));
} else {
Tcl_AppendPrintfToObj(objPtr, "0\n");
}
|
| ︙ | ︙ |
Changes to generic/tclFCmd.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 | */ static int CopyRenameOneFile(Tcl_Interp *interp, Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, int copyFlag, int force); static Tcl_Obj * FileBasename(Tcl_Interp *interp, Tcl_Obj *pathPtr); static int FileCopyRename(Tcl_Interp *interp, | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | */ static int CopyRenameOneFile(Tcl_Interp *interp, Tcl_Obj *srcPathPtr, Tcl_Obj *destPathPtr, int copyFlag, int force); static Tcl_Obj * FileBasename(Tcl_Interp *interp, Tcl_Obj *pathPtr); static int FileCopyRename(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int copyFlag); static int FileForceOption(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int *forcePtr); /* *--------------------------------------------------------------------------- * * TclFileRenameCmd * * This function implements the "rename" subcommand of the "file" |
| ︙ | ︙ | |||
74 75 76 77 78 79 80 |
*/
int
TclFileRenameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interp for error reporting or recursive
* calls in the case of a tricky rename. */
| | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
*/
int
TclFileRenameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interp for error reporting or recursive
* calls in the case of a tricky rename. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument strings passed to Tcl_FileCmd. */
{
return FileCopyRename(interp, objc, objv, 0);
}
/*
*---------------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
103 104 105 106 107 108 109 |
*/
int
TclFileCopyCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Used for error reporting or recursive calls
* in the case of a tricky copy. */
| | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
*/
int
TclFileCopyCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Used for error reporting or recursive calls
* in the case of a tricky copy. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument strings passed to Tcl_FileCmd. */
{
return FileCopyRename(interp, objc, objv, 1);
}
/*
*---------------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
129 130 131 132 133 134 135 |
*
*---------------------------------------------------------------------------
*/
static int
FileCopyRename(
Tcl_Interp *interp, /* Used for error reporting. */
| | | | < > | > | > > | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
*
*---------------------------------------------------------------------------
*/
static int
FileCopyRename(
Tcl_Interp *interp, /* Used for error reporting. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[], /* Argument strings passed to Tcl_FileCmd. */
int copyFlag) /* If non-zero, copy source(s). Otherwise,
* rename them. */
{
int i, result, force;
Tcl_StatBuf statBuf;
Tcl_Obj *target;
Tcl_DString ds;
i = FileForceOption(interp, objc - 1, objv + 1, &force);
if (i < 0) {
return TCL_ERROR;
}
i++;
if ((objc - i) < 2) {
Tcl_WrongNumArgs(interp, 1, objv,
"?-option value ...? source ?source ...? target");
return TCL_ERROR;
}
/*
* If target doesn't exist or isn't a directory, try the copy/rename. More
* than 2 arguments is only valid if the target is an existing directory.
*/
target = objv[objc - 1];
if (Tcl_FSConvertToPathType(interp, target) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(target),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&ds);
result = TCL_OK;
/*
* Call Tcl_FSStat() so that if target is a symlink that points to a
* directory we will put the sources in that directory instead of
* overwriting the symlink.
|
| ︙ | ︙ | |||
208 209 210 211 212 213 214 |
source = FileBasename(interp, objv[i]);
if (source == NULL) {
result = TCL_ERROR;
break;
}
jargv[0] = objv[objc - 1];
jargv[1] = source;
| | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
source = FileBasename(interp, objv[i]);
if (source == NULL) {
result = TCL_ERROR;
break;
}
jargv[0] = objv[objc - 1];
jargv[1] = source;
newFileName = TclJoinPath(2, jargv, 1);
Tcl_IncrRefCount(newFileName);
result = CopyRenameOneFile(interp, objv[i], newFileName, copyFlag,
force);
Tcl_DecrRefCount(newFileName);
Tcl_DecrRefCount(source);
if (result == TCL_ERROR) {
|
| ︙ | ︙ | |||
244 245 246 247 248 249 250 |
*----------------------------------------------------------------------
*/
int
TclFileMakeDirsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Used for error reporting. */
| | | | | > > | > > | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
*----------------------------------------------------------------------
*/
int
TclFileMakeDirsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Used for error reporting. */
int objc, /* Number of arguments */
Tcl_Obj *const objv[]) /* Argument strings passed to Tcl_FileCmd. */
{
Tcl_Obj *errfile = NULL;
int result, i;
Tcl_Size j, pobjc;
Tcl_Obj *split = NULL;
Tcl_Obj *target = NULL;
Tcl_StatBuf statBuf;
Tcl_DString ds;
result = TCL_OK;
for (i = 1; i < objc; i++) {
if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) {
result = TCL_ERROR;
break;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(objv[i]),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
result = TCL_ERROR;
break;
}
Tcl_DStringFree(&ds);
split = Tcl_FSSplitPath(objv[i], &pobjc);
Tcl_IncrRefCount(split);
if (pobjc == 0) {
errno = ENOENT;
errfile = objv[i];
break;
|
| ︙ | ︙ | |||
373 374 375 376 377 378 379 |
*----------------------------------------------------------------------
*/
int
TclFileDeleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Used for error reporting */
| | | | < > | > | > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
*----------------------------------------------------------------------
*/
int
TclFileDeleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Used for error reporting */
int objc, /* Number of arguments */
Tcl_Obj *const objv[]) /* Argument strings passed to Tcl_FileCmd. */
{
int i, force, result;
Tcl_Obj *errfile;
Tcl_Obj *errorBuffer = NULL;
Tcl_DString ds;
i = FileForceOption(interp, objc - 1, objv + 1, &force);
if (i < 0) {
return TCL_ERROR;
}
errfile = NULL;
result = TCL_OK;
for (i++ ; i < objc; i++) {
Tcl_StatBuf statBuf;
errfile = objv[i];
if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) {
result = TCL_ERROR;
goto done;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(objv[i]),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
result = TCL_ERROR;
goto done;
}
Tcl_DStringFree(&ds);
/*
* Call lstat() to get info so can delete symbolic link itself.
*/
if (Tcl_FSLstat(objv[i], &statBuf) != 0) {
result = TCL_ERROR;
|
| ︙ | ︙ | |||
443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
}
}
} else {
result = Tcl_FSDeleteFile(objv[i]);
}
if (result != TCL_OK) {
/*
* Avoid possible race condition (file/directory deleted after call
* of lstat), so bypass ENOENT because not an error, just a no-op
*/
if (errno == ENOENT) {
result = TCL_OK;
continue;
| > | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
}
}
} else {
result = Tcl_FSDeleteFile(objv[i]);
}
if (result != TCL_OK) {
/*
* Avoid possible race condition (file/directory deleted after call
* of lstat), so bypass ENOENT because not an error, just a no-op
*/
if (errno == ENOENT) {
result = TCL_OK;
continue;
|
| ︙ | ︙ | |||
519 520 521 522 523 524 525 526 527 528 529 |
* exists. */
{
int result;
Tcl_Obj *errfile, *errorBuffer;
Tcl_Obj *actualSource=NULL; /* If source is a link, then this is the real
* file/directory. */
Tcl_StatBuf sourceStatBuf, targetStatBuf;
if (Tcl_FSConvertToPathType(interp, source) != TCL_OK) {
return TCL_ERROR;
}
| > > | > > > | > > | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
* exists. */
{
int result;
Tcl_Obj *errfile, *errorBuffer;
Tcl_Obj *actualSource=NULL; /* If source is a link, then this is the real
* file/directory. */
Tcl_StatBuf sourceStatBuf, targetStatBuf;
Tcl_DString ds;
if (Tcl_FSConvertToPathType(interp, source) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(source),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&ds);
if (Tcl_FSConvertToPathType(interp, target) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(target),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&ds);
errfile = NULL;
errorBuffer = NULL;
result = TCL_ERROR;
/*
* We want to copy/rename links and not the files they point to, so we use
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 |
if (result != TCL_OK) {
if (errno == EXDEV) {
/*
* The copy failed because we're trying to do a
* cross-filesystem copy. We do this through our Tcl library.
*/
| | > > | > | > > > > > | | < | < | > | < | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 |
if (result != TCL_OK) {
if (errno == EXDEV) {
/*
* The copy failed because we're trying to do a
* cross-filesystem copy. We do this through our Tcl library.
*/
Tcl_Obj *copyCommand, *cmdObj, *opObj;
TclNewObj(copyCommand);
TclNewLiteralStringObj(cmdObj, "::tcl::CopyDirectory");
Tcl_ListObjAppendElement(interp, copyCommand, cmdObj);
if (copyFlag) {
TclNewLiteralStringObj(opObj, "copying");
} else {
TclNewLiteralStringObj(opObj, "renaming");
}
Tcl_ListObjAppendElement(interp, copyCommand, opObj);
Tcl_ListObjAppendElement(interp, copyCommand, source);
Tcl_ListObjAppendElement(interp, copyCommand, target);
Tcl_IncrRefCount(copyCommand);
result = Tcl_EvalObjEx(interp, copyCommand,
TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
Tcl_DecrRefCount(copyCommand);
if (result != TCL_OK) {
/*
* There was an error in the Tcl-level copy. We will pass
* on the Tcl error message and can ensure this by setting
* errfile to NULL
*/
|
| ︙ | ︙ | |||
852 853 854 855 856 857 858 | * * Side effects: * None. * *--------------------------------------------------------------------------- */ | | | | | < | | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 |
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
static int
FileForceOption(
Tcl_Interp *interp, /* Interp, for error return. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[], /* Argument strings. First command line
* option, if it exists, begins at 0. */
int *forcePtr) /* If the "-force" was specified, *forcePtr is
* filled with 1, otherwise with 0. */
{
int force, i, idx;
static const char *const options[] = {
"-force", "--", NULL
};
force = 0;
for (i = 0; i < objc; i++) {
if (TclGetString(objv[i])[0] != '-') {
break;
}
if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", TCL_EXACT,
&idx) != TCL_OK) {
return -1;
}
if (idx == 0 /* -force */) {
force = 1;
} else { /* -- */
i++;
break;
}
|
| ︙ | ︙ | |||
977 978 979 980 981 982 983 |
*----------------------------------------------------------------------
*/
int
TclFileAttrsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter for error reporting. */
| | | > > | > > | 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 |
*----------------------------------------------------------------------
*/
int
TclFileAttrsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The interpreter for error reporting. */
int objc, /* Number of command line arguments. */
Tcl_Obj *const objv[]) /* The command line objects. */
{
int result;
const char *const *attributeStrings;
const char **attributeStringsAllocated = NULL;
Tcl_Obj *objStrings = NULL;
Tcl_Size numObjStrings = TCL_INDEX_NONE;
Tcl_Obj *filePtr;
Tcl_DString ds;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?-option value ...?");
return TCL_ERROR;
}
filePtr = objv[1];
if (Tcl_FSConvertToPathType(interp, filePtr) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(filePtr),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&ds);
objc -= 2;
objv += 2;
result = TCL_ERROR;
Tcl_SetErrno(0);
/*
|
| ︙ | ︙ | |||
1130 1131 1132 1133 1134 1135 1136 |
}
Tcl_SetObjResult(interp, objPtr);
} else {
/*
* Set option/value pairs.
*/
| < | | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 |
}
Tcl_SetObjResult(interp, objPtr);
} else {
/*
* Set option/value pairs.
*/
int i, index;
if (numObjStrings == 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad option \"%s\", there are no file attributes in this"
" filesystem", TclGetString(objv[0])));
Tcl_SetErrorCode(interp, "TCL","OPERATION","FATTR","NONE", (char *)NULL);
goto end;
|
| ︙ | ︙ | |||
1197 1198 1199 1200 1201 1202 1203 |
*----------------------------------------------------------------------
*/
int
TclFileLinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > | 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 |
*----------------------------------------------------------------------
*/
int
TclFileLinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *contents;
int index;
Tcl_DString ds;
if (objc < 2 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "?-linktype? linkname ?target?");
return TCL_ERROR;
}
/*
|
| ︙ | ︙ | |||
1244 1245 1246 1247 1248 1249 1250 |
}
} else {
linkAction = TCL_CREATE_SYMBOLIC_LINK | TCL_CREATE_HARD_LINK;
}
if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) {
return TCL_ERROR;
}
| > | > > | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 |
}
} else {
linkAction = TCL_CREATE_SYMBOLIC_LINK | TCL_CREATE_HARD_LINK;
}
if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(objv[index]),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&ds);
/*
* Create link from source to target.
*/
contents = Tcl_FSLink(objv[index], objv[index+1], linkAction);
if (contents == NULL) {
|
| ︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 |
}
return TCL_ERROR;
}
} else {
if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) {
return TCL_ERROR;
}
| > | > > | 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 |
}
return TCL_ERROR;
}
} else {
if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(objv[index]),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&ds);
/*
* Read link
*/
contents = Tcl_FSLink(objv[index], NULL, 0);
if (contents == NULL) {
|
| ︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 |
*----------------------------------------------------------------------
*/
int
TclFileReadLinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > > | > > | 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 |
*----------------------------------------------------------------------
*/
int
TclFileReadLinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *contents;
Tcl_DString ds;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
if (Tcl_FSConvertToPathType(interp, objv[1]) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_UtfToExternalDStringEx(interp, TCLFSENCODING, TclGetString(objv[1]),
TCL_INDEX_NONE, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&ds);
contents = Tcl_FSLink(objv[1], NULL, 0);
if (contents == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"could not read link \"%s\": %s",
TclGetString(objv[1]), Tcl_PosixError(interp)));
|
| ︙ | ︙ | |||
1408 1409 1410 1411 1412 1413 1414 |
*---------------------------------------------------------------------------
*/
int
TclFileTemporaryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 |
*---------------------------------------------------------------------------
*/
int
TclFileTemporaryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *nameVarObj = NULL; /* Variable to store the name of the temporary
* file in. */
Tcl_Obj *nameObj = NULL; /* Object that will contain the filename. */
Tcl_Channel chan; /* The channel opened (RDWR) on the temporary
* file, or NULL if there's an error. */
Tcl_Obj *tempDirObj = NULL, *tempBaseObj = NULL, *tempExtObj = NULL;
|
| ︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 |
*---------------------------------------------------------------------------
*/
int
TclFileTempDirCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 |
*---------------------------------------------------------------------------
*/
int
TclFileTempDirCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *dirNameObj; /* Object that will contain the directory
* name. */
Tcl_Obj *baseDirObj = NULL, *nameBaseObj = NULL;
/* Pieces of template. Each piece is NULL if
* it is omitted. The platform temporary file
* engine might ignore some pieces. */
|
| ︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 |
*----------------------------------------------------------------------
*/
int
TclFileHomeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 |
*----------------------------------------------------------------------
*/
int
TclFileHomeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *homeDirObj;
if (objc != 1 && objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?user?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 |
*----------------------------------------------------------------------
*/
int
TclFileTildeExpandCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 |
*----------------------------------------------------------------------
*/
int
TclFileTildeExpandCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *expandedPathObj;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "path");
return TCL_ERROR;
}
|
| ︙ | ︙ |
Changes to generic/tclFileName.c.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 | TclPlatformType tclPlatform = TCL_PLATFORM_UNIX; /* * Prototypes for local procedures defined in this file: */ static const char * ExtractWinRoot(const char *path, | | > | | | < | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | TclPlatformType tclPlatform = TCL_PLATFORM_UNIX; /* * Prototypes for local procedures defined in this file: */ static const char * ExtractWinRoot(const char *path, Tcl_DString *resultPtr, int offset, Tcl_PathType *typePtr); static int SkipToChar(char **stringPtr, int match); static Tcl_Obj * SplitWinPath(const char *path); static Tcl_Obj * SplitUnixPath(const char *path); static int DoGlob(Tcl_Interp *interp, Tcl_Obj *resultPtr, const char *separators, Tcl_Obj *pathPtr, int flags, char *pattern, Tcl_GlobTypeData *types); static int TclGlob(Tcl_Interp *interp, char *pattern, Tcl_Obj *pathPrefix, int globFlags, Tcl_GlobTypeData *types); /* Flag values used by TclGlob() */ #define TCL_GLOBMODE_DIR 4 #define TCL_GLOBMODE_TAILS 8 /* * When there is no support for getting the block size of a file in a stat() * call, use this as a guess. Allow it to be overridden in the platform- * specific files. */ |
| ︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 |
* May modify the Tcl_DString.
*----------------------------------------------------------------------
*/
static void
SetResultLength(
Tcl_DString *resultPtr,
int extended)
{
| > | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
* May modify the Tcl_DString.
*----------------------------------------------------------------------
*/
static void
SetResultLength(
Tcl_DString *resultPtr,
int offset,
int extended)
{
Tcl_DStringSetLength(resultPtr, offset);
if (extended == 2) {
TclDStringAppendLiteral(resultPtr, "//?/UNC/");
} else if (extended == 1) {
TclDStringAppendLiteral(resultPtr, "//?/");
}
}
|
| ︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
*----------------------------------------------------------------------
*/
static const char *
ExtractWinRoot(
const char *path, /* Path to parse. */
Tcl_DString *resultPtr, /* Buffer to hold result. */
Tcl_PathType *typePtr) /* Where to store pathType result */
{
int extended = 0;
if ( (path[0] == '/' || path[0] == '\\')
&& (path[1] == '/' || path[1] == '\\')
&& (path[2] == '?')
| > > | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
*----------------------------------------------------------------------
*/
static const char *
ExtractWinRoot(
const char *path, /* Path to parse. */
Tcl_DString *resultPtr, /* Buffer to hold result. */
int offset, /* Offset in buffer where result should be
* stored. */
Tcl_PathType *typePtr) /* Where to store pathType result */
{
int extended = 0;
if ( (path[0] == '/' || path[0] == '\\')
&& (path[1] == '/' || path[1] == '\\')
&& (path[2] == '?')
|
| ︙ | ︙ | |||
128 129 130 131 132 133 134 |
* Might be a UNC or Vol-Relative path.
*/
const char *host, *share, *tail;
int hlen, slen;
if (path[1] != '/' && path[1] != '\\') {
| | | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
* Might be a UNC or Vol-Relative path.
*/
const char *host, *share, *tail;
int hlen, slen;
if (path[1] != '/' && path[1] != '\\') {
SetResultLength(resultPtr, offset, extended);
*typePtr = TCL_PATH_VOLUME_RELATIVE;
TclDStringAppendLiteral(resultPtr, "/");
return &path[1];
}
host = &path[2];
/*
|
| ︙ | ︙ | |||
163 164 165 166 167 168 169 | * been documented that that is not the case). */ *typePtr = TCL_PATH_VOLUME_RELATIVE; TclDStringAppendLiteral(resultPtr, "/"); return &path[2]; } | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
* been documented that that is not the case).
*/
*typePtr = TCL_PATH_VOLUME_RELATIVE;
TclDStringAppendLiteral(resultPtr, "/");
return &path[2];
}
SetResultLength(resultPtr, offset, extended);
share = &host[hlen];
/*
* Skip separators.
*/
while (share[0] == '/' || share[0] == '\\') {
|
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
*typePtr = TCL_PATH_ABSOLUTE;
return tail;
} else if (*path && path[1] == ':') {
/*
* Might be a drive separator.
*/
| | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
*typePtr = TCL_PATH_ABSOLUTE;
return tail;
} else if (*path && path[1] == ':') {
/*
* Might be a drive separator.
*/
SetResultLength(resultPtr, offset, extended);
if (path[2] != '/' && path[2] != '\\') {
*typePtr = TCL_PATH_VOLUME_RELATIVE;
Tcl_DStringAppend(resultPtr, path, 2);
return &path[2];
} else {
const char *tail = &path[3];
|
| ︙ | ︙ | |||
300 301 302 303 304 305 306 |
*/
abs = 3;
}
if (abs != 0) {
*typePtr = TCL_PATH_ABSOLUTE;
| | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
*/
abs = 3;
}
if (abs != 0) {
*typePtr = TCL_PATH_ABSOLUTE;
SetResultLength(resultPtr, offset, extended);
Tcl_DStringAppend(resultPtr, path, abs);
return path + abs;
}
}
/*
* Anything else is treated as relative.
|
| ︙ | ︙ | |||
417 418 419 420 421 422 423 |
break;
}
case TCL_PLATFORM_WINDOWS: {
Tcl_DString ds;
const char *rootEnd;
Tcl_DStringInit(&ds);
| | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
break;
}
case TCL_PLATFORM_WINDOWS: {
Tcl_DString ds;
const char *rootEnd;
Tcl_DStringInit(&ds);
rootEnd = ExtractWinRoot(path, &ds, 0, &type);
if ((rootEnd != path) && (driveNameLengthPtr != NULL)) {
*driveNameLengthPtr = rootEnd - path;
if (driveNameRef != NULL) {
*driveNameRef = Tcl_DStringToObj(&ds);
Tcl_IncrRefCount(*driveNameRef);
}
}
|
| ︙ | ︙ | |||
576 577 578 579 580 581 582 |
* Now set up the argv pointers.
*/
p = (char *) &(*argvPtr)[(*argcPtr) + 1];
for (i = 0; i < *argcPtr; i++) {
(*argvPtr)[i] = p;
| | < < | 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
* Now set up the argv pointers.
*/
p = (char *) &(*argvPtr)[(*argcPtr) + 1];
for (i = 0; i < *argcPtr; i++) {
(*argvPtr)[i] = p;
while (*(p++) != '\0');
}
(*argvPtr)[i] = NULL;
/*
* Free the result ptr given to us by Tcl_FSSplitPath
*/
|
| ︙ | ︙ | |||
689 690 691 692 693 694 695 |
const char *p, *elementStart;
Tcl_PathType type = TCL_PATH_ABSOLUTE;
Tcl_DString buf;
Tcl_Obj *result;
Tcl_DStringInit(&buf);
TclNewObj(result);
| | | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
const char *p, *elementStart;
Tcl_PathType type = TCL_PATH_ABSOLUTE;
Tcl_DString buf;
Tcl_Obj *result;
Tcl_DStringInit(&buf);
TclNewObj(result);
p = ExtractWinRoot(path, &buf, 0, &type);
/*
* Terminate the root portion, if we matched something.
*/
if (p != path) {
Tcl_ListObjAppendElement(NULL, result, Tcl_DStringToObj(&buf));
|
| ︙ | ︙ | |||
712 713 714 715 716 717 718 |
elementStart = p;
while ((*p != '\0') && (*p != '/') && (*p != '\\')) {
p++;
}
length = p - elementStart;
if (length > 0) {
Tcl_Obj *nextElt;
| < | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 |
elementStart = p;
while ((*p != '\0') && (*p != '/') && (*p != '\\')) {
p++;
}
length = p - elementStart;
if (length > 0) {
Tcl_Obj *nextElt;
if ((elementStart != path) &&
isalpha(UCHAR(elementStart[0])) &&
(elementStart[1] == ':')) {
TclNewLiteralStringObj(nextElt, "./");
Tcl_AppendToObj(nextElt, elementStart, length);
} else {
nextElt = Tcl_NewStringObj(elementStart, length);
|
| ︙ | ︙ | |||
755 756 757 758 759 760 761 |
*---------------------------------------------------------------------------
*/
Tcl_Obj *
TclFSJoinPathHelper(
Tcl_Obj *pathPtr, /* Valid path or NULL. */
Tcl_Size objc, /* Number of array elements to join */
| | | | < | | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 |
*---------------------------------------------------------------------------
*/
Tcl_Obj *
TclFSJoinPathHelper(
Tcl_Obj *pathPtr, /* Valid path or NULL. */
Tcl_Size objc, /* Number of array elements to join */
Tcl_Obj *const objv[], /* Path elements to join. */
int forceRelative) /* If non-zero, assume all paths except first
* are relative */
{
if (pathPtr == NULL) {
return TclJoinPath(objc, objv, forceRelative);
}
if (objc == 0) {
return TclJoinPath(1, &pathPtr, forceRelative);
}
if (objc == 1) {
Tcl_Obj *pair[2];
pair[0] = pathPtr;
pair[1] = objv[0];
return TclJoinPath(2, pair, forceRelative);
} else {
Tcl_Size elemc = objc + 1;
Tcl_Obj *ret, **elemv = (Tcl_Obj**)Tcl_Alloc(elemc*sizeof(Tcl_Obj *));
elemv[0] = pathPtr;
memcpy(elemv+1, objv, objc*sizeof(Tcl_Obj *));
ret = TclJoinPath(elemc, elemv, forceRelative);
Tcl_Free(elemv);
return ret;
}
|
| ︙ | ︙ | |||
813 814 815 816 817 818 819 |
*---------------------------------------------------------------------------
*/
Tcl_Obj *
Tcl_FSJoinToPath(
Tcl_Obj *pathPtr, /* Valid path or NULL. */
Tcl_Size objc, /* Number of array elements to join */
| | | | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
*---------------------------------------------------------------------------
*/
Tcl_Obj *
Tcl_FSJoinToPath(
Tcl_Obj *pathPtr, /* Valid path or NULL. */
Tcl_Size objc, /* Number of array elements to join */
Tcl_Obj *const objv[]) /* Path elements to join. */
{
return TclFSJoinPathHelper(pathPtr, objc, objv, 0);
}
/*
*---------------------------------------------------------------------------
*
* TclpNativeJoinPath --
*
|
| ︙ | ︙ | |||
854 855 856 857 858 859 860 |
/*
* Remove the ./ from drive-letter prefixed
* elements on Windows, unless it is the first component.
*/
p = joining;
| < | 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
/*
* Remove the ./ from drive-letter prefixed
* elements on Windows, unless it is the first component.
*/
p = joining;
if (length != 0) {
if ((p[0] == '.') && (p[1] == '/') &&
(tclPlatform==TCL_PLATFORM_WINDOWS) && isalpha(UCHAR(p[2]))
&& (p[3] == ':')) {
p += 2;
}
}
|
| ︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 | * Tcl_TranslateFileName -- * * Converts a file name into a form usable by the native system * interfaces. * * Results: * The return value is a pointer to a string containing the name. | | | | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | * Tcl_TranslateFileName -- * * Converts a file name into a form usable by the native system * interfaces. * * Results: * The return value is a pointer to a string containing the name. * This may either be the name pointer passed in or space allocated in * bufferPtr. In all cases, if the return value is not NULL, the caller * must call Tcl_DStringFree() to free the space. If there was an * error in processing the name, then an error message is left in the * interp's result (if interp was not NULL) and the return value is NULL. * * Side effects: * None. * |
| ︙ | ︙ | |||
1148 1149 1150 1151 1152 1153 1154 |
*----------------------------------------------------------------------
*/
int
Tcl_GlobObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 |
*----------------------------------------------------------------------
*/
int
Tcl_GlobObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int i, globFlags, join, dir, result;
Tcl_Size length;
char *string;
const char *separators;
Tcl_Obj *typePtr, *look;
Tcl_Obj *pathOrDir = NULL;
Tcl_DString prefix;
static const char *const options[] = {
"-directory", "-join", "-nocomplain", "-path", "-tails",
|
| ︙ | ︙ | |||
1588 1589 1590 1591 1592 1593 1594 | } /* *---------------------------------------------------------------------- * * TclGlob -- * | | | 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 | } /* *---------------------------------------------------------------------- * * TclGlob -- * * Sets the separator string based on the platform and calls DoGlob. * * The interpreter's result, on entry to this function, must be a valid * Tcl list (e.g. it could be empty), since we will lappend any new * results to that list. If it is not a valid list, this function will * fail to do anything very meaningful. * * Note that if globFlags contains 'TCL_GLOBMODE_TAILS' then pathPrefix |
| ︙ | ︙ | |||
2282 2283 2284 2285 2286 2287 2288 |
* Common for all platforms.
*/
if (pathPtr == NULL) {
joinedPtr = Tcl_DStringToObj(&append);
} else if (flags) {
joinedPtr = TclNewFSPathObj(pathPtr, Tcl_DStringValue(&append),
| | | 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 |
* Common for all platforms.
*/
if (pathPtr == NULL) {
joinedPtr = Tcl_DStringToObj(&append);
} else if (flags) {
joinedPtr = TclNewFSPathObj(pathPtr, Tcl_DStringValue(&append),
Tcl_DStringLength(&append));
} else {
joinedPtr = Tcl_DuplicateObj(pathPtr);
if (strchr(separators, Tcl_DStringValue(&append)[0]) == NULL) {
/*
* The current prefix must end in a separator.
*/
|
| ︙ | ︙ | |||
2315 2316 2317 2318 2319 2320 2321 |
/*
* If it's not the end of the string, we must recurse
*/
if (pathPtr == NULL) {
joinedPtr = Tcl_NewStringObj(pattern, p-pattern);
} else if (flags) {
| | | 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 |
/*
* If it's not the end of the string, we must recurse
*/
if (pathPtr == NULL) {
joinedPtr = Tcl_NewStringObj(pattern, p-pattern);
} else if (flags) {
joinedPtr = TclNewFSPathObj(pathPtr, pattern, p-pattern);
} else {
joinedPtr = Tcl_DuplicateObj(pathPtr);
if (strchr(separators, pattern[0]) == NULL) {
/*
* The current prefix must end in a separator, unless this is a
* volume-relative path. In particular globbing in Windows shares,
* when not using -dir or -path, e.g. 'glob [file join
|
| ︙ | ︙ |
Changes to generic/tclFileSystem.h.
1 2 3 4 5 6 | /* * tclFileSystem.h -- * * This file contains the common definitions and prototypes for use by * Tcl's filesystem and path handling layers. * | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | /* * tclFileSystem.h -- * * This file contains the common definitions and prototypes for use by * Tcl's filesystem and path handling layers. * * Copyright (c) 2003 Vince Darley. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLFILESYSTEM #define _TCLFILESYSTEM #include "tcl.h" /* * The internal TclFS API provides routines for handling and manipulating * paths efficiently, taking direct advantage of the "path" Tcl_Obj type. * * These functions are not exported at all at present. */ MODULE_SCOPE int TclFSCwdPointerEquals(Tcl_Obj **pathPtrPtr); MODULE_SCOPE int TclFSNormalizeToUniquePath(Tcl_Interp *interp, Tcl_Obj *pathPtr, int startAt); MODULE_SCOPE Tcl_Obj * TclFSMakePathRelative(Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_Obj *cwdPtr); MODULE_SCOPE int TclFSEnsureEpochOk(Tcl_Obj *pathPtr, const Tcl_Filesystem **fsPtrPtr); MODULE_SCOPE void TclFSSetPathDetails(Tcl_Obj *pathPtr, const Tcl_Filesystem *fsPtr, void *clientData); MODULE_SCOPE Tcl_Obj * TclFSNormalizeAbsolutePath(Tcl_Interp *interp, |
| ︙ | ︙ | |||
60 61 62 63 64 65 66 | MODULE_SCOPE Tcl_Obj * TclWinVolumeRelativeNormalize(Tcl_Interp *interp, const char *path, Tcl_Obj **useThisCwdPtr); MODULE_SCOPE Tcl_FSPathInFilesystemProc TclNativePathInFilesystem; MODULE_SCOPE Tcl_FSCreateInternalRepProc TclNativeCreateNativeRep; #endif /* _TCLFILESYSTEM */ | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | MODULE_SCOPE Tcl_Obj * TclWinVolumeRelativeNormalize(Tcl_Interp *interp, const char *path, Tcl_Obj **useThisCwdPtr); MODULE_SCOPE Tcl_FSPathInFilesystemProc TclNativePathInFilesystem; MODULE_SCOPE Tcl_FSCreateInternalRepProc TclNativeCreateNativeRep; #endif /* _TCLFILESYSTEM */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to generic/tclGetDate.y.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | * Copyright © 1995-1997 Sun Microsystems, Inc. * Copyright © 2015 Sergey G. Brester aka sebres. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
* Copyright © 1995-1997 Sun Microsystems, Inc.
* Copyright © 2015 Sergey G. Brester aka sebres.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
%parse-param {DateInfo* info}
%lex-param {DateInfo* info}
%define api.pure
/* %error-verbose would be nice, but our token names are meaningless */
%locations
%{
/*
* tclDate.c --
|
| ︙ | ︙ | |||
59 60 61 62 63 64 65 | * yyparse will accept a 'struct DateInfo' as its parameter; that's where the * parsed fields will be returned. */ #include "tclDate.h" #define YYMALLOC Tcl_Alloc | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | * yyparse will accept a 'struct DateInfo' as its parameter; that's where the * parsed fields will be returned. */ #include "tclDate.h" #define YYMALLOC Tcl_Alloc #define YYFREE(x) (Tcl_Free((void*) (x))) #define EPOCH 1970 #define START_OF_TIME 1902 #define END_OF_TIME 2037 /* * The offset of tm_year of struct tm returned by localtime, gmtime, etc. |
| ︙ | ︙ | |||
113 114 115 116 117 118 119 |
%{
/*
* Prototypes of internal functions.
*/
| | | | | | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
%{
/*
* Prototypes of internal functions.
*/
static int LookupWord(YYSTYPE* yylvalPtr, char *buff);
static void TclDateerror(YYLTYPE* location,
DateInfo* info, const char *s);
static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location,
DateInfo* info);
MODULE_SCOPE int yyparse(DateInfo*);
%}
%token tAGO
%token tDAY
%token tDAYZONE
%token tID
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
yyDSTmode = DSToff;
}
| tDAYZONE {
yyTimezone = $1;
yyDSTmode = DSTon;
}
| tZONEwO4 sign INTNUM { /* GMT+0100, GMT-1000, etc. */
| | | | | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
yyDSTmode = DSToff;
}
| tDAYZONE {
yyTimezone = $1;
yyDSTmode = DSTon;
}
| tZONEwO4 sign INTNUM { /* GMT+0100, GMT-1000, etc. */
yyTimezone = $1 - $2*($3 % 100 + ($3 / 100) * 60);
yyDSTmode = DSToff;
}
| tZONEwO2 sign INTNUM { /* GMT+1, GMT-10, etc. */
yyTimezone = $1 - $2*($3 * 60);
yyDSTmode = DSToff;
}
;
nmzone : sign tUNUMBER %?{ yyDigitCount == 4 || yyDigitCount <= 2 } {
if (yyDigitCount == 4) { /* +0100, -0100 */
yyTimezone = -$1*($2 % 100 + ($2 / 100) * 60);
} else { /* +01, -01, +1, -1 */
yyTimezone = -$1*($2 * 60);
}
yyDSTmode = DSToff;
}
;
comma : ','
| ',' SP
|
| ︙ | ︙ | |||
714 715 716 717 718 719 720 | /* * Dump error messages in the bit bucket. */ static void TclDateerror( | | | | | 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
/*
* Dump error messages in the bit bucket.
*/
static void
TclDateerror(
YYLTYPE* location,
DateInfo* infoPtr,
const char *s)
{
Tcl_Obj* t;
if (!infoPtr->messages) {
TclNewObj(infoPtr->messages);
}
Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1);
Tcl_AppendToObj(infoPtr->messages, s, -1);
Tcl_AppendToObj(infoPtr->messages, " (characters ", -1);
TclNewIntObj(t, location->first_column);
|
| ︙ | ︙ | |||
758 759 760 761 762 763 764 |
return (((Hours / 24) * 24 + (Hours % 12) + 12) * 60 + Minutes) * 60 + Seconds;
}
return -1; /* Should never be reached */
}
static int
LookupWord(
| | | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 |
return (((Hours / 24) * 24 + (Hours % 12) + 12) * 60 + Minutes) * 60 + Seconds;
}
return -1; /* Should never be reached */
}
static int
LookupWord(
YYSTYPE* yylvalPtr,
char *buff)
{
char *p;
char *q;
const TABLE *tp;
int i, abbrev;
|
| ︙ | ︙ | |||
882 883 884 885 886 887 888 |
}
return tID;
}
static int
TclDatelex(
| | | | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 |
}
return tID;
}
static int
TclDatelex(
YYSTYPE* yylvalPtr,
YYLTYPE* location,
DateInfo *info)
{
char c;
char *p;
char buff[20];
int Count;
const char *tokStart;
|
| ︙ | ︙ | |||
922 923 924 925 926 927 928 |
*/
if (yyDigitCount == 14 || yyDigitCount == 12) {
/* long form of ISO 8601 (without separator), either
* YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date
* (8 chars is isodate) */
p = (char *)yyInput+8;
if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) {
| | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 |
*/
if (yyDigitCount == 14 || yyDigitCount == 12) {
/* long form of ISO 8601 (without separator), either
* YYYYMMDDhhmmss or YYYYMMDDhhmm, so reduce to date
* (8 chars is isodate) */
p = (char *)yyInput+8;
if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) {
return tID; /* overflow*/
}
yyDigitCount = 8;
yyInput = p;
location->last_column = yyInput - info->dateStart - 1;
return tISOBASL;
}
/*
* Convert the string into a number
*/
if (TclAtoWIe(&yylvalPtr->Number, yyInput, p, 1) != TCL_OK) {
return tID; /* overflow*/
}
yyInput = p;
/*
* A number with 6 or more digits is considered an ISO 8601 base.
*/
location->last_column = yyInput - info->dateStart - 1;
if (yyDigitCount >= 6) {
|
| ︙ | ︙ |
Deleted generic/tclGrapheme.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to generic/tclHash.c.
| ︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 | static Tcl_HashEntry * AllocStringEntry(Tcl_HashTable *tablePtr, void *keyPtr); /* * Function prototypes for static functions in this file: */ static Tcl_HashEntry * BogusCreate(Tcl_HashTable *tablePtr, const char *key, int *newPtr); static Tcl_HashEntry * CreateHashEntry(Tcl_HashTable *tablePtr, const char *key, int *newPtr); | > < < | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
static Tcl_HashEntry * AllocStringEntry(Tcl_HashTable *tablePtr,
void *keyPtr);
/*
* Function prototypes for static functions in this file:
*/
static Tcl_HashEntry * BogusFind(Tcl_HashTable *tablePtr, const char *key);
static Tcl_HashEntry * BogusCreate(Tcl_HashTable *tablePtr, const char *key,
int *newPtr);
static Tcl_HashEntry * CreateHashEntry(Tcl_HashTable *tablePtr, const char *key,
int *newPtr);
static Tcl_HashEntry * FindHashEntry(Tcl_HashTable *tablePtr, const char *key);
static void RebuildTable(Tcl_HashTable *tablePtr);
const Tcl_HashKeyType tclArrayHashKeyType = {
TCL_HASH_KEY_TYPE_VERSION, /* version */
TCL_HASH_KEY_RANDOMIZE_HASH, /* flags */
HashArrayKey, /* hashKeyProc */
CompareArrayKeys, /* compareKeysProc */
|
| ︙ | ︙ | |||
167 168 169 170 171 172 173 |
tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
tablePtr->numEntries = 0;
tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
tablePtr->downShift = 28;
tablePtr->mask = 3;
tablePtr->keyType = keyType;
| < < | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
tablePtr->numEntries = 0;
tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
tablePtr->downShift = 28;
tablePtr->mask = 3;
tablePtr->keyType = keyType;
tablePtr->findProc = FindHashEntry;
tablePtr->createProc = CreateHashEntry;
if (typePtr == NULL) {
/*
* The caller has been rebuilt so the hash table is an extended
* version.
*/
|
| ︙ | ︙ | |||
208 209 210 211 212 213 214 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static Tcl_HashEntry *
FindHashEntry(
Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
const char *key) /* Key to use to find matching entry. */
{
return CreateHashEntry(tablePtr, key, NULL);
}
/*
*----------------------------------------------------------------------
*
* CreateHashEntry --
*
* Given a hash table with string keys, and a string key, find the entry
* with a matching key. If there is no matching entry, then create a new
* entry that does match.
*
* Results:
* The return value is a pointer to the matching entry. If this is a
* newly-created entry, then *newPtr will be set to a non-zero value;
* otherwise *newPtr will be set to 0. If this is a new entry the value
* stored in the entry will initially be 0.
*
* Side effects:
* A new entry may be added to the hash table.
*
*----------------------------------------------------------------------
*/
static Tcl_HashEntry *
CreateHashEntry(
Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
const char *key, /* Key to use to find or create matching
* entry. */
int *newPtr) /* Store info here telling whether a new entry
* was created. */
|
| ︙ | ︙ | |||
320 321 322 323 324 325 326 |
for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
hPtr = hPtr->nextPtr) {
if (hash != hPtr->hash) {
continue;
}
/* if keys pointers or values are equal */
if ((key == hPtr->key.oneWordValue)
| | | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
hPtr = hPtr->nextPtr) {
if (hash != hPtr->hash) {
continue;
}
/* if keys pointers or values are equal */
if ((key == hPtr->key.oneWordValue)
|| compareKeysProc((void *) key, hPtr)) {
if (newPtr && (newPtr != TCL_HASH_FIND)) {
*newPtr = 0;
}
return hPtr;
}
}
} else { /* no direct compare - compare key addresses only */
|
| ︙ | ︙ | |||
358 359 360 361 362 363 364 |
*newPtr = 0;
}
return hPtr;
}
}
}
| | < | < | < < < | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
*newPtr = 0;
}
return hPtr;
}
}
}
if (!newPtr || (newPtr == TCL_HASH_FIND)) {
/* This is the findProc functionality, so we are done. */
return NULL;
}
/*
* Entry not found. Add a new one to the bucket.
*/
*newPtr = 1;
if (typePtr->allocEntryProc) {
hPtr = typePtr->allocEntryProc(tablePtr, (void *) key);
} else {
hPtr = (Tcl_HashEntry *)Tcl_Alloc(sizeof(Tcl_HashEntry));
hPtr->key.oneWordValue = (char *) key;
Tcl_SetHashValue(hPtr, NULL);
}
hPtr->tablePtr = tablePtr;
hPtr->hash = hash;
hPtr->nextPtr = tablePtr->buckets[index];
|
| ︙ | ︙ | |||
540 541 542 543 544 545 546 |
}
/*
* Arrange for panics if the table is used again without
* re-initialization.
*/
| < | < | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
}
/*
* Arrange for panics if the table is used again without
* re-initialization.
*/
tablePtr->findProc = BogusFind;
tablePtr->createProc = BogusCreate;
}
/*
*----------------------------------------------------------------------
*
* Tcl_FirstHashEntry --
|
| ︙ | ︙ | |||
722 723 724 725 726 727 728 |
Tcl_HashEntry *hPtr;
size_t count = tablePtr->keyType * sizeof(int);
size_t size = offsetof(Tcl_HashEntry, key) + count;
if (size < sizeof(Tcl_HashEntry)) {
size = sizeof(Tcl_HashEntry);
}
| | < | | < | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 |
Tcl_HashEntry *hPtr;
size_t count = tablePtr->keyType * sizeof(int);
size_t size = offsetof(Tcl_HashEntry, key) + count;
if (size < sizeof(Tcl_HashEntry)) {
size = sizeof(Tcl_HashEntry);
}
hPtr = (Tcl_HashEntry *)Tcl_Alloc(size);
memcpy(hPtr->key.string, keyPtr, count);
Tcl_SetHashValue(hPtr, NULL);
return hPtr;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
822 823 824 825 826 827 828 |
Tcl_HashEntry *hPtr;
size_t size, allocsize;
allocsize = size = strlen(string) + 1;
if (size < sizeof(hPtr->key)) {
allocsize = sizeof(hPtr->key);
}
| | < | | | < | 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
Tcl_HashEntry *hPtr;
size_t size, allocsize;
allocsize = size = strlen(string) + 1;
if (size < sizeof(hPtr->key)) {
allocsize = sizeof(hPtr->key);
}
hPtr = (Tcl_HashEntry *)Tcl_Alloc(offsetof(Tcl_HashEntry, key) + allocsize);
memset(hPtr, 0, offsetof(Tcl_HashEntry, key) + allocsize);
memcpy(hPtr->key.string, string, size);
Tcl_SetHashValue(hPtr, NULL);
return hPtr;
}
/*
*----------------------------------------------------------------------
*
* TclCompareStringKeys --
|
| ︙ | ︙ | |||
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 |
}
return result;
}
/*
*----------------------------------------------------------------------
*
* BogusCreate --
*
* This function is invoked when Tcl_CreateHashEntry is called on a
* table that has been deleted.
*
* Results:
* If panic returns (which it shouldn't) this function returns NULL.
*
* Side effects:
* Generates a panic.
*
*----------------------------------------------------------------------
*/
static Tcl_HashEntry *
BogusCreate(
TCL_UNUSED(Tcl_HashTable *),
TCL_UNUSED(const char *),
| > > > > > > > > > > > > > > > > > > > > > > > > > > | | < | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 |
}
return result;
}
/*
*----------------------------------------------------------------------
*
* BogusFind --
*
* This function is invoked when Tcl_FindHashEntry is called on a
* table that has been deleted.
*
* Results:
* If Tcl_Panic returns (which it shouldn't) this function returns NULL.
*
* Side effects:
* Generates a panic.
*
*----------------------------------------------------------------------
*/
static Tcl_HashEntry *
BogusFind(
TCL_UNUSED(Tcl_HashTable *),
TCL_UNUSED(const char *))
{
Tcl_Panic("called %s on deleted table", "Tcl_FindHashEntry");
return NULL;
}
/*
*----------------------------------------------------------------------
*
* BogusCreate --
*
* This function is invoked when Tcl_CreateHashEntry is called on a
* table that has been deleted.
*
* Results:
* If panic returns (which it shouldn't) this function returns NULL.
*
* Side effects:
* Generates a panic.
*
*----------------------------------------------------------------------
*/
static Tcl_HashEntry *
BogusCreate(
TCL_UNUSED(Tcl_HashTable *),
TCL_UNUSED(const char *),
TCL_UNUSED(int *))
{
Tcl_Panic("called %s on deleted table", "Tcl_CreateHashEntry");
return NULL;
}
/*
*----------------------------------------------------------------------
*
* RebuildTable --
|
| ︙ | ︙ |
Changes to generic/tclHistory.c.
| ︙ | ︙ | |||
141 142 143 144 145 146 147 |
/*
* Do not call [history] if it has been replaced by an empty proc
*/
result = Tcl_GetCommandInfo(interp, "::history", &info);
if (result && (info.deleteProc == TclProcDeleteProc)) {
| | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
/*
* Do not call [history] if it has been replaced by an empty proc
*/
result = Tcl_GetCommandInfo(interp, "::history", &info);
if (result && (info.deleteProc == TclProcDeleteProc)) {
Proc *procPtr = (Proc *) info.objClientData;
call = (procPtr->cmdPtr->compileProc != TclCompileNoOp);
}
if (call) {
Tcl_Obj *list[3];
/*
|
| ︙ | ︙ |
Changes to generic/tclIO.c.
| ︙ | ︙ | |||
132 133 134 135 136 137 138 |
int stdinInitialized;
int stdoutInitialized;
int stderrInitialized;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
| < < < < < < | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
int stdinInitialized;
int stdoutInitialized;
int stderrInitialized;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
* Structure to record a close callback. One such record exists for
* each close callback registered for a channel.
*/
typedef struct CloseCallback {
Tcl_CloseProc *proc; /* The procedure to call. */
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 | static int TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr); static Tcl_Encoding GetBinaryEncoding(void); static void FreeBinaryEncoding(void); static Tcl_HashTable * GetChannelTable(Tcl_Interp *interp); static int GetInput(Channel *chanPtr); static void PeekAhead(Channel *chanPtr, char **dstEndPtr, GetsState *gsPtr); | | | | | | < | | | | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | static int TclGetsObjBinary(Tcl_Channel chan, Tcl_Obj *objPtr); static Tcl_Encoding GetBinaryEncoding(void); static void FreeBinaryEncoding(void); static Tcl_HashTable * GetChannelTable(Tcl_Interp *interp); static int GetInput(Channel *chanPtr); static void PeekAhead(Channel *chanPtr, char **dstEndPtr, GetsState *gsPtr); static int ReadBytes(ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft); static int ReadChars(ChannelState *statePtr, Tcl_Obj *objPtr, int charsLeft, int *factorPtr); static void RecycleBuffer(ChannelState *statePtr, ChannelBuffer *bufPtr, int mustDiscard); static int StackSetBlockMode(Channel *chanPtr, int mode); static int SetBlockMode(Tcl_Interp *interp, Channel *chanPtr, int mode); static void StopCopy(CopyState *csPtr); static void CopyDecrRefCount(CopyState *csPtr); static void TranslateInputEOL(ChannelState *statePtr, char *dst, const char *src, int *dstLenPtr, int *srcLenPtr); static void UpdateInterest(Channel *chanPtr); static Tcl_Size Write(Channel *chanPtr, const char *src, Tcl_Size srcLen, Tcl_Encoding encoding); static Tcl_Obj * FixLevelCode(Tcl_Obj *msg); static void SpliceChannel(Tcl_Channel chan); static void CutChannel(Tcl_Channel chan); static int WillRead(Channel *chanPtr); #define WriteChars(chanPtr, src, srcLen) \ Write(chanPtr, src, srcLen, chanPtr->state->encoding) #define WriteBytes(chanPtr, src, srcLen) \ Write(chanPtr, src, srcLen, tclIdentityEncoding) /* * Simplifying helper macros. All may use their argument(s) multiple times. * The ANSI C "prototypes" for the macros are listed below, together with a * short description of what the macro does. * * -------------------------------------------------------------------------- |
| ︙ | ︙ | |||
337 338 339 340 341 342 343 |
size_t refCount; /* Share this struct among many Tcl_Obj. */
} ResolvedChanName;
static void DupChannelInternalRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
static void FreeChannelInternalRep(Tcl_Obj *objPtr);
static const Tcl_ObjType chanObjType = {
| | | | | | | | | 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
size_t refCount; /* Share this struct among many Tcl_Obj. */
} ResolvedChanName;
static void DupChannelInternalRep(Tcl_Obj *objPtr, Tcl_Obj *copyPtr);
static void FreeChannelInternalRep(Tcl_Obj *objPtr);
static const Tcl_ObjType chanObjType = {
"channel", /* name for this type */
FreeChannelInternalRep, /* freeIntRepProc */
DupChannelInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define ChanSetInternalRep(objPtr, resPtr) \
do { \
Tcl_ObjInternalRep ir; \
(resPtr)->refCount++; \
ir.twoPtrValue.ptr1 = (resPtr); \
ir.twoPtrValue.ptr2 = NULL; \
Tcl_StoreInternalRep((objPtr), &chanObjType, &ir); \
} while (0)
#define ChanGetInternalRep(objPtr, resPtr) \
do { \
const Tcl_ObjInternalRep *irPtr; \
irPtr = TclFetchInternalRep((objPtr), &chanObjType); \
(resPtr) = irPtr ? (ResolvedChanName *)irPtr->twoPtrValue.ptr1 : NULL; \
} while (0)
#define BUSY_STATE(st, fl) \
((((st)->csPtrR) && ((fl) & TCL_READABLE)) || \
(((st)->csPtrW) && ((fl) & TCL_WRITABLE)))
#define MAX_CHANNEL_BUFFER_SIZE (1024*1024)
/*
*---------------------------------------------------------------------------
*
* ChanClose, ChanRead, ChanSeek, ChanThreadAction, ChanWatch, ChanWrite --
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
static inline int
ChanClose(
Channel *chanPtr,
Tcl_Interp *interp)
{
return chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, 0);
}
| | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
static inline int
ChanClose(
Channel *chanPtr,
Tcl_Interp *interp)
{
return chanPtr->typePtr->close2Proc(chanPtr->instanceData, interp, 0);
}
/*
*---------------------------------------------------------------------------
*
* ChanRead --
*
* Read up to dstSize bytes using the inputProc of chanPtr, store them at
* dst, and return the number of bytes stored.
|
| ︙ | ︙ | |||
618 619 620 621 622 623 624 |
for (statePtr = tsdPtr->firstCSPtr;
statePtr != NULL;
statePtr = statePtr->nextCSPtr) {
chanPtr = statePtr->topChanPtr;
if (GotFlag(statePtr, CHANNEL_DEAD)) {
continue;
}
| | | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 |
for (statePtr = tsdPtr->firstCSPtr;
statePtr != NULL;
statePtr = statePtr->nextCSPtr) {
chanPtr = statePtr->topChanPtr;
if (GotFlag(statePtr, CHANNEL_DEAD)) {
continue;
}
if (!GotFlag(statePtr, CHANNEL_INCLOSE | CHANNEL_CLOSED )
|| GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
active = 1;
break;
}
}
|
| ︙ | ︙ | |||
676 677 678 679 680 681 682 |
} else {
/*
* The refcount is greater than zero, so flush the channel.
*/
Tcl_Flush((Tcl_Channel) chanPtr);
| < < < < < < < < < < | 669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
} else {
/*
* The refcount is greater than zero, so flush the channel.
*/
Tcl_Flush((Tcl_Channel) chanPtr);
/*
* Call the device driver to actually close the underlying
* device for this channel.
*/
(void) ChanClose(chanPtr, NULL);
|
| ︙ | ︙ | |||
750 751 752 753 754 755 756 |
tsdPtr->stdoutInitialized = init;
tsdPtr->stdoutChannel = channel;
break;
case TCL_STDERR:
tsdPtr->stderrInitialized = init;
tsdPtr->stderrChannel = channel;
if (channel) {
| | < | < | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 |
tsdPtr->stdoutInitialized = init;
tsdPtr->stdoutChannel = channel;
break;
case TCL_STDERR:
tsdPtr->stderrInitialized = init;
tsdPtr->stderrChannel = channel;
if (channel) {
ENCODING_PROFILE_SET(((Channel *)channel)->state->inputEncodingFlags, TCL_ENCODING_PROFILE_REPLACE);
ENCODING_PROFILE_SET(((Channel *)channel)->state->outputEncodingFlags, TCL_ENCODING_PROFILE_REPLACE);
}
break;
}
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
825 826 827 828 829 830 831 |
channel = tsdPtr->stdoutChannel;
break;
case TCL_STDERR:
if (!tsdPtr->stderrInitialized) {
tsdPtr->stderrInitialized = -1;
tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR);
if (tsdPtr->stderrChannel != NULL) {
| | < | < | 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
channel = tsdPtr->stdoutChannel;
break;
case TCL_STDERR:
if (!tsdPtr->stderrInitialized) {
tsdPtr->stderrInitialized = -1;
tsdPtr->stderrChannel = TclpGetDefaultStdChannel(TCL_STDERR);
if (tsdPtr->stderrChannel != NULL) {
ENCODING_PROFILE_SET(((Channel *)tsdPtr->stderrChannel)->state->inputEncodingFlags, TCL_ENCODING_PROFILE_REPLACE);
ENCODING_PROFILE_SET(((Channel *)tsdPtr->stderrChannel)->state->outputEncodingFlags, TCL_ENCODING_PROFILE_REPLACE);
tsdPtr->stderrInitialized = 1;
Tcl_RegisterChannel(NULL, tsdPtr->stderrChannel);
}
}
channel = tsdPtr->stderrChannel;
break;
}
|
| ︙ | ︙ | |||
948 949 950 951 952 953 954 |
static Tcl_HashTable *
GetChannelTable(
Tcl_Interp *interp)
{
Tcl_HashTable *hTblPtr; /* Hash table of channels. */
Tcl_Channel stdinChan, stdoutChan, stderrChan;
| | | | 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 |
static Tcl_HashTable *
GetChannelTable(
Tcl_Interp *interp)
{
Tcl_HashTable *hTblPtr; /* Hash table of channels. */
Tcl_Channel stdinChan, stdoutChan, stderrChan;
hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
hTblPtr = (Tcl_HashTable *)Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(hTblPtr, TCL_STRING_KEYS);
Tcl_SetAssocData(interp, "tclIO",
(Tcl_InterpDeleteProc *) DeleteChannelTable, hTblPtr);
/*
* If the interpreter is trusted (not "safe"), insert channels for
* stdin, stdout and stderr (possibly creating them in the process).
*/
|
| ︙ | ︙ | |||
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 |
Tcl_DeleteHashEntry(hPtr);
statePtr->epoch++;
if (statePtr->refCount-- <= 1) {
if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
(void) Tcl_CloseEx(interp, (Tcl_Channel) chanPtr, 0);
}
}
}
Tcl_DeleteHashTable(hTblPtr);
Tcl_Free(hTblPtr);
}
/*
*----------------------------------------------------------------------
| > | 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 |
Tcl_DeleteHashEntry(hPtr);
statePtr->epoch++;
if (statePtr->refCount-- <= 1) {
if (!GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
(void) Tcl_CloseEx(interp, (Tcl_Channel) chanPtr, 0);
}
}
}
Tcl_DeleteHashTable(hTblPtr);
Tcl_Free(hTblPtr);
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 |
* necessary during (un)stack operation.
*/
chanPtr = ((Channel *) chan)->state->bottomChanPtr;
statePtr = chanPtr->state;
if (interp != NULL) {
| | | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 |
* necessary during (un)stack operation.
*/
chanPtr = ((Channel *) chan)->state->bottomChanPtr;
statePtr = chanPtr->state;
if (interp != NULL) {
hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_ERROR;
}
hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName);
if (hPtr == NULL) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 |
}
return TCL_ERROR;
}
if (resPtr && resPtr->refCount == 1) {
/* Re-use the ResolvedCmdName struct */
Tcl_Release(resPtr->statePtr);
} else {
resPtr = (ResolvedChanName *) Tcl_Alloc(sizeof(ResolvedChanName));
resPtr->refCount = 0;
ChanSetInternalRep(objPtr, resPtr); /* Overwrites, if needed */
}
statePtr = ((Channel *)chan)->state;
resPtr->statePtr = statePtr;
| > | 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 |
}
return TCL_ERROR;
}
if (resPtr && resPtr->refCount == 1) {
/* Re-use the ResolvedCmdName struct */
Tcl_Release(resPtr->statePtr);
} else {
resPtr = (ResolvedChanName *) Tcl_Alloc(sizeof(ResolvedChanName));
resPtr->refCount = 0;
ChanSetInternalRep(objPtr, resPtr); /* Overwrites, if needed */
}
statePtr = ((Channel *)chan)->state;
resPtr->statePtr = statePtr;
|
| ︙ | ︙ | |||
1631 1632 1633 1634 1635 1636 1637 |
if (Tcl_ChannelVersion(typePtr) != TCL_CHANNEL_VERSION_5) {
Tcl_Panic("channel type %s must be version TCL_CHANNEL_VERSION_5", typePtr->typeName);
}
if (typePtr->close2Proc == NULL) {
Tcl_Panic("channel type %s must define close2Proc", typePtr->typeName);
}
if ((TCL_READABLE & mask) && (NULL == typePtr->inputProc)) {
| | < | < | 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 |
if (Tcl_ChannelVersion(typePtr) != TCL_CHANNEL_VERSION_5) {
Tcl_Panic("channel type %s must be version TCL_CHANNEL_VERSION_5", typePtr->typeName);
}
if (typePtr->close2Proc == NULL) {
Tcl_Panic("channel type %s must define close2Proc", typePtr->typeName);
}
if ((TCL_READABLE & mask) && (NULL == typePtr->inputProc)) {
Tcl_Panic("channel type %s must define inputProc when used for reader channel", typePtr->typeName);
}
if ((TCL_WRITABLE & mask) && (NULL == typePtr->outputProc)) {
Tcl_Panic("channel type %s must define outputProc when used for writer channel", typePtr->typeName);
}
if (NULL == typePtr->watchProc) {
Tcl_Panic("channel type %s must define watchProc", typePtr->typeName);
}
/*
* JH: We could subsequently memset these to 0 to avoid the numerous
|
| ︙ | ︙ | |||
1660 1661 1662 1663 1664 1665 1666 |
/*
* Set all the bits that are part of the stack-independent state
* information for the channel.
*/
if (chanName != NULL) {
| | | 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 |
/*
* Set all the bits that are part of the stack-independent state
* information for the channel.
*/
if (chanName != NULL) {
unsigned len = strlen(chanName) + 1;
/*
* Make sure we allocate at least 7 bytes, so it fits for "stdout"
* later.
*/
tmp = (char *)Tcl_Alloc((len < 7) ? 7 : len);
|
| ︙ | ︙ | |||
2414 2415 2416 2417 2418 2419 2420 |
*----------------------------------------------------------------------
*/
int
Tcl_GetChannelHandle(
Tcl_Channel chan, /* The channel to get file from. */
int direction, /* TCL_WRITABLE or TCL_READABLE. */
| | | 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 |
*----------------------------------------------------------------------
*/
int
Tcl_GetChannelHandle(
Tcl_Channel chan, /* The channel to get file from. */
int direction, /* TCL_WRITABLE or TCL_READABLE. */
void **handlePtr) /* Where to store handle */
{
Channel *chanPtr; /* The actual channel. */
void *handle;
int result;
chanPtr = ((Channel *) chan)->state->bottomChanPtr;
if (!chanPtr->typePtr->getHandleProc) {
|
| ︙ | ︙ | |||
2454 2455 2456 2457 2458 2459 2460 | * May leave an error message in the interp. * *---------------------------------------------------------------------- */ int Tcl_RemoveChannelMode( | | | | | | 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 |
* May leave an error message in the interp.
*
*----------------------------------------------------------------------
*/
int
Tcl_RemoveChannelMode(
Tcl_Interp *interp, /* The interp for an error message. Allowed to be NULL. */
Tcl_Channel chan, /* The channel which is modified. */
int mode) /* The access mode to drop from the channel */
{
const char* emsg;
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of actual channel. */
if ((mode != TCL_READABLE) && (mode != TCL_WRITABLE)) {
emsg = "Illegal mode value.";
goto error;
}
if (0 == (GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE) & ~mode)) {
emsg = "Bad mode, would make channel inacessible";
goto error;
}
ResetFlag(statePtr, mode);
return TCL_OK;
error:
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Tcl_RemoveChannelMode error: %s. Channel: \"%s\"",
emsg, Tcl_GetChannelName((Tcl_Channel) chan)));
}
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2818 2819 2820 2821 2822 2823 2824 | bufPtr = statePtr->outQueueHead; /* * Produce the output on the channel. */ PreserveChannelBuffer(bufPtr); | | | 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 | bufPtr = statePtr->outQueueHead; /* * Produce the output on the channel. */ PreserveChannelBuffer(bufPtr); written = ChanWrite(chanPtr, RemovePoint(bufPtr), BytesLeft(bufPtr), &errorCode); /* * If the write failed completely attempt to start the asynchronous * flush mechanism and break out of this loop - do not attempt to * write any more output at this time. */ |
| ︙ | ︙ | |||
2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 |
statePtr->outQueueHead = bufPtr->nextPtr;
if (statePtr->outQueueHead == NULL) {
statePtr->outQueueTail = NULL;
}
RecycleBuffer(statePtr, bufPtr, 0);
}
}
} /* Closes "while". */
/*
* If we wrote some data while flushing in the background, we are done.
* We can't finish the background flush until we run out of data and the
* channel becomes writable again. This ensures that all of the pending
* data has been flushed at the system level.
| > | 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 |
statePtr->outQueueHead = bufPtr->nextPtr;
if (statePtr->outQueueHead == NULL) {
statePtr->outQueueTail = NULL;
}
RecycleBuffer(statePtr, bufPtr, 0);
}
}
} /* Closes "while". */
/*
* If we wrote some data while flushing in the background, we are done.
* We can't finish the background flush until we run out of data and the
* channel becomes writable again. This ensures that all of the pending
* data has been flushed at the system level.
|
| ︙ | ︙ | |||
5966 5967 5968 5969 5970 5971 5972 |
/* State info for channel */
ChannelBuffer *bufPtr;
Tcl_Size copied;
int result;
Tcl_Encoding encoding = statePtr->encoding;
int binaryMode;
#define UTF_EXPANSION_FACTOR 1024
| | | 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 |
/* State info for channel */
ChannelBuffer *bufPtr;
Tcl_Size copied;
int result;
Tcl_Encoding encoding = statePtr->encoding;
int binaryMode;
#define UTF_EXPANSION_FACTOR 1024
int factor = UTF_EXPANSION_FACTOR;
if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
ResetFlag(statePtr, CHANNEL_EOF|CHANNEL_ENCODING_ERROR);
/* TODO: UpdateInterest not needed here? */
UpdateInterest(chanPtr);
Tcl_SetErrno(EILSEQ);
return -1;
|
| ︙ | ︙ | |||
6040 6041 6042 6043 6044 6045 6046 |
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
}
ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF);
statePtr->inputEncodingFlags &= ~TCL_ENCODING_END;
for (copied = 0; toRead != 0 ; ) {
| | | 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 |
if (GotFlag(statePtr, CHANNEL_EOF)) {
statePtr->inputEncodingFlags |= TCL_ENCODING_START;
}
ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF);
statePtr->inputEncodingFlags &= ~TCL_ENCODING_END;
for (copied = 0; toRead != 0 ; ) {
int copiedNow = -1;
if (statePtr->inQueueHead != NULL) {
if (binaryMode) {
copiedNow = ReadBytes(statePtr, objPtr, toRead);
} else {
copiedNow = ReadChars(statePtr, objPtr, toRead, &factor);
}
|
| ︙ | ︙ | |||
6189 6190 6191 6192 6193 6194 6195 | * * Side effects: * The storage of bytes in objPtr can cause (re-)allocation of memory. * *--------------------------------------------------------------------------- */ | | | | | | 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 |
*
* Side effects:
* The storage of bytes in objPtr can cause (re-)allocation of memory.
*
*---------------------------------------------------------------------------
*/
static int
ReadBytes(
ChannelState *statePtr, /* State of the channel to read. */
Tcl_Obj *objPtr, /* Input data is appended to this ByteArray
* object. Its length is how much space has
* been allocated to hold data, not how many
* bytes of data have been stored in the
* object. */
int bytesToRead) /* Maximum number of bytes to store, or -1 to
* get all available bytes. Bytes are obtained
* from the first buffer in the queue - even
* if this number is larger than the number of
* bytes available in the first buffer, only
* the bytes from the first buffer are
* returned. */
{
ChannelBuffer *bufPtr = statePtr->inQueueHead;
int srcLen = BytesLeft(bufPtr);
int toRead = bytesToRead>srcLen || bytesToRead<0 ? srcLen : bytesToRead;
TclAppendBytesToByteArray(objPtr, (unsigned char *) RemovePoint(bufPtr),
toRead);
bufPtr->nextRemoved += toRead;
return toRead;
}
|
| ︙ | ︙ | |||
6242 6243 6244 6245 6246 6247 6248 | * * Side effects: * None. * *--------------------------------------------------------------------------- */ | | | | | | < < | | | | | | 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 |
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
static int
ReadChars(
ChannelState *statePtr, /* State of channel to read. */
Tcl_Obj *objPtr, /* Input data is appended to this object.
* objPtr->length is how much space has been
* allocated to hold data, not how many bytes
* of data have been stored in the object. */
int charsToRead, /* Maximum number of characters to store, or
* TCL_INDEX_NONE to get all available characters.
* Characters are obtained from the first
* buffer in the queue -- even if this number
* is larger than the number of characters
* available in the first buffer, only the
* characters from the first buffer are
* returned. The exception is when there is
* not any complete character in the first
* buffer. In that case, a recursive call
* effectively obtains chars from the
* second buffer. */
int *factorPtr) /* On input, contains a guess of how many
* bytes need to be allocated to hold the
* result of converting N source bytes to
* UTF-8. On output, contains another guess
* based on the data seen so far. */
{
Tcl_Encoding encoding = statePtr->encoding;
Tcl_EncodingState savedState = statePtr->inputEncodingState;
ChannelBuffer *bufPtr = statePtr->inQueueHead;
int savedIEFlags = statePtr->inputEncodingFlags;
int savedFlags = statePtr->flags;
char *dst, *src = RemovePoint(bufPtr);
Tcl_Size numBytes;
int srcLen = BytesLeft(bufPtr);
/*
* One src byte can yield at most one character. So when the number of
* src bytes we plan to read is less than the limit on character count to
* be read, clearly we will remain within that limit, and we can use the
* value of "srcLen" as a tighter limit for sizing receiving buffers.
*/
int toRead = ((charsToRead<0)||(charsToRead > srcLen)) ? srcLen : charsToRead;
/*
* 'factor' is how much we guess that the bytes in the source buffer will
* expand when converted to UTF-8 chars. This guess comes from analyzing
* how many characters were produced by the previous pass.
*/
int factor = *factorPtr;
int dstLimit = TCL_UTF_MAX - 1 + toRead * factor / UTF_EXPANSION_FACTOR;
if (dstLimit <= 0) {
dstLimit = INT_MAX; /* avoid overflow */
}
(void)TclGetStringFromObj(objPtr, &numBytes);
TclAppendUtfToUtf(objPtr, NULL, dstLimit);
if (toRead == srcLen) {
Tcl_Size size;
dst = TclGetStringStorage(objPtr, &size) + numBytes;
dstLimit = (size - numBytes) > INT_MAX ? INT_MAX : (size - numBytes);
} else {
dst = TclGetString(objPtr) + numBytes;
}
/*
* This routine is burdened with satisfying several constraints. It cannot
* append more than 'charsToRead` chars onto objPtr. This is measured
* after encoding and translation transformations are completed. There is
* no precise number of src bytes that can be associated with the limit.
* Yet, when we are done, we must know precisely the number of src bytes
* that were consumed to produce the appended chars, so that all
* subsequent bytes are left in the buffers for future read operations.
*
* The consequence is that we have no choice but to implement a "trial and
* error" approach, where in general we may need to perform
* transformations and copies multiple times to achieve a consistent set
* of results. This takes the shape of a loop.
*/
while (1) {
int dstDecoded, dstRead, dstWrote, srcRead, numChars, code;
int flags = statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE;
if (charsToRead > 0) {
flags |= TCL_ENCODING_CHAR_LIMIT;
numChars = charsToRead;
}
|
| ︙ | ︙ | |||
6351 6352 6353 6354 6355 6356 6357 | * appear only in situations where there are no further bytes in any * buffers. */ assert(bufPtr->nextPtr == NULL || BytesLeft(bufPtr->nextPtr) == 0 || (statePtr->inputEncodingFlags & TCL_ENCODING_END) == 0); | | | 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 |
* appear only in situations where there are no further bytes in any
* buffers.
*/
assert(bufPtr->nextPtr == NULL || BytesLeft(bufPtr->nextPtr) == 0
|| (statePtr->inputEncodingFlags & TCL_ENCODING_END) == 0);
code = Tcl_ExternalToUtf(NULL, encoding, src, srcLen,
flags, &statePtr->inputEncodingState,
dst, dstLimit, &srcRead, &dstDecoded, &numChars);
if (code == TCL_CONVERT_UNKNOWN || code == TCL_CONVERT_SYNTAX
|| (code == TCL_CONVERT_MULTIBYTE && GotFlag(statePtr, CHANNEL_EOF))) {
SetFlag(statePtr, CHANNEL_ENCODING_ERROR);
code = TCL_OK;
|
| ︙ | ︙ | |||
6411 6412 6413 6414 6415 6416 6417 | * the eof char in the buffer. */ Tcl_SetObjLength(objPtr, numBytes); return -1; } | > | | | | | | | | | | > | 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 |
* the eof char in the buffer.
*/
Tcl_SetObjLength(objPtr, numBytes);
return -1;
}
{
/*
* There are chars leading the buffer before the eof char.
* Adjust the dstLimit so we go back and read only those
* and do not encounter the eof char this time.
*/
dstLimit = dstRead + (TCL_UTF_MAX - 1);
statePtr->flags = savedFlags;
statePtr->inputEncodingFlags = savedIEFlags;
statePtr->inputEncodingState = savedState;
continue;
}
}
/*
* 2) The other way to read fewer bytes than are decoded is when
* the final byte is \r and we're in a CRLF translation mode so
* we cannot decide whether to record \r or \n yet.
*/
|
| ︙ | ︙ | |||
6457 6458 6459 6460 6461 6462 6463 | /* * We decoded only the bare CR, and we cannot read a translated * char from that alone. We have to know what's next. So why do * we only have the one decoded char? */ | < > | | 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 |
/*
* We decoded only the bare CR, and we cannot read a translated
* char from that alone. We have to know what's next. So why do
* we only have the one decoded char?
*/
if (code != TCL_OK) {
int read, decoded, count;
char buffer[TCL_UTF_MAX + 1];
/*
* Didn't get everything the buffer could offer
*/
statePtr->flags = savedFlags;
|
| ︙ | ︙ | |||
6480 6481 6482 6483 6484 6485 6486 | /* * bug 73bb42fb: the result was not checked for an encoding error. * So, add a check as above for testing. * Leave eof check out, as typically only two characters are * handled. */ | | < | < < < < < < < < > > > > > > > > > > > | 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 |
/*
* bug 73bb42fb: the result was not checked for an encoding error.
* So, add a check as above for testing.
* Leave eof check out, as typically only two characters are
* handled.
*/
code = Tcl_ExternalToUtf(NULL, encoding, src, srcLen,
(statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE),
&statePtr->inputEncodingState, buffer, sizeof(buffer),
&read, &decoded, &count);
if (code == TCL_CONVERT_UNKNOWN || code == TCL_CONVERT_SYNTAX) {
SetFlag(statePtr, CHANNEL_ENCODING_ERROR);
code = TCL_OK;
}
if (count == 2) {
if (buffer[1] == '\n') {
/* \r\n translate to \n */
dst[0] = '\n';
bufPtr->nextRemoved += read;
} else {
dst[0] = '\r';
bufPtr->nextRemoved += srcRead;
}
statePtr->inputEncodingFlags &= ~TCL_ENCODING_START;
Tcl_SetObjLength(objPtr, numBytes + 1);
return 1;
}
} else if (GotFlag(statePtr, CHANNEL_EOF)) {
/*
* The bare \r is the only char and we will never read a
* subsequent char to make the determination.
*/
dst[0] = '\r';
bufPtr->nextRemoved = bufPtr->nextAdded;
Tcl_SetObjLength(objPtr, numBytes + 1);
return 1;
}
/*
* Revise the dstRead value so that the numChars calc below
* correctly computes zero characters read.
*/
|
| ︙ | ︙ | |||
6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 |
* when it converts \r\n into \n. The reduction in the number of chars
* is the difference in bytes read and written.
*/
numChars -= (dstRead - dstWrote);
if (charsToRead > 0 && numChars > charsToRead) {
/*
* TODO: This cannot happen anymore.
*
* We read more chars than allowed. Reset limits to prevent that
* and try again. Don't forget the extra padding of TCL_UTF_MAX
* bytes demanded by the Tcl_ExternalToUtf() call!
*/
| > | 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 |
* when it converts \r\n into \n. The reduction in the number of chars
* is the difference in bytes read and written.
*/
numChars -= (dstRead - dstWrote);
if (charsToRead > 0 && numChars > charsToRead) {
/*
* TODO: This cannot happen anymore.
*
* We read more chars than allowed. Reset limits to prevent that
* and try again. Don't forget the extra padding of TCL_UTF_MAX
* bytes demanded by the Tcl_ExternalToUtf() call!
*/
|
| ︙ | ︙ | |||
6661 6662 6663 6664 6665 6666 6667 |
TranslateInputEOL(
ChannelState *statePtr, /* Channel being read, for EOL translation and
* EOF character. */
char *dstStart, /* Output buffer filled with chars by applying
* appropriate EOL translation to source
* characters. */
const char *srcStart, /* Source characters. */
| | | | | | 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 |
TranslateInputEOL(
ChannelState *statePtr, /* Channel being read, for EOL translation and
* EOF character. */
char *dstStart, /* Output buffer filled with chars by applying
* appropriate EOL translation to source
* characters. */
const char *srcStart, /* Source characters. */
int *dstLenPtr, /* On entry, the maximum length of output
* buffer in bytes. On exit, the number of
* bytes actually used in output buffer. */
int *srcLenPtr) /* On entry, the length of source buffer. On
* exit, the number of bytes read from the
* source buffer. */
{
const char *eof = NULL;
int dstLen = *dstLenPtr;
int srcLen = *srcLenPtr;
int inEofChar = statePtr->inEofChar;
/*
* Depending on the translation mode in use, there's no need to scan more
* srcLen bytes at srcStart than can possibly transform to dstLen bytes.
* This keeps the scan for eof char below from being pointlessly long.
*/
|
| ︙ | ︙ | |||
6731 6732 6733 6734 6735 6736 6737 |
}
}
dstLen = srcLen;
break;
case TCL_TRANSLATE_CRLF: {
const char *crFound, *src = srcStart;
char *dst = dstStart;
| | | | 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 |
}
}
dstLen = srcLen;
break;
case TCL_TRANSLATE_CRLF: {
const char *crFound, *src = srcStart;
char *dst = dstStart;
int lesser = (dstLen < srcLen) ? dstLen : srcLen;
while ((crFound = (const char *)memchr(src, '\r', lesser))) {
int numBytes = crFound - src;
memmove(dst, src, numBytes);
dst += numBytes;
dstLen -= numBytes;
src += numBytes;
srcLen -= numBytes;
if (srcLen == 1) {
|
| ︙ | ︙ | |||
6771 6772 6773 6774 6775 6776 6777 |
srcLen = src + lesser - srcStart;
dstLen = dst + lesser - dstStart;
break;
}
case TCL_TRANSLATE_AUTO: {
const char *crFound, *src = srcStart;
char *dst = dstStart;
| | | | 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 |
srcLen = src + lesser - srcStart;
dstLen = dst + lesser - dstStart;
break;
}
case TCL_TRANSLATE_AUTO: {
const char *crFound, *src = srcStart;
char *dst = dstStart;
int lesser;
if (GotFlag(statePtr, INPUT_SAW_CR) && srcLen) {
if (*src == '\n') {
src++;
srcLen--;
}
ResetFlag(statePtr, INPUT_SAW_CR);
}
lesser = (dstLen < srcLen) ? dstLen : srcLen;
while ((crFound = (const char *)memchr(src, '\r', lesser))) {
int numBytes = crFound - src;
memmove(dst, src, numBytes);
dst[numBytes] = '\n';
dst += numBytes + 1;
dstLen -= numBytes + 1;
src += numBytes + 1;
srcLen -= numBytes + 1;
|
| ︙ | ︙ | |||
7596 7597 7598 7599 7600 7601 7602 |
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
return ((statePtr->encoding == GetBinaryEncoding()) && !statePtr->inEofChar
&& (!GotFlag(statePtr, TCL_READABLE) || (statePtr->inputTranslation == TCL_TRANSLATE_LF))
&& (!GotFlag(statePtr, TCL_WRITABLE) || (statePtr->outputTranslation == TCL_TRANSLATE_LF)));
}
| | | 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 |
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
return ((statePtr->encoding == GetBinaryEncoding()) && !statePtr->inEofChar
&& (!GotFlag(statePtr, TCL_READABLE) || (statePtr->inputTranslation == TCL_TRANSLATE_LF))
&& (!GotFlag(statePtr, TCL_WRITABLE) || (statePtr->outputTranslation == TCL_TRANSLATE_LF)));
}
/*
*----------------------------------------------------------------------
*
* Tcl_Eof --
*
* Returns 1 if the channel is at EOF, 0 otherwise.
*
|
| ︙ | ︙ | |||
7623 7624 7625 7626 7627 7628 7629 |
{
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
return 0;
}
| | | 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 |
{
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
if (GotFlag(statePtr, CHANNEL_ENCODING_ERROR)) {
return 0;
}
return GotFlag(statePtr, CHANNEL_EOF) ? 1 : 0;
}
/*
*----------------------------------------------------------------------
*
* TclChannelGetBlockingMode --
*
|
| ︙ | ︙ | |||
7675 7676 7677 7678 7679 7680 7681 |
int
Tcl_InputBlocked(
Tcl_Channel chan) /* Is this channel blocked? */
{
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
| | | 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 |
int
Tcl_InputBlocked(
Tcl_Channel chan) /* Is this channel blocked? */
{
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
return GotFlag(statePtr, CHANNEL_BLOCKED) ? 1 : 0;
}
/*
*----------------------------------------------------------------------
*
* Tcl_InputBuffered --
*
|
| ︙ | ︙ | |||
7727 7728 7729 7730 7731 7732 7733 | } /* *---------------------------------------------------------------------- * * Tcl_OutputBuffered -- * | | | | | | | 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 |
}
/*
*----------------------------------------------------------------------
*
* Tcl_OutputBuffered --
*
* Returns the number of bytes of output currently buffered in the common
* internal buffer of a channel.
*
* Results:
* The number of output bytes buffered, or zero if the channel is not open
* for writing.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Tcl_OutputBuffered(
Tcl_Channel chan) /* The channel to query. */
|
| ︙ | ︙ | |||
8069 8070 8071 8072 8073 8074 8075 |
}
}
if (len == 0 || HaveOpt(2, "-encoding")) {
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-encoding");
}
Tcl_DStringAppendElement(dsPtr,
| | | | 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 |
}
}
if (len == 0 || HaveOpt(2, "-encoding")) {
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-encoding");
}
Tcl_DStringAppendElement(dsPtr,
Tcl_GetEncodingName(statePtr->encoding));
if (len > 0) {
return TCL_OK;
}
}
if (len == 0 || HaveOpt(2, "-eofchar")) {
char buf[4] = "";
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-eofchar");
}
if ((flags & TCL_READABLE) && (statePtr->inEofChar != 0)) {
snprintf(buf, sizeof(buf), "%c", statePtr->inEofChar);
}
if (len > 0) {
Tcl_DStringAppend(dsPtr, buf, -1);
return TCL_OK;
}
Tcl_DStringAppendElement(dsPtr, buf);
}
if (len == 0 || HaveOpt(1, "-profile")) {
int profile;
const char *profileName;
|
| ︙ | ︙ | |||
8837 8838 8839 8840 8841 8842 8843 |
&& (statePtr->inQueueHead != NULL)
&& IsBufferReady(statePtr->inQueueHead)) {
/*
* Restart the timer in case a channel handler reenters the event loop
* before UpdateInterest gets called by Tcl_NotifyChannel.
*/
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
| | | 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 |
&& (statePtr->inQueueHead != NULL)
&& IsBufferReady(statePtr->inQueueHead)) {
/*
* Restart the timer in case a channel handler reenters the event loop
* before UpdateInterest gets called by Tcl_NotifyChannel.
*/
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
ChannelTimerProc,chanPtr);
Tcl_Preserve(statePtr);
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
Tcl_Release(statePtr);
} else {
statePtr->timer = NULL;
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
|
| ︙ | ︙ | |||
9242 9243 9244 9245 9246 9247 9248 |
*/
int
Tcl_FileEventObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which the channel for which
* to create the handler is found. */
| | | > | 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 |
*/
int
Tcl_FileEventObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which the channel for which
* to create the handler is found. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Channel *chanPtr; /* The channel to create the handler for. */
ChannelState *statePtr; /* State info for channel */
Tcl_Channel chan; /* The opaque type for the channel. */
const char *chanName;
int modeIndex; /* Index of mode argument. */
int mask;
Tcl_Size length; /* llength of callback script */
static const char *const modeOptions[] = {"readable", "writable", NULL};
static const int maskArray[] = {TCL_READABLE, TCL_WRITABLE};
if ((objc != 3) && (objc != 4)) {
Tcl_WrongNumArgs(interp, 1, objv, "channel event ?script?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
9298 9299 9300 9301 9302 9303 9304 |
return TCL_OK;
}
/*
* If we are supposed to delete a stored script, do so.
*/
| > | > > > > | 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 |
return TCL_OK;
}
/*
* If we are supposed to delete a stored script, do so.
*/
if ((objv[3]->bytes == NULL) && TclObjTypeHasProc(objv[3], lengthProc)) {
length = TclObjTypeLength(objv[3]);
} else {
TclGetStringFromObj(objv[3], &length);
}
if (0 == length) {
DeleteScriptRecord(interp, chanPtr, mask);
return TCL_OK;
}
/*
* Make the script record that will link between the event and the script
* to invoke. This also creates a channel event handler which will
|
| ︙ | ︙ | |||
9435 9436 9437 9438 9439 9440 9441 |
/*
* Allocate a new CopyState to maintain info about the current copy in
* progress. This structure will be deallocated when the copy is
* completed.
*/
| < | | 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 |
/*
* Allocate a new CopyState to maintain info about the current copy in
* progress. This structure will be deallocated when the copy is
* completed.
*/
csPtr = (CopyState *)Tcl_Alloc(offsetof(CopyState, buffer) + 1U + !moveBytes * inStatePtr->bufSize);
csPtr->bufSize = !moveBytes * inStatePtr->bufSize;
csPtr->readPtr = inPtr;
csPtr->writePtr = outPtr;
csPtr->refCount = 2; /* two references below (inStatePtr, outStatePtr) */
csPtr->readFlags = readFlags;
csPtr->writeFlags = writeFlags;
csPtr->toRead = toRead;
|
| ︙ | ︙ | |||
9815 9816 9817 9818 9819 9820 9821 |
sizeb = csPtr->bufSize;
} else {
sizeb = csPtr->toRead;
}
if (moveBytes) {
size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb,
| | | | 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 |
sizeb = csPtr->bufSize;
} else {
sizeb = csPtr->toRead;
}
if (moveBytes) {
size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb,
!GotFlag(inStatePtr, CHANNEL_NONBLOCKING));
} else {
size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb,
!GotFlag(inStatePtr, CHANNEL_NONBLOCKING)
,0 /* No append */);
/*
* In case of a recoverable encoding error, any data before
* the error should be written. This data is in the bufObj.
* Program flow for this case:
* - Check, if there are any remaining bytes to write
* - If yes, simulate a successful read to write them out
* - Come back here by the outer loop and read again
* - Do not enter in the if below, as there are no pending
* writes
* - Fail below with a read error
*/
if (size < 0 && Tcl_GetErrno() == EILSEQ) {
TclGetStringFromObj(bufObj, &sizePart);
if (sizePart > 0) {
size = sizePart;
}
|
| ︙ | ︙ | |||
10143 10144 10145 10146 10147 10148 10149 |
TclChannelPreserve((Tcl_Channel)chanPtr);
while (bytesToRead) {
/*
* Each pass through the loop is intended to process up to one channel
* buffer.
*/
| | | 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 |
TclChannelPreserve((Tcl_Channel)chanPtr);
while (bytesToRead) {
/*
* Each pass through the loop is intended to process up to one channel
* buffer.
*/
int bytesRead, bytesWritten;
ChannelBuffer *bufPtr = statePtr->inQueueHead;
/*
* Don't read more data if we have what we need.
*/
while (!bufPtr || /* We got no buffer! OR */
|
| ︙ | ︙ | |||
10178 10179 10180 10181 10182 10183 10184 |
goto readErr;
}
assert(IsBufferFull(bufPtr));
}
if (!bufPtr) {
| | > | 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 |
goto readErr;
}
assert(IsBufferFull(bufPtr));
}
if (!bufPtr) {
readErr:
UpdateInterest(chanPtr);
TclChannelRelease((Tcl_Channel)chanPtr);
return -1;
}
bytesRead = BytesLeft(bufPtr);
bytesWritten = bytesToRead;
|
| ︙ | ︙ | |||
10343 10344 10345 10346 10347 10348 10349 | * translations to be performed, and no inline signals to respond to. * * Result: * True if copying would be lossless. * *---------------------------------------------------------------------- */ | | | 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 |
* translations to be performed, and no inline signals to respond to.
*
* Result:
* True if copying would be lossless.
*
*----------------------------------------------------------------------
*/
int
Lossless(
ChannelState *inStatePtr,
ChannelState *outStatePtr,
long long toRead)
{
return inStatePtr->inEofChar == '\0' /* No eofChar to stop input */
&& inStatePtr->inputTranslation == TCL_TRANSLATE_LF
|
| ︙ | ︙ | |||
10714 10715 10716 10717 10718 10719 10720 |
* Always check bottom-most channel in the stack. This is the one that
* gets registered.
*/
chanPtr = ((Channel *) chan)->state->bottomChanPtr;
statePtr = chanPtr->state;
| | | 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 |
* Always check bottom-most channel in the stack. This is the one that
* gets registered.
*/
chanPtr = ((Channel *) chan)->state->bottomChanPtr;
statePtr = chanPtr->state;
hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return 0;
}
hPtr = Tcl_FindHashEntry(hTblPtr, statePtr->channelName);
if (hPtr == NULL) {
return 0;
}
|
| ︙ | ︙ | |||
10752 10753 10754 10755 10756 10757 10758 |
int
Tcl_IsChannelShared(
Tcl_Channel chan) /* The channel to query */
{
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
| | | 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 |
int
Tcl_IsChannelShared(
Tcl_Channel chan) /* The channel to query */
{
ChannelState *statePtr = ((Channel *) chan)->state;
/* State of real channel structure. */
return ((statePtr->refCount > 1) ? 1 : 0);
}
/*
*----------------------------------------------------------------------
*
* Tcl_IsChannelExisting --
*
|
| ︙ | ︙ | |||
11227 11228 11229 11230 11231 11232 11233 | * * TIP #219, Tcl Channel Reflection API. * Scans an error message for bad -code / -level directives. Returns a * modified copy with such directives corrected, and the input if it had * no problems. * * Results: | | | 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 | * * TIP #219, Tcl Channel Reflection API. * Scans an error message for bad -code / -level directives. Returns a * modified copy with such directives corrected, and the input if it had * no problems. * * Results: * A Tcl_Obj* * * Side effects: * None. * *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
11293 11294 11295 11296 11297 11298 11299 |
newcode = 1;
}
} else if (0 == strcmp(TclGetString(lv[i]), "-level")) {
/*
* !integer, integer != 0
*/
| | | 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 |
newcode = 1;
}
} else if (0 == strcmp(TclGetString(lv[i]), "-level")) {
/*
* !integer, integer != 0
*/
res = TclGetIntFromObj(NULL, lv [i+1], &val);
if ((res != TCL_OK) || (val != 0)) {
newlevel = 0;
}
}
}
/*
|
| ︙ | ︙ | |||
11477 11478 11479 11480 11481 11482 11483 | * representation. * *---------------------------------------------------------------------- */ static void DupChannelInternalRep( | | | | 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 |
* representation.
*
*----------------------------------------------------------------------
*/
static void
DupChannelInternalRep(
Tcl_Obj *srcPtr, /* Object with internal rep to copy. Must have
* an internal rep of type "Channel". */
Tcl_Obj *copyPtr) /* Object with internal rep to set. Must not
* currently have an internal rep.*/
{
ResolvedChanName *resPtr;
ChanGetInternalRep(srcPtr, resPtr);
assert(resPtr);
ChanSetInternalRep(copyPtr, resPtr);
|
| ︙ | ︙ | |||
11534 11535 11536 11537 11538 11539 11540 |
DumpFlags(
char *str,
int flags)
{
int i = 0;
char buf[24];
| | < | 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 |
DumpFlags(
char *str,
int flags)
{
int i = 0;
char buf[24];
#define ChanFlag(chr, bit) (buf[i++] = ((flags & (bit)) ? (chr) : '_'))
ChanFlag('r', TCL_READABLE);
ChanFlag('w', TCL_WRITABLE);
ChanFlag('n', CHANNEL_NONBLOCKING);
ChanFlag('l', CHANNEL_LINEBUFFERED);
ChanFlag('u', CHANNEL_UNBUFFERED);
ChanFlag('F', BG_FLUSH_SCHEDULED);
|
| ︙ | ︙ |
Changes to generic/tclIO.h.
1 2 3 4 5 6 | /* * tclIO.h -- * * This file provides the generic portions (those that are the same on * all platforms and for all channel types) of Tcl's IO facilities. * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * tclIO.h -- * * This file provides the generic portions (those that are the same on * all platforms and for all channel types) of Tcl's IO facilities. * * Copyright (c) 1998-2000 Ajuba Solutions * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ /* * Make sure that both EAGAIN and EWOULDBLOCK are defined. This does not |
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
* One of these structures is allocated for each open channel. It contains
* data specific to the channel but which belongs to the generic part of the
* Tcl channel mechanism, and it points at an instance specific (and type
* specific) instance data, and at a channel type structure.
*/
typedef struct Channel {
| | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
* One of these structures is allocated for each open channel. It contains
* data specific to the channel but which belongs to the generic part of the
* Tcl channel mechanism, and it points at an instance specific (and type
* specific) instance data, and at a channel type structure.
*/
typedef struct Channel {
struct ChannelState *state; /* Split out state information */
void *instanceData; /* Instance-specific data provided by creator
* of channel. */
const Tcl_ChannelType *typePtr; /* Pointer to channel type structure. */
struct Channel *downChanPtr;/* Refers to channel this one was stacked
* upon. This reference is NULL for normal
* channels. See Tcl_StackChannel. */
struct Channel *upChanPtr; /* Refers to the channel above stacked this
|
| ︙ | ︙ | |||
125 126 127 128 129 130 131 |
* specific) instance data, and at a channel type structure.
*/
typedef struct ChannelState {
char *channelName; /* The name of the channel instance in Tcl
* commands. Storage is owned by the generic
* IO code, is dynamically allocated. */
| | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
* specific) instance data, and at a channel type structure.
*/
typedef struct ChannelState {
char *channelName; /* The name of the channel instance in Tcl
* commands. Storage is owned by the generic
* IO code, is dynamically allocated. */
int flags; /* OR'ed combination of the flags defined
* below. */
Tcl_Encoding encoding; /* Encoding to apply when reading or writing
* data on this channel. NULL means no
* encoding is applied to data. */
Tcl_EncodingState inputEncodingState;
/* Current encoding state, used when
* converting input data bytes to UTF-8. */
|
| ︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
/* What translation to apply for end of line
* sequences on input? */
TclEolTranslation outputTranslation;
/* What translation to use for generating end
* of line sequences in output? */
int inEofChar; /* If nonzero, use this as a signal of EOF on
* input. */
int unreportedError; /* Non-zero if an error report was deferred
* because it happened in the background. The
* value is the POSIX error code. */
Tcl_Size refCount; /* How many interpreters hold references to
* this IO channel? */
struct CloseCallback *closeCbPtr;
/* Callbacks registered to be called when the
| > > > > > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
/* What translation to apply for end of line
* sequences on input? */
TclEolTranslation outputTranslation;
/* What translation to use for generating end
* of line sequences in output? */
int inEofChar; /* If nonzero, use this as a signal of EOF on
* input. */
#if TCL_MAJOR_VERSION < 9
int outEofChar; /* If nonzero, append this to the channel when
* it is closed if it is open for writing.
* For Tcl 8.x only */
#endif
int unreportedError; /* Non-zero if an error report was deferred
* because it happened in the background. The
* value is the POSIX error code. */
Tcl_Size refCount; /* How many interpreters hold references to
* this IO channel? */
struct CloseCallback *closeCbPtr;
/* Callbacks registered to be called when the
|
| ︙ | ︙ | |||
223 224 225 226 227 228 229 | /* * Values for the flags field in Channel. Any OR'ed combination of the * following flags can be stored in the field. These flags record various * options and state bits about the channel. In addition to the flags below, * the channel can also have TCL_READABLE (1<<1) and TCL_WRITABLE (1<<2) set. */ | | | > | > | | | > | | > | > | | | | | > | | > | | | > | | | | < | | > | | | > | | | | | < | | < | | | | | | > | | | | | < | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | /* * Values for the flags field in Channel. Any OR'ed combination of the * following flags can be stored in the field. These flags record various * options and state bits about the channel. In addition to the flags below, * the channel can also have TCL_READABLE (1<<1) and TCL_WRITABLE (1<<2) set. */ #define CHANNEL_NONBLOCKING (1<<6) /* Channel is currently in nonblocking * mode. */ #define BG_FLUSH_SCHEDULED (1<<7) /* A background flush of the queued * output buffers has been * scheduled. */ #define CHANNEL_CLOSED (1<<8) /* Channel has been closed. No further * Tcl-level IO on the channel is * allowed. */ #define CHANNEL_EOF (1<<9) /* EOF occurred on this channel. This * bit is cleared before every input * operation. */ #define CHANNEL_STICKY_EOF (1<<10) /* EOF occurred on this channel * because we saw the input * eofChar. This bit prevents clearing * of the EOF bit before every input * operation. */ #define CHANNEL_BLOCKED (1<<11) /* EWOULDBLOCK or EAGAIN occurred on * this channel. This bit is cleared * before every input or output * operation. */ #define INPUT_SAW_CR (1<<12) /* Channel is in CRLF eol input * translation mode and the last byte * seen was a "\r". */ #define CHANNEL_DEAD (1<<13) /* The channel has been closed by the * exit handler (on exit) but not * deallocated. When any IO operation * sees this flag on a channel, it * does not call driver level * functions to avoid referring to * deallocated data. */ #define CHANNEL_NEED_MORE_DATA (1<<14) /* The last input operation failed * because there was not enough data * to complete the operation. This * flag is set when gets fails to get * a complete line or when read fails * to get a complete character. When * set, file events will not be * delivered for buffered data until * the state of the channel * changes. */ #define CHANNEL_ENCODING_ERROR (1<<15) /* set if channel * encountered an encoding error */ #define CHANNEL_RAW_MODE (1<<16) /* When set, notes that the Raw API is * being used. */ #define CHANNEL_LINEBUFFERED (1<<17) /* Output to the channel must be * flushed after every newline. */ #define CHANNEL_UNBUFFERED (1<<18) /* Output to the channel must always * be flushed immediately. */ #define CHANNEL_INCLOSE (1<<19) /* Channel is currently being closed. * Its structures are still live and * usable, but it may not be closed * again from within the close * handler. */ #define CHANNEL_CLOSEDWRITE (1<<21) /* Channel write side has been closed. * No further Tcl-level write IO on * the channel is allowed. */ /* * The length of time to wait between synthetic timer events. Must be zero or * bad things tend to happen. */ #define SYNTHETIC_EVENT_TIME 0 |
| ︙ | ︙ |
Changes to generic/tclIOCmd.c.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
typedef struct {
int initialized; /* Set to 1 when the module is initialized. */
Tcl_Obj *stdoutObjPtr; /* Cached stdout channel Tcl_Obj */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
| < < < < < < < | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
typedef struct {
int initialized; /* Set to 1 when the module is initialized. */
Tcl_Obj *stdoutObjPtr; /* Cached stdout channel Tcl_Obj */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
* Static functions for this file:
*/
static Tcl_ExitProc FinalizeIOCmdTSD;
static Tcl_TcpAcceptProc AcceptCallbackProc;
static Tcl_ObjCmdProc ChanPendingObjCmd;
static Tcl_ObjCmdProc ChanTruncateObjCmd;
static void RegisterTcpServerInterpCleanup(
Tcl_Interp *interp,
AcceptCallback *acceptCallbackPtr);
static Tcl_InterpDeleteProc TcpAcceptCallbacksDeleteProc;
static void TcpServerCloseProc(void *callbackData);
static void UnregisterTcpServerInterpCleanupProc(
Tcl_Interp *interp,
AcceptCallback *acceptCallbackPtr);
/*
*----------------------------------------------------------------------
*
* FinalizeIOCmdTSD --
*
* Release the storage associated with the per-thread cache.
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 |
*----------------------------------------------------------------------
*/
int
Tcl_PutsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
*----------------------------------------------------------------------
*/
int
Tcl_PutsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan; /* The channel to puts on. */
Tcl_Obj *string; /* String to write. */
Tcl_Obj *chanObjPtr = NULL; /* channel object. */
int newline; /* Add a newline at end? */
Tcl_Size result; /* Result of puts operation. */
int mode; /* Mode in which channel is opened. */
|
| ︙ | ︙ | |||
247 248 249 250 251 252 253 |
*----------------------------------------------------------------------
*/
int
Tcl_FlushObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
*----------------------------------------------------------------------
*/
int
Tcl_FlushObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *chanObjPtr;
Tcl_Channel chan; /* The channel to flush on. */
int mode;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "channel");
|
| ︙ | ︙ | |||
311 312 313 314 315 316 317 |
*----------------------------------------------------------------------
*/
int
Tcl_GetsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
*----------------------------------------------------------------------
*/
int
Tcl_GetsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan; /* The channel to read from. */
Tcl_Size lineLen; /* Length of line just read. */
int mode; /* Mode in which channel is opened. */
Tcl_Obj *linePtr, *chanObjPtr;
int code = TCL_OK;
|
| ︙ | ︙ | |||
397 398 399 400 401 402 403 |
*----------------------------------------------------------------------
*/
int
Tcl_ReadObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | < | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
*----------------------------------------------------------------------
*/
int
Tcl_ReadObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan; /* The channel to read from. */
int newline, i; /* Discard newline at end? */
Tcl_WideInt toRead; /* How many bytes to read? */
Tcl_Size charactersRead; /* How many characters were read? */
int mode; /* Mode in which channel is opened. */
Tcl_Obj *resultPtr, *chanObjPtr;
if ((objc != 2) && (objc != 3)) {
Interp *iPtr;
argerror:
iPtr = (Interp *) interp;
|
| ︙ | ︙ | |||
462 463 464 465 466 467 468 |
|| (toRead < 0)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected non-negative integer but got \"%s\"",
TclGetString(objv[i])));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", (char *)NULL);
return TCL_ERROR;
}
| < < < < | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
|| (toRead < 0)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected non-negative integer but got \"%s\"",
TclGetString(objv[i])));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "NUMBER", (char *)NULL);
return TCL_ERROR;
}
}
TclNewObj(resultPtr);
TclChannelPreserve(chan);
charactersRead = Tcl_ReadChars(chan, resultPtr, toRead, 0);
if (charactersRead == TCL_IO_FAILURE) {
Tcl_Obj *returnOptsPtr = NULL;
|
| ︙ | ︙ | |||
539 540 541 542 543 544 545 |
*----------------------------------------------------------------------
*/
int
Tcl_SeekObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
*----------------------------------------------------------------------
*/
int
Tcl_SeekObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan; /* The channel to tell on. */
Tcl_WideInt offset; /* Where to seek? */
int mode; /* How to seek? */
Tcl_WideInt result; /* Of calling Tcl_Seek. */
int optionIndex;
static const char *const originOptions[] = {
|
| ︙ | ︙ | |||
614 615 616 617 618 619 620 |
*----------------------------------------------------------------------
*/
int
Tcl_TellObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
*----------------------------------------------------------------------
*/
int
Tcl_TellObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan; /* The channel to tell on. */
Tcl_WideInt newLoc;
int code;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "channel");
|
| ︙ | ︙ | |||
675 676 677 678 679 680 681 |
*----------------------------------------------------------------------
*/
int
Tcl_CloseObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 |
*----------------------------------------------------------------------
*/
int
Tcl_CloseObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan; /* The channel to close. */
static const char *const dirOptions[] = {
"read", "write", NULL
};
static const int dirArray[] = {TCL_CLOSE_READ, TCL_CLOSE_WRITE};
|
| ︙ | ︙ | |||
783 784 785 786 787 788 789 |
*----------------------------------------------------------------------
*/
int
Tcl_FconfigureObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 |
*----------------------------------------------------------------------
*/
int
Tcl_FconfigureObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *optionName, *valueName;
Tcl_Channel chan; /* The channel to set a mode on. */
int i; /* Iterate over arg-value pairs. */
if ((objc < 2) || (((objc % 2) == 1) && (objc != 3))) {
Tcl_WrongNumArgs(interp, 1, objv, "channel ?-option value ...?");
return TCL_ERROR;
}
if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
|
| ︙ | ︙ | |||
858 859 860 861 862 863 864 |
*---------------------------------------------------------------------------
*/
int
Tcl_EofObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 |
*---------------------------------------------------------------------------
*/
int
Tcl_EofObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "channel");
return TCL_ERROR;
}
if (TclGetChannelFromObj(interp, objv[1], &chan, NULL, 0) != TCL_OK) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(Tcl_Eof(chan)));
return TCL_OK;
}
/*
*---------------------------------------------------------------------------
*
* ChanIsBinaryCmd --
*
* This function is invoked to process the Tcl "chan isbinary" command. See the
* user documentation for details on what it does.
|
| ︙ | ︙ | |||
898 899 900 901 902 903 904 |
*---------------------------------------------------------------------------
*/
static int
ChanIsBinaryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 |
*---------------------------------------------------------------------------
*/
static int
ChanIsBinaryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "channel");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
937 938 939 940 941 942 943 |
*----------------------------------------------------------------------
*/
int
Tcl_ExecObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
*----------------------------------------------------------------------
*/
int
Tcl_ExecObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *resultPtr;
const char **argv; /* An array for the string arguments. Stored
* on the _Tcl_ stack. */
const char *string;
Tcl_Channel chan;
int argc, background, i, index, keepNewline, result, skip, ignoreStderr;
Tcl_Size length;
static const char *const options[] = {
"-ignorestderr", "-keepnewline", "-encoding", "--", NULL
};
enum execOptionsEnum {
EXEC_IGNORESTDERR, EXEC_KEEPNEWLINE, EXEC_ENCODING, EXEC_LAST
};
Tcl_Obj *encodingObj = NULL;
|
| ︙ | ︙ | |||
983 984 985 986 987 988 989 |
keepNewline = 1;
break;
case EXEC_IGNORESTDERR:
ignoreStderr = 1;
break;
case EXEC_ENCODING:
if (++skip >= objc) {
| | > | 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 |
keepNewline = 1;
break;
case EXEC_IGNORESTDERR:
ignoreStderr = 1;
break;
case EXEC_ENCODING:
if (++skip >= objc) {
Tcl_SetResult(interp, "No value given for option -encoding.",
TCL_STATIC);
return TCL_ERROR;
} else {
Tcl_Encoding encoding;
encodingObj = objv[skip];
/* Verify validity - bug [da5e1bc7bc] */
if (Tcl_GetEncodingFromObj(interp, encodingObj, &encoding)
!= TCL_OK) {
|
| ︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 |
/* Bug [0f1ddc0df7] - encoding errors - use replace profile */
if (Tcl_SetChannelOption(interp, chan, "-profile", "replace") != TCL_OK) {
goto errorWithOpenChannel;
}
/* TIP 716 */
if (encodingObj &&
| | | | 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 |
/* Bug [0f1ddc0df7] - encoding errors - use replace profile */
if (Tcl_SetChannelOption(interp, chan, "-profile", "replace") != TCL_OK) {
goto errorWithOpenChannel;
}
/* TIP 716 */
if (encodingObj &&
Tcl_SetChannelOption(interp, chan, "-encoding",
Tcl_GetString(encodingObj)) != TCL_OK) {
goto errorWithOpenChannel;
}
TclNewObj(resultPtr);
if (Tcl_GetChannelHandle(chan, TCL_READABLE, NULL) == TCL_OK) {
if (Tcl_ReadChars(chan, resultPtr, -1, 0) == TCL_IO_FAILURE) {
/*
|
| ︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 |
*---------------------------------------------------------------------------
*/
int
Tcl_FblockedObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 |
*---------------------------------------------------------------------------
*/
int
Tcl_FblockedObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan;
int mode;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "channel");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1187 1188 1189 1190 1191 1192 1193 |
*----------------------------------------------------------------------
*/
int
Tcl_OpenObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 |
*----------------------------------------------------------------------
*/
int
Tcl_OpenObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int pipeline, prot;
const char *modeString, *what;
Tcl_Channel chan;
if ((objc < 2) || (objc > 4)) {
Tcl_WrongNumArgs(interp, 1, objv, "fileName ?access? ?permissions?");
return TCL_ERROR;
}
prot = 0666;
if (objc == 2) {
modeString = "r";
} else {
modeString = TclGetString(objv[2]);
if (objc == 4) {
const char *permString = TclGetString(objv[3]);
int code = TCL_ERROR;
int scanned = TclParseAllWhiteSpace(permString, -1);
/*
* Support legacy octal numbers.
*/
if ((permString[scanned] == '0')
&& (permString[scanned+1] >= '0')
|
| ︙ | ︙ | |||
1309 1310 1311 1312 1313 1314 1315 | * subsequently to eval accept scripts. * *---------------------------------------------------------------------- */ static void TcpAcceptCallbacksDeleteProc( | | | 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
* subsequently to eval accept scripts.
*
*----------------------------------------------------------------------
*/
static void
TcpAcceptCallbacksDeleteProc(
void *clientData, /* Data which was passed when the assocdata
* was registered. */
TCL_UNUSED(Tcl_Interp *))
{
Tcl_HashTable *hTblPtr = (Tcl_HashTable *)clientData;
Tcl_HashEntry *hPtr;
Tcl_HashSearch hSearch;
|
| ︙ | ︙ | |||
1361 1362 1363 1364 1365 1366 1367 |
{
Tcl_HashTable *hTblPtr; /* Hash table for accept callback records to
* smash when the interpreter will be
* deleted. */
Tcl_HashEntry *hPtr; /* Entry for this record. */
int isNew; /* Is the entry new? */
| | | | 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 |
{
Tcl_HashTable *hTblPtr; /* Hash table for accept callback records to
* smash when the interpreter will be
* deleted. */
Tcl_HashEntry *hPtr; /* Entry for this record. */
int isNew; /* Is the entry new? */
hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL);
if (hTblPtr == NULL) {
hTblPtr = (Tcl_HashTable *)Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(hTblPtr, TCL_ONE_WORD_KEYS);
Tcl_SetAssocData(interp, "tclTCPAcceptCallbacks",
TcpAcceptCallbacksDeleteProc, hTblPtr);
}
hPtr = Tcl_CreateHashEntry(hTblPtr, acceptCallbackPtr, &isNew);
if (!isNew) {
Tcl_Panic("RegisterTcpServerCleanup: damaged accept record table");
}
|
| ︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 |
AcceptCallback *acceptCallbackPtr)
/* The record for which to delete the
* registration. */
{
Tcl_HashTable *hTblPtr;
Tcl_HashEntry *hPtr;
| | | 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 |
AcceptCallback *acceptCallbackPtr)
/* The record for which to delete the
* registration. */
{
Tcl_HashTable *hTblPtr;
Tcl_HashEntry *hPtr;
hTblPtr = (Tcl_HashTable *)Tcl_GetAssocData(interp, "tclTCPAcceptCallbacks", NULL);
if (hTblPtr == NULL) {
return;
}
hPtr = Tcl_FindHashEntry(hTblPtr, acceptCallbackPtr);
if (hPtr != NULL) {
Tcl_DeleteHashEntry(hPtr);
|
| ︙ | ︙ | |||
1437 1438 1439 1440 1441 1442 1443 | * Whatever the script does. * *---------------------------------------------------------------------- */ static void AcceptCallbackProc( | | | 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 |
* Whatever the script does.
*
*----------------------------------------------------------------------
*/
static void
AcceptCallbackProc(
void *callbackData, /* The data stored when the callback was
* created in the call to
* Tcl_OpenTcpServer. */
Tcl_Channel chan, /* Channel for the newly accepted
* connection. */
char *address, /* Address of client that was accepted. */
int port) /* Port of client that was accepted. */
{
|
| ︙ | ︙ | |||
1528 1529 1530 1531 1532 1533 1534 | * longer be informed. * *---------------------------------------------------------------------- */ static void TcpServerCloseProc( | | | 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 |
* longer be informed.
*
*----------------------------------------------------------------------
*/
static void
TcpServerCloseProc(
void *callbackData) /* The data passed in the call to
* Tcl_CreateCloseHandler. */
{
AcceptCallback *acceptCallbackPtr = (AcceptCallback *)callbackData;
/* The actual data. */
if (acceptCallbackPtr->interp != NULL) {
UnregisterTcpServerInterpCleanupProc(acceptCallbackPtr->interp,
|
| ︙ | ︙ | |||
1563 1564 1565 1566 1567 1568 1569 |
*----------------------------------------------------------------------
*/
int
Tcl_SocketObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 |
*----------------------------------------------------------------------
*/
int
Tcl_SocketObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const socketOptions[] = {
"-async", "-backlog", "-myaddr", "-myport", "-reuseaddr",
"-reuseport", "-server", NULL
};
enum socketOptionsEnum {
SKT_ASYNC, SKT_BACKLOG, SKT_MYADDR, SKT_MYPORT, SKT_REUSEADDR,
SKT_REUSEPORT, SKT_SERVER
} optionIndex;
int a, server = 0, myport = 0, async = 0, reusep = -1,
reusea = -1, backlog = -1;
unsigned int flags = 0;
const char *host, *port, *myaddr = NULL;
Tcl_Obj *script = NULL;
Tcl_Channel chan;
TclInitSockets();
|
| ︙ | ︙ | |||
1814 1815 1816 1817 1818 1819 1820 |
*----------------------------------------------------------------------
*/
int
Tcl_FcopyObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | < | 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 |
*----------------------------------------------------------------------
*/
int
Tcl_FcopyObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel inChan, outChan;
int mode, i, index;
Tcl_WideInt toRead;
Tcl_Obj *cmdPtr;
static const char *const switches[] = { "-size", "-command", NULL };
enum { FcopySize, FcopyCommand };
if ((objc < 3) || (objc > 7) || (objc == 4) || (objc == 6)) {
Tcl_WrongNumArgs(interp, 1, objv,
|
| ︙ | ︙ | |||
1912 1913 1914 1915 1916 1917 1918 |
*---------------------------------------------------------------------------
*/
static int
ChanPendingObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 |
*---------------------------------------------------------------------------
*/
static int
ChanPendingObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan;
static const char *const options[] = {"input", "output", NULL};
enum pendingOptionsEnum {PENDING_INPUT, PENDING_OUTPUT} index;
int mode;
if (objc != 3) {
|
| ︙ | ︙ | |||
1976 1977 1978 1979 1980 1981 1982 |
*----------------------------------------------------------------------
*/
static int
ChanTruncateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 |
*----------------------------------------------------------------------
*/
static int
ChanTruncateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel chan;
Tcl_WideInt length;
if ((objc < 2) || (objc > 3)) {
Tcl_WrongNumArgs(interp, 1, objv, "channel ?length?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2049 2050 2051 2052 2053 2054 2055 |
*----------------------------------------------------------------------
*/
static int
ChanPipeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 |
*----------------------------------------------------------------------
*/
static int
ChanPipeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Channel rchan, wchan;
const char *channelNames[2];
Tcl_Obj *resultPtr;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
|
| ︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 |
*----------------------------------------------------------------------
*/
int
TclChannelNamesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | | | | | < | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 |
*----------------------------------------------------------------------
*/
int
TclChannelNamesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc < 1 || objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?pattern?");
return TCL_ERROR;
}
return Tcl_GetChannelNamesEx(interp,
((objc == 1) ? NULL : TclGetString(objv[1])));
}
/*
*----------------------------------------------------------------------
*
* TclInitChanCmd --
*
* This function is invoked to create the "chan" Tcl command. See the
* user documentation for details on what it does.
*
* Results:
* A Tcl command handle.
*
* Side effects:
* None (since nothing is byte-compiled).
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitChanCmd(
Tcl_Interp *interp)
{
/*
* Most commands are plugged directly together, but some are done via
* alias-like rewriting; [chan configure] is this way for security reasons
* (want overwriting of [fconfigure] to control that nicely), and [chan
* names] because the functionality isn't available as a separate command
* function at the moment.
*/
static const EnsembleImplMap initMap[] = {
{"blocked", Tcl_FblockedObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"close", Tcl_CloseObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"copy", Tcl_FcopyObjCmd, NULL, NULL, NULL, 0},
{"create", TclChanCreateObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #219 */
{"eof", Tcl_EofObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"event", Tcl_FileEventObjCmd, TclCompileBasic2Or3ArgCmd, NULL, NULL, 0},
{"flush", Tcl_FlushObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"gets", Tcl_GetsObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"isbinary", ChanIsBinaryCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"names", TclChannelNamesCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"pending", ChanPendingObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #287 */
{"pipe", ChanPipeObjCmd, TclCompileBasic0ArgCmd, NULL, NULL, 0}, /* TIP #304 */
{"pop", TclChanPopObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, /* TIP #230 */
{"postevent", TclChanPostEventObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #219 */
{"push", TclChanPushObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0}, /* TIP #230 */
{"puts", Tcl_PutsObjCmd, NULL, NULL, NULL, 0},
{"read", Tcl_ReadObjCmd, NULL, NULL, NULL, 0},
{"seek", Tcl_SeekObjCmd, TclCompileBasic2Or3ArgCmd, NULL, NULL, 0},
{"tell", Tcl_TellObjCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"truncate", ChanTruncateObjCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0}, /* TIP #208 */
{NULL, NULL, NULL, NULL, NULL, 0}
};
static const char *const extras[] = {
"configure", "::fconfigure",
NULL
};
Tcl_Command ensemble;
Tcl_Obj *mapObj;
int i;
ensemble = TclMakeEnsemble(interp, "chan", initMap);
Tcl_GetEnsembleMappingDict(NULL, ensemble, &mapObj);
for (i=0 ; extras[i] ; i+=2) {
/*
* Can assume that reference counts are all incremented.
*/
TclDictPutString(NULL, mapObj, extras[i], extras[i + 1]);
}
Tcl_SetEnsembleMappingDict(interp, ensemble, mapObj);
return ensemble;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclIOGT.c.
| ︙ | ︙ | |||
52 53 54 55 56 57 58 | * encapsulating essential tasks. */ typedef struct TransformChannelData TransformChannelData; static int ExecuteCallback(TransformChannelData *ctrl, Tcl_Interp *interp, unsigned char *op, | | | | | | | | < | | | < | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
* encapsulating essential tasks.
*/
typedef struct TransformChannelData TransformChannelData;
static int ExecuteCallback(TransformChannelData *ctrl,
Tcl_Interp *interp, unsigned char *op,
unsigned char *buf, int bufLen, int transmit,
int preserve);
/*
* Action codes to give to 'ExecuteCallback' (argument 'transmit'), telling
* the procedure what to do with the result of the script it calls.
*/
#define TRANSMIT_DONT 0 /* No transfer to do. */
#define TRANSMIT_DOWN 1 /* Transfer to the underlying channel. */
#define TRANSMIT_SELF 2 /* Transfer into our channel. */
#define TRANSMIT_IBUF 3 /* Transfer to internal input buffer. */
#define TRANSMIT_NUM 4 /* Transfer number to 'maxRead'. */
/*
* Codes for 'preserve' of 'ExecuteCallback'.
*/
#define P_PRESERVE 1
#define P_NO_PRESERVE 0
/*
* Strings for the action codes delivered to the script implementing a
* transformation. Argument 'op' of 'ExecuteCallback'.
*/
#define A_CREATE_WRITE (UCHARP("create/write"))
|
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
NULL, /* Thread action proc. */
NULL /* Truncate proc. */
};
/*
* Possible values for 'flags' field in control structure, see below.
*/
| | | < | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
NULL, /* Thread action proc. */
NULL /* Truncate proc. */
};
/*
* Possible values for 'flags' field in control structure, see below.
*/
#define CHANNEL_ASYNC (1<<0) /* Non-blocking mode. */
/*
* Definition of the structure containing the information about the internal
* input buffer.
*/
struct ResultBuffer {
|
| ︙ | ︙ | |||
266 267 268 269 270 271 272 |
Tcl_DString ds;
if (chan == NULL) {
return TCL_ERROR;
}
if (TCL_OK != TclListObjLength(interp, cmdObjPtr, &objc)) {
| | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
Tcl_DString ds;
if (chan == NULL) {
return TCL_ERROR;
}
if (TCL_OK != TclListObjLength(interp, cmdObjPtr, &objc)) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("-command value is not a list", -1));
return TCL_ERROR;
}
chanPtr = (Channel *) chan;
statePtr = chanPtr->state;
chanPtr = statePtr->topChanPtr;
chan = (Tcl_Channel) chanPtr;
|
| ︙ | ︙ | |||
365 366 367 368 369 370 371 |
static int
ExecuteCallback(
TransformChannelData *dataPtr,
/* Transformation with the callback. */
Tcl_Interp *interp, /* Current interpreter, possibly NULL. */
unsigned char *op, /* Operation invoking the callback. */
unsigned char *buf, /* Buffer to give to the script. */
| | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
static int
ExecuteCallback(
TransformChannelData *dataPtr,
/* Transformation with the callback. */
Tcl_Interp *interp, /* Current interpreter, possibly NULL. */
unsigned char *op, /* Operation invoking the callback. */
unsigned char *buf, /* Buffer to give to the script. */
int bufLen, /* And its length. */
int transmit, /* Flag, determines whether the result of the
* callback is sent to the underlying channel
* or not. */
int preserve) /* Flag. If true the procedure will preserve
* the result state of all accessed
* interpreters. */
{
|
| ︙ | ︙ | |||
514 515 516 517 518 519 520 | * 0 if successful, errno when failed. * *---------------------------------------------------------------------- */ static int TransformBlockModeProc( | | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
* 0 if successful, errno when failed.
*
*----------------------------------------------------------------------
*/
static int
TransformBlockModeProc(
void *instanceData, /* State of transformation. */
int mode) /* New blocking mode. */
{
TransformChannelData *dataPtr = (TransformChannelData *)instanceData;
if (mode == TCL_MODE_NONBLOCKING) {
dataPtr->flags |= CHANNEL_ASYNC;
} else {
|
| ︙ | ︙ | |||
636 637 638 639 640 641 642 |
TransformInputProc(
void *instanceData,
char *buf,
int toRead,
int *errorCodePtr)
{
TransformChannelData *dataPtr = (TransformChannelData *)instanceData;
| | < | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 |
TransformInputProc(
void *instanceData,
char *buf,
int toRead,
int *errorCodePtr)
{
TransformChannelData *dataPtr = (TransformChannelData *)instanceData;
int gotBytes, read, copied;
Tcl_Channel downChan;
/*
* Should assert(dataPtr->mode & TCL_READABLE);
*/
if (toRead == 0 || dataPtr->self == NULL) {
|
| ︙ | ︙ | |||
738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
* that zero bytes are available because blocked.
*/
*errorCodePtr = Tcl_GetErrno();
gotBytes = -1;
break;
} else if (read == 0) {
/*
* Zero returned from Tcl_ReadRaw() always indicates EOF
* on the down channel.
*/
dataPtr->eofPending = 1;
dataPtr->readIsFlushed = 1;
| > | 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 |
* that zero bytes are available because blocked.
*/
*errorCodePtr = Tcl_GetErrno();
gotBytes = -1;
break;
} else if (read == 0) {
/*
* Zero returned from Tcl_ReadRaw() always indicates EOF
* on the down channel.
*/
dataPtr->eofPending = 1;
dataPtr->readIsFlushed = 1;
|
| ︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | * None. * *---------------------------------------------------------------------- */ static void TransformWatchProc( | | | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 |
* None.
*
*----------------------------------------------------------------------
*/
static void
TransformWatchProc(
void *instanceData, /* Channel to watch. */
int mask) /* Events of interest. */
{
TransformChannelData *dataPtr = (TransformChannelData *)instanceData;
Tcl_Channel downChan;
/*
* The caller expressed interest in events occurring for this channel. We
|
| ︙ | ︙ | |||
1090 1091 1092 1093 1094 1095 1096 | * The appropriate Tcl_File or NULL if not present. * *---------------------------------------------------------------------- */ static int TransformGetFileHandleProc( | | | | 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 |
* The appropriate Tcl_File or NULL if not present.
*
*----------------------------------------------------------------------
*/
static int
TransformGetFileHandleProc(
void *instanceData, /* Channel to query. */
int direction, /* Direction of interest. */
void **handlePtr) /* Place to store the handle into. */
{
TransformChannelData *dataPtr = (TransformChannelData *)instanceData;
/*
* Return the handle belonging to parent channel. IOW, pass the request
* down and the result up.
*/
|
| ︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | * None. * *---------------------------------------------------------------------- */ static int TransformNotifyProc( | | | 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 |
* None.
*
*----------------------------------------------------------------------
*/
static int
TransformNotifyProc(
void *clientData, /* The state of the notified
* transformation. */
int mask) /* The mask of occurring events. */
{
TransformChannelData *dataPtr = (TransformChannelData *)clientData;
/*
* An event occurred in the underlying channel. This transformation doesn't
|
| ︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 | * None. * *---------------------------------------------------------------------- */ static void TransformChannelHandlerTimer( | | | 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 |
* None.
*
*----------------------------------------------------------------------
*/
static void
TransformChannelHandlerTimer(
void *clientData) /* Transformation to query. */
{
TransformChannelData *dataPtr = (TransformChannelData *)clientData;
dataPtr->timer = NULL;
if (!(dataPtr->watchMask&TCL_READABLE) || ResultEmpty(&dataPtr->result)) {
/*
* The timer fired, but either is there no (more) interest in the
|
| ︙ | ︙ |
Changes to generic/tclIORChan.c.
| ︙ | ︙ | |||
39 40 41 42 43 44 45 | static void ReflectWatch(void *clientData, int mask); static int ReflectBlock(void *clientData, int mode); #if TCL_THREADS static void ReflectThread(void *clientData, int action); static int ReflectEventRun(Tcl_Event *ev, int flags); static int ReflectEventDelete(Tcl_Event *ev, void *cd); #endif | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | static void ReflectWatch(void *clientData, int mask); static int ReflectBlock(void *clientData, int mode); #if TCL_THREADS static void ReflectThread(void *clientData, int action); static int ReflectEventRun(Tcl_Event *ev, int flags); static int ReflectEventDelete(Tcl_Event *ev, void *cd); #endif static long long ReflectSeekWide(void *clientData, long long offset, int mode, int *errorCodePtr); static int ReflectGetOption(void *clientData, Tcl_Interp *interp, const char *optionName, Tcl_DString *dsPtr); static int ReflectSetOption(void *clientData, Tcl_Interp *interp, const char *optionName, const char *newValue); |
| ︙ | ︙ | |||
497 498 499 500 501 502 503 |
*----------------------------------------------------------------------
*/
int
TclChanCreateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 |
*----------------------------------------------------------------------
*/
int
TclChanCreateObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
ReflectedChannel *rcPtr; /* Instance data of the new channel */
Tcl_Obj *rcId; /* Handle of the new channel */
int mode; /* R/W mode of new channel. Has to match
* abilities of handler commands */
Tcl_Obj *cmdObj; /* Command prefix, list of words */
|
| ︙ | ︙ | |||
729 730 731 732 733 734 735 |
if (!isNew && chanPtr != Tcl_GetHashValue(hPtr)) {
Tcl_Panic("TclChanCreateObjCmd: duplicate channel names");
}
Tcl_SetHashValue(hPtr, chan);
#if TCL_THREADS
rcmPtr = GetThreadReflectedChannelMap();
hPtr = Tcl_CreateHashEntry(&rcmPtr->map, chanPtr->state->channelName,
| | | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 |
if (!isNew && chanPtr != Tcl_GetHashValue(hPtr)) {
Tcl_Panic("TclChanCreateObjCmd: duplicate channel names");
}
Tcl_SetHashValue(hPtr, chan);
#if TCL_THREADS
rcmPtr = GetThreadReflectedChannelMap();
hPtr = Tcl_CreateHashEntry(&rcmPtr->map, chanPtr->state->channelName,
&isNew);
Tcl_SetHashValue(hPtr, chan);
#endif
/*
* Return handle as result of command.
*/
|
| ︙ | ︙ | |||
817 818 819 820 821 822 823 |
}
#endif
int
TclChanPostEventObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 |
}
#endif
int
TclChanPostEventObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
/*
* Ensure -> HANDLER thread
*
* Syntax: chan postevent CHANNEL EVENTSPEC
* [0] [1] [2] [3]
|
| ︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 |
*errorCodePtr = EOK;
if (bytec > 0) {
memcpy(buf, bytev, bytec);
}
| | | | | 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 |
*errorCodePtr = EOK;
if (bytec > 0) {
memcpy(buf, bytev, bytec);
}
stop:
Tcl_DecrRefCount(toReadObj);
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
Tcl_Release(rcPtr);
return (int)bytec;
invalid:
*errorCodePtr = EINVAL;
error:
bytec = -1;
goto stop;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1485 1486 1487 1488 1489 1490 1491 |
*/
SetChannelErrorStr(rcPtr->chan, msg_write_toomuch);
goto invalid;
}
*errorCodePtr = EOK;
| | | | | 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 |
*/
SetChannelErrorStr(rcPtr->chan, msg_write_toomuch);
goto invalid;
}
*errorCodePtr = EOK;
stop:
Tcl_DecrRefCount(bufObj);
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
Tcl_Release(rcPtr->interp);
Tcl_Release(rcPtr);
return written;
invalid:
*errorCodePtr = EINVAL;
error:
written = -1;
goto stop;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1578 1579 1580 1581 1582 1583 1584 |
if (newLoc < 0) {
SetChannelErrorStr(rcPtr->chan, msg_seek_beforestart);
goto invalid;
}
*errorCodePtr = EOK;
| | | | 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 |
if (newLoc < 0) {
SetChannelErrorStr(rcPtr->chan, msg_seek_beforestart);
goto invalid;
}
*errorCodePtr = EOK;
stop:
Tcl_DecrRefCount(offObj);
Tcl_DecrRefCount(baseObj);
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
Tcl_Release(rcPtr);
return newLoc;
invalid:
*errorCodePtr = EINVAL;
newLoc = -1;
goto stop;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1978 1979 1980 1981 1982 1983 1984 |
if (len) {
TclDStringAppendLiteral(dsPtr, " ");
Tcl_DStringAppend(dsPtr, str, len);
}
goto ok;
}
| | | | | 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 |
if (len) {
TclDStringAppendLiteral(dsPtr, " ");
Tcl_DStringAppend(dsPtr, str, len);
}
goto ok;
}
ok:
result = TCL_OK;
stop:
if (optionObj) {
Tcl_DecrRefCount(optionObj);
}
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
Tcl_Release(rcPtr);
return result;
error:
result = TCL_ERROR;
goto stop;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2946 2947 2948 2949 2950 2951 2952 | * waiting here? IOW Is it possible that "SrcExitProc" is called while * we are here? See complementary note (2) in "SrcExitProc" * * The ConditionWait unlocks the mutex during the wait and relocks it * immediately after. */ | | | 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 |
* waiting here? IOW Is it possible that "SrcExitProc" is called while
* we are here? See complementary note (2) in "SrcExitProc"
*
* The ConditionWait unlocks the mutex during the wait and relocks it
* immediately after.
*/
Tcl_ConditionWait(&resultPtr->done, &rcForwardMutex, NULL);
}
/*
* Unlink result from the forwarder list. No need to lock. Either still
* locked, or locked by the ConditionWait
*/
|
| ︙ | ︙ |
Changes to generic/tclIORTrans.c.
| ︙ | ︙ | |||
132 133 134 135 136 137 138 |
* argv [0] ... [.] | [argc-2] [argc-1] | [argc] [argc+2]
* cmd ... pfx | method chan | detail1 detail2
* ~~~~ CT ~~~ ~~ CT ~~
*
* CT = Belongs to the 'Command handler Thread'.
*/
| | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
* argv [0] ... [.] | [argc-2] [argc-1] | [argc] [argc+2]
* cmd ... pfx | method chan | detail1 detail2
* ~~~~ CT ~~~ ~~ CT ~~
*
* CT = Belongs to the 'Command handler Thread'.
*/
int argc; /* Number of preallocated words - 2. */
Tcl_Obj **argv; /* Preallocated array for calling the handler.
* args[0] is placeholder for cmd word.
* Followed by the arguments in the prefix,
* plus 4 placeholders for method, channel,
* and at most two varying (method specific)
* words. */
int methods; /* Bitmask of supported methods. */
|
| ︙ | ︙ | |||
354 355 356 357 358 359 360 |
ForwardedOperation op, void *param);
static int ForwardProc(Tcl_Event *evPtr, int mask);
static void SrcExitProc(void *clientData);
#define FreeReceivedError(p) \
do { \
if ((p)->base.mustFree) { \
| | | | | | | | | | | | | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
ForwardedOperation op, void *param);
static int ForwardProc(Tcl_Event *evPtr, int mask);
static void SrcExitProc(void *clientData);
#define FreeReceivedError(p) \
do { \
if ((p)->base.mustFree) { \
Tcl_Free((p)->base.msgStr); \
} \
} while (0)
#define PassReceivedErrorInterp(interp, p) \
do { \
if ((interp) != NULL) { \
Tcl_SetChannelErrorInterp((interp), \
Tcl_NewStringObj((p)->base.msgStr, -1)); \
} \
FreeReceivedError(p); \
} while (0)
#define PassReceivedError(chan, p) \
do { \
Tcl_SetChannelError((chan), \
Tcl_NewStringObj((p)->base.msgStr, -1)); \
FreeReceivedError(p); \
} while (0)
#define ForwardSetStaticError(p, emsg) \
do { \
(p)->base.code = TCL_ERROR; \
(p)->base.mustFree = 0; \
(p)->base.msgStr = (char *) (emsg); \
} while (0)
#define ForwardSetDynamicError(p, emsg) \
do { \
(p)->base.code = TCL_ERROR; \
(p)->base.mustFree = 1; \
(p)->base.msgStr = (char *) (emsg); \
} while (0)
static void ForwardSetObjError(ForwardParam *p,
Tcl_Obj *objPtr);
static ReflectedTransformMap * GetThreadReflectedTransformMap(void);
static void DeleteThreadReflectedTransformMap(
void *clientData);
#endif /* TCL_THREADS */
|
| ︙ | ︙ | |||
492 493 494 495 496 497 498 |
*----------------------------------------------------------------------
*/
int
TclChanPushObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 |
*----------------------------------------------------------------------
*/
int
TclChanPushObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
ReflectedTransform *rtPtr; /* Instance data of the new (transform)
* channel. */
Tcl_Obj *chanObj; /* Handle of parent channel */
Tcl_Channel parentChan; /* Token of parent channel */
int mode; /* R/W mode of parent, later the new channel.
|
| ︙ | ︙ | |||
691 692 693 694 695 696 697 |
hPtr = Tcl_CreateHashEntry(&rtmPtr->map, TclGetString(rtId), &isNew);
if (!isNew && rtPtr != Tcl_GetHashValue(hPtr)) {
Tcl_Panic("TclChanPushObjCmd: duplicate transformation handle");
}
Tcl_SetHashValue(hPtr, rtPtr);
#if TCL_THREADS
rtmPtr = GetThreadReflectedTransformMap();
| | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
hPtr = Tcl_CreateHashEntry(&rtmPtr->map, TclGetString(rtId), &isNew);
if (!isNew && rtPtr != Tcl_GetHashValue(hPtr)) {
Tcl_Panic("TclChanPushObjCmd: duplicate transformation handle");
}
Tcl_SetHashValue(hPtr, rtPtr);
#if TCL_THREADS
rtmPtr = GetThreadReflectedTransformMap();
hPtr = Tcl_CreateHashEntry(&rtmPtr->map, TclGetString(rtId), &isNew);
Tcl_SetHashValue(hPtr, rtPtr);
#endif /* TCL_THREADS */
/*
* Return the channel as the result of the command.
*/
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 |
*----------------------------------------------------------------------
*/
int
TclChanPopObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 |
*----------------------------------------------------------------------
*/
int
TclChanPopObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
/*
* Syntax: chan pop CHANNEL
* [0] [1] [2]
*
* Actually: rPop CHANNEL
|
| ︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 |
Tcl_DecrRefCount(bufObj);
TclNewObj(bufObj);
Tcl_IncrRefCount(bufObj);
}
Tcl_SetByteArrayLength(bufObj, 0);
} /* while toRead > 0 */
| | | | 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 |
Tcl_DecrRefCount(bufObj);
TclNewObj(bufObj);
Tcl_IncrRefCount(bufObj);
}
Tcl_SetByteArrayLength(bufObj, 0);
} /* while toRead > 0 */
stop:
if (gotBytes == 0) {
rtPtr->eofPending = 0;
}
Tcl_DecrRefCount(bufObj);
Tcl_Release(rtPtr);
return gotBytes;
error:
gotBytes = -1;
goto stop;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 |
return resObj;
}
static void
FreeReflectedTransformArgs(
ReflectedTransform *rtPtr)
{
| | | 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 |
return resObj;
}
static void
FreeReflectedTransformArgs(
ReflectedTransform *rtPtr)
{
int i, n = rtPtr->argc - 2;
if (n < 0) {
return;
}
Tcl_DecrRefCount(rtPtr->handle);
rtPtr->handle = NULL;
|
| ︙ | ︙ | |||
1906 1907 1908 1909 1910 1911 1912 |
InvokeTclMethod(
ReflectedTransform *rtPtr,
const char *method,
Tcl_Obj *argOneObj, /* NULL'able */
Tcl_Obj *argTwoObj, /* NULL'able */
Tcl_Obj **resultObjPtr) /* NULL'able */
{
| | | 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 |
InvokeTclMethod(
ReflectedTransform *rtPtr,
const char *method,
Tcl_Obj *argOneObj, /* NULL'able */
Tcl_Obj *argTwoObj, /* NULL'able */
Tcl_Obj **resultObjPtr) /* NULL'able */
{
int cmdc; /* #words in constructed command */
Tcl_Obj *methObj = NULL; /* Method name in object form */
Tcl_InterpState sr; /* State of handler interp */
int result; /* Result code of method invocation */
Tcl_Obj *resObj = NULL; /* Result of method invocation. */
if (rtPtr->dead) {
/*
|
| ︙ | ︙ | |||
2424 2425 2426 2427 2428 2429 2430 | * waiting here? IOW Is it possible that "SrcExitProc" is called * while we are here? See complementary note (2) in "SrcExitProc" * * The ConditionWait unlocks the mutex during the wait and relocks it * immediately after. */ | | | 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 |
* waiting here? IOW Is it possible that "SrcExitProc" is called
* while we are here? See complementary note (2) in "SrcExitProc"
*
* The ConditionWait unlocks the mutex during the wait and relocks it
* immediately after.
*/
Tcl_ConditionWait(&resultPtr->done, &rtForwardMutex, NULL);
}
/*
* Unlink result from the forwarder list. No need to lock. Either still
* locked, or locked by the ConditionWait
*/
|
| ︙ | ︙ |
Changes to generic/tclIOSock.c.
| ︙ | ︙ | |||
125 126 127 128 129 130 131 |
int
TclSockMinimumBuffers(
void *sock, /* Socket file descriptor */
Tcl_Size size1) /* Minimum buffer size */
{
int current;
socklen_t len;
| | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
int
TclSockMinimumBuffers(
void *sock, /* Socket file descriptor */
Tcl_Size size1) /* Minimum buffer size */
{
int current;
socklen_t len;
int size = size1;
if (size != size1) {
return TCL_ERROR;
}
len = sizeof(int);
getsockopt((SOCKET)(size_t)sock, SOL_SOCKET, SO_SNDBUF,
(char *) ¤t, &len);
|
| ︙ | ︙ | |||
190 191 192 193 194 195 196 |
const char *family = NULL;
Tcl_DString ds;
int result;
if (host != NULL) {
if (Tcl_UtfToExternalDStringEx(interp, NULL, host, -1, 0, &ds,
NULL) != TCL_OK) {
| | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
const char *family = NULL;
Tcl_DString ds;
int result;
if (host != NULL) {
if (Tcl_UtfToExternalDStringEx(interp, NULL, host, -1, 0, &ds,
NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return 0;
}
native = Tcl_DStringValue(&ds);
}
/*
* Workaround for OSX's apparent inability to resolve "localhost", "0"
|
| ︙ | ︙ | |||
335 336 337 338 339 340 341 |
char portbuf[TCL_INTEGER_SPACE];
TclFormatInt(portbuf, port);
return Tcl_OpenTcpServerEx(interp, portbuf, host, TCL_TCPSERVER_REUSEADDR,
-1, acceptProc, callbackData);
}
| < < < < < < < < < < < < < < < < < < < | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
char portbuf[TCL_INTEGER_SPACE];
TclFormatInt(portbuf, port);
return Tcl_OpenTcpServerEx(interp, portbuf, host, TCL_TCPSERVER_REUSEADDR,
-1, acceptProc, callbackData);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclIOUtil.c.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
* the ned of the list */
} FilesystemRecord;
/*
*/
typedef struct {
| | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
* the ned of the list */
} FilesystemRecord;
/*
*/
typedef struct {
int initialized;
size_t cwdPathEpoch; /* Compared with the global cwdPathEpoch to
* determine whether cwdPathPtr is stale. */
size_t filesystemEpoch;
Tcl_Obj *cwdPathPtr; /* A private copy of cwdPathPtr. Updated when
* the value is accessed and cwdPathEpoch has
* changed. */
void *cwdClientData;
|
| ︙ | ︙ | |||
204 205 206 207 208 209 210 | static FilesystemRecord *filesystemList = &nativeFilesystemRecord; TCL_DECLARE_MUTEX(filesystemMutex) /* * A files-system indepent sense of the current directory. */ | | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | static FilesystemRecord *filesystemList = &nativeFilesystemRecord; TCL_DECLARE_MUTEX(filesystemMutex) /* * A files-system indepent sense of the current directory. */ static Tcl_Obj *cwdPathPtr = NULL; static size_t cwdPathEpoch = 0; /* The pathname of the current directory */ static void *cwdClientData = NULL; TCL_DECLARE_MUTEX(cwdMutex) static Tcl_ThreadDataKey fsDataKey; /* * When a temporary copy of a file is created on the native filesystem in order |
| ︙ | ︙ | |||
251 252 253 254 255 256 257 |
ret = Tcl_FSStat(pathPtr, &buf);
Tcl_DecrRefCount(pathPtr);
if (ret != -1) {
#ifndef TCL_WIDE_INT_IS_LONG
Tcl_WideInt tmp1, tmp2, tmp3 = 0;
# define OUT_OF_RANGE(x) \
| | > | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
ret = Tcl_FSStat(pathPtr, &buf);
Tcl_DecrRefCount(pathPtr);
if (ret != -1) {
#ifndef TCL_WIDE_INT_IS_LONG
Tcl_WideInt tmp1, tmp2, tmp3 = 0;
# define OUT_OF_RANGE(x) \
(((Tcl_WideInt)(x)) < LONG_MIN || \
((Tcl_WideInt)(x)) > LONG_MAX)
# define OUT_OF_URANGE(x) \
(((Tcl_WideUInt)(x)) > ((Tcl_WideUInt)ULONG_MAX))
/*
* Perform the result-buffer overflow check manually.
*
* Note that ino_t/ino64_t is unsigned...
|
| ︙ | ︙ | |||
437 438 439 440 441 442 443 |
while (fsRecPtr != NULL) {
tmpFsRecPtr = fsRecPtr->nextPtr;
fsRecPtr->fsPtr = NULL;
Tcl_Free(fsRecPtr);
fsRecPtr = tmpFsRecPtr;
}
tsdPtr->filesystemList = NULL;
| | < | < < | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
while (fsRecPtr != NULL) {
tmpFsRecPtr = fsRecPtr->nextPtr;
fsRecPtr->fsPtr = NULL;
Tcl_Free(fsRecPtr);
fsRecPtr = tmpFsRecPtr;
}
tsdPtr->filesystemList = NULL;
tsdPtr->initialized = 0;
}
int
TclFSCwdIsNative(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey);
/* if not yet initialized - ensure we'll once obtain cwd */
if (!tsdPtr->cwdPathEpoch) {
Tcl_Obj *temp = Tcl_FSGetCwd(NULL);
if (temp) { Tcl_DecrRefCount(temp); }
}
if (tsdPtr->cwdClientData != NULL) {
return 1;
} else {
return 0;
}
}
/*
*----------------------------------------------------------------------
*
* TclFSCwdPointerEquals --
* Determine whether the given pathname is equal to the current working
* directory.
*
* Results:
* 1 if equal, 0 otherwise.
*
* Side effects:
|
| ︙ | ︙ | |||
512 513 514 515 516 517 518 |
} else {
tsdPtr->cwdClientData = TclNativeDupInternalRep(cwdClientData);
}
tsdPtr->cwdPathEpoch = cwdPathEpoch;
}
Tcl_MutexUnlock(&cwdMutex);
| | | | | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 |
} else {
tsdPtr->cwdClientData = TclNativeDupInternalRep(cwdClientData);
}
tsdPtr->cwdPathEpoch = cwdPathEpoch;
}
Tcl_MutexUnlock(&cwdMutex);
if (tsdPtr->initialized == 0) {
Tcl_CreateThreadExitHandler(FsThrExitProc, tsdPtr);
tsdPtr->initialized = 1;
}
if (pathPtrPtr == NULL) {
return (tsdPtr->cwdPathPtr == NULL);
}
if (tsdPtr->cwdPathPtr == *pathPtrPtr) {
return 1;
} else {
Tcl_Size len1, len2;
const char *str1, *str2;
|
| ︙ | ︙ | |||
604 605 606 607 608 609 610 |
toFree = next;
}
/*
* Make sure the above gets released on thread exit.
*/
| | | | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 |
toFree = next;
}
/*
* Make sure the above gets released on thread exit.
*/
if (tsdPtr->initialized == 0) {
Tcl_CreateThreadExitHandler(FsThrExitProc, tsdPtr);
tsdPtr->initialized = 1;
}
}
static FilesystemRecord *
FsGetFirstFilesystem(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey);
|
| ︙ | ︙ | |||
630 631 632 633 634 635 636 |
* "system encoding" changes, and when env(HOME) changes.
*/
int
TclFSEpochOk(
size_t filesystemEpoch)
{
| | | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 |
* "system encoding" changes, and when env(HOME) changes.
*/
int
TclFSEpochOk(
size_t filesystemEpoch)
{
return (filesystemEpoch == 0 || filesystemEpoch == theFilesystemEpoch);
}
static void
Claim(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&fsDataKey);
|
| ︙ | ︙ | |||
966 967 968 969 970 971 972 | * Search in the given pathname for files matching the given pattern. * Used by [glob]. Processes just one pattern for one directory. Callers * such as TclGlob and DoGlob implement manage the searching of multiple * directories in cases such as * glob -dir $dir -join * pkgIndex.tcl * * Results: | < > | | > | 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 |
* Search in the given pathname for files matching the given pattern.
* Used by [glob]. Processes just one pattern for one directory. Callers
* such as TclGlob and DoGlob implement manage the searching of multiple
* directories in cases such as
* glob -dir $dir -join * pkgIndex.tcl
*
* Results:
*
* TCL_OK, or TCL_ERROR
*
* Side effects:
* resultPtr is populated, or in the case of an TCL_ERROR, an error message is
* set in the interpreter.
*
*----------------------------------------------------------------------
*/
int
Tcl_FSMatchInDirectory(
Tcl_Interp *interp, /* Interpreter to receive error messages, or
|
| ︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 |
types);
if (ret == TCL_OK && pattern != NULL) {
FsAddMountsToGlobResult(resultPtr, pathPtr, pattern, types);
}
return ret;
}
| | | 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 |
types);
if (ret == TCL_OK && pattern != NULL) {
FsAddMountsToGlobResult(resultPtr, pathPtr, pattern, types);
}
return ret;
}
if (pathPtr != NULL && TclGetString(pathPtr)[0] != '\0') {
/*
* There is a pathname but it belongs to no known filesystem. Mayday!
*/
Tcl_SetErrno(ENOENT);
return -1;
}
|
| ︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 |
return ret;
}
/*
*----------------------------------------------------------------------
*
* FsAddMountsToGlobResult --
| < | 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 |
return ret;
}
/*
*----------------------------------------------------------------------
*
* FsAddMountsToGlobResult --
* Adds any mounted pathnames to a set of results so that simple things
* like 'glob *' merge mounts and listings correctly. Used by the
* Tcl_FSMatchInDirectory.
*
* Results:
* None.
*
|
| ︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 | * Deal with the root of the volume. */ len--; } len++; /* account for '/' in the mElt [Bug 1602539] */ | | | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 |
* Deal with the root of the volume.
*/
len--;
}
len++; /* account for '/' in the mElt [Bug 1602539] */
mElt = TclNewFSPathObj(pathPtr, mount + len, mlen - len);
Tcl_ListObjAppendElement(NULL, resultPtr, mElt);
}
/*
* Not comparing mounts to mounts, so no need to increment gLength
*/
}
}
|
| ︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 |
*
*----------------------------------------------------------------------
*/
void *
Tcl_FSData(
const Tcl_Filesystem *fsPtr) /* The filesystem to find in the list of
| | | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 |
*
*----------------------------------------------------------------------
*/
void *
Tcl_FSData(
const Tcl_Filesystem *fsPtr) /* The filesystem to find in the list of
* registered filesystems. */
{
void *retVal = NULL;
FilesystemRecord *fsRecPtr = FsGetFirstFilesystem();
/*
* Find the filesystem in and retrieve its clientData.
*/
|
| ︙ | ︙ | |||
1313 1314 1315 1316 1317 1318 1319 | * components into the pathname, this function does not return the correct * result. This may be possible with symbolic links on unix. * * *--------------------------------------------------------------------------- */ | | | | | | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 |
* components into the pathname, this function does not return the correct
* result. This may be possible with symbolic links on unix.
*
*
*---------------------------------------------------------------------------
*/
int
TclFSNormalizeToUniquePath(
Tcl_Interp *interp, /* Used for error messages. */
Tcl_Obj *pathPtr, /* An Pathname to normalize in-place. Must be
* unshared. */
int startAt) /* Offset the string of pathPtr to start at.
* Must either be 0 or offset of a directory
* separator at the end of a pathname part that
* is already normalized, I.e. not the index of
* the byte just after the separator. */
{
FilesystemRecord *fsRecPtr, *firstFsRecPtr;
Tcl_Size i;
int isVfsPath = 0;
const char *path;
|
| ︙ | ︙ | |||
1381 1382 1383 1384 1385 1386 1387 | } /* * TODO: Always call the normalizePathProc here because it should * always exist. */ | | | | | | 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 |
}
/*
* TODO: Always call the normalizePathProc here because it should
* always exist.
*/
if (fsRecPtr->fsPtr->normalizePathProc != NULL) {
startAt = fsRecPtr->fsPtr->normalizePathProc(interp, pathPtr,
startAt);
}
break;
}
}
for (fsRecPtr=firstFsRecPtr; fsRecPtr!=NULL; fsRecPtr=fsRecPtr->nextPtr) {
if (fsRecPtr->fsPtr == &tclNativeFilesystem) {
/*
* Skip the native system this time through.
*/
continue;
}
if (fsRecPtr->fsPtr->normalizePathProc != NULL) {
startAt = fsRecPtr->fsPtr->normalizePathProc(interp, pathPtr,
startAt);
}
/*
* This efficiency check could be added:
* if (retVal == length-of(pathPtr)) {break;}
* but there's not much benefit.
*/
|
| ︙ | ︙ | |||
1421 1422 1423 1424 1425 1426 1427 | *--------------------------------------------------------------------------- * * TclGetOpenMode -- * * Computes a POSIX mode mask for opening a file. * * Results: | | < > > > | 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 | *--------------------------------------------------------------------------- * * TclGetOpenMode -- * * Computes a POSIX mode mask for opening a file. * * Results: * The mode to pass to "open", or -1 if an error occurs. * * Side effects: * Sets *modeFlagsPtr to 1 to tell the caller to * seek to EOF after opening the file, or to 0 otherwise. * * Adds CHANNEL_RAW_MODE to *modeFlagsPtr to tell the caller * to configure the channel as a binary channel. * * If there is an error and interp is not NULL, sets * interpreter result to an error message. * * Special note: * Based on a prototype implementation contributed by Mark Diekhans. * *--------------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
1547 1548 1549 1550 1551 1552 1553 |
flag = modeArgv[i];
c = flag[0];
if ((c == 'R') && (strcmp(flag, "RDONLY") == 0)) {
if (gotRW) {
invRW:
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
| | | | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 |
flag = modeArgv[i];
c = flag[0];
if ((c == 'R') && (strcmp(flag, "RDONLY") == 0)) {
if (gotRW) {
invRW:
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"invalid access mode \"%s\": modes RDONLY, "
"RDWR, and WRONLY cannot be combined", flag));
}
goto invAccessMode;
}
mode = (mode & ~O_ACCMODE) | O_RDONLY;
gotRW = 1;
} else if ((c == 'W') && (strcmp(flag, "WRONLY") == 0)) {
if (gotRW) {
|
| ︙ | ︙ | |||
1570 1571 1572 1573 1574 1575 1576 |
}
mode = (mode & ~O_ACCMODE) | O_RDWR;
gotRW = 1;
} else if ((c == 'A') && (strcmp(flag, "APPEND") == 0)) {
if (mode & O_APPEND) {
accessFlagRepeated:
if (interp) {
| | | | | | 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 |
}
mode = (mode & ~O_ACCMODE) | O_RDWR;
gotRW = 1;
} else if ((c == 'A') && (strcmp(flag, "APPEND") == 0)) {
if (mode & O_APPEND) {
accessFlagRepeated:
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"access mode \"%s\" repeated", flag));
}
goto invAccessMode;
}
mode |= O_APPEND;
*modeFlagsPtr |= 1;
} else if ((c == 'C') && (strcmp(flag, "CREAT") == 0)) {
if (mode & O_CREAT) {
goto accessFlagRepeated;
}
mode |= O_CREAT;
} else if ((c == 'E') && (strcmp(flag, "EXCL") == 0)) {
if (mode & O_EXCL) {
goto accessFlagRepeated;
}
mode |= O_EXCL;
|
| ︙ | ︙ | |||
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 |
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"access mode \"%s\" not supported by this system",
flag));
}
goto invAccessMode;
#endif
} else if ((c == 'N') && (strcmp(flag, "NONBLOCK") == 0)) {
#ifdef O_NONBLOCK
if (mode & O_NONBLOCK) {
goto accessFlagRepeated;
}
mode |= O_NONBLOCK;
#else
| > | 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 |
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"access mode \"%s\" not supported by this system",
flag));
}
goto invAccessMode;
#endif
} else if ((c == 'N') && (strcmp(flag, "NONBLOCK") == 0)) {
#ifdef O_NONBLOCK
if (mode & O_NONBLOCK) {
goto accessFlagRepeated;
}
mode |= O_NONBLOCK;
#else
|
| ︙ | ︙ | |||
1827 1828 1829 1830 1831 1832 1833 |
int
TclNREvalFile(
Tcl_Interp *interp, /* Interpreter in which to evaluate the script. */
Tcl_Obj *pathPtr, /* Pathname of a file containing the script to
* evaluate. Tilde-substitution is performed on
* this pathname. */
const char *encodingName) /* The name of an encoding to use, or NULL to
| | | 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 |
int
TclNREvalFile(
Tcl_Interp *interp, /* Interpreter in which to evaluate the script. */
Tcl_Obj *pathPtr, /* Pathname of a file containing the script to
* evaluate. Tilde-substitution is performed on
* this pathname. */
const char *encodingName) /* The name of an encoding to use, or NULL to
* use the utf-8 encoding. */
{
Tcl_StatBuf statBuf;
Tcl_Obj *oldScriptFile, *objPtr;
Interp *iPtr;
Tcl_Channel chan;
const char *string;
|
| ︙ | ︙ | |||
2040 2041 2042 2043 2044 2045 2046 | * * Tcl_PosixError -- * * Typically called after a UNIX kernel call returns an error. Sets the * interpreter errorCode to machine-parsable information about the error. * * Results: | | | 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 | * * Tcl_PosixError -- * * Typically called after a UNIX kernel call returns an error. Sets the * interpreter errorCode to machine-parsable information about the error. * * Results: * A human-readable sring describing the error. * * Side effects: * Sets the errorCode value of the interpreter. * *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
2066 2067 2068 2069 2070 2071 2072 |
return msg;
}
/*
*----------------------------------------------------------------------
*
* Tcl_FSStat --
| < | | < | 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 |
return msg;
}
/*
*----------------------------------------------------------------------
*
* Tcl_FSStat --
* Calls 'statProc' of the filesystem corresponding to pathPtr.
*
* Replaces the standard library "stat" routine.
*
* Results:
* See stat documentation.
*
* Side effects:
* See stat documentation.
*
*----------------------------------------------------------------------
*/
int
Tcl_FSStat(
Tcl_Obj *pathPtr, /* Pathname of the file to call stat on (in
* current system encoding). */
Tcl_StatBuf *buf) /* A buffer to hold the results of the call to
* stat. */
{
const Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
if (fsPtr != NULL && fsPtr->statProc != NULL) {
return fsPtr->statProc(pathPtr, buf);
}
Tcl_SetErrno(ENOENT);
return -1;
}
/*
*----------------------------------------------------------------------
*
* Tcl_FSLstat --
* Calls the 'lstatProc' of the filesystem corresponding to pathPtr.
*
* Replaces the library version of lstat. If the filesystem doesn't
* provide lstatProc but does provide statProc, Tcl falls back to
* statProc.
*
* Results:
|
| ︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 |
if (TclListObjGetElements(NULL, listObj, &objc, &objv) != TCL_OK) {
TclDecrRefCount(listObj);
return TCL_ERROR;
}
for (i=0 ; i<objc ; i++) {
if (!strcmp(attributeName, TclGetString(objv[i]))) {
TclDecrRefCount(listObj);
| | | 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 |
if (TclListObjGetElements(NULL, listObj, &objc, &objv) != TCL_OK) {
TclDecrRefCount(listObj);
return TCL_ERROR;
}
for (i=0 ; i<objc ; i++) {
if (!strcmp(attributeName, TclGetString(objv[i]))) {
TclDecrRefCount(listObj);
*indexPtr = i;
return TCL_OK;
}
}
TclDecrRefCount(listObj);
return TCL_ERROR;
} else {
return TCL_ERROR;
|
| ︙ | ︙ | |||
2749 2750 2751 2752 2753 2754 2755 |
*/
TclFSGetCwdProc2 *proc2 = (TclFSGetCwdProc2 *) fsPtr->getCwdProc;
retCd = proc2(tsdPtr->cwdClientData);
if (retCd == NULL) {
if (interp != NULL) {
| | > | 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 |
*/
TclFSGetCwdProc2 *proc2 = (TclFSGetCwdProc2 *) fsPtr->getCwdProc;
retCd = proc2(tsdPtr->cwdClientData);
if (retCd == NULL) {
if (interp != NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf(
"error getting working directory name: %s",
Tcl_PosixError(interp)));
}
retVal = NULL;
} else {
if (retCd == tsdPtr->cwdClientData) {
goto cdDidNotChange;
|
| ︙ | ︙ | |||
2783 2784 2785 2786 2787 2788 2789 |
FsUpdateCwd(NULL, NULL);
goto cdDidNotChange;
}
norm = TclFSNormalizeAbsolutePath(interp, retVal);
if (norm == NULL) {
| | | | 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 |
FsUpdateCwd(NULL, NULL);
goto cdDidNotChange;
}
norm = TclFSNormalizeAbsolutePath(interp, retVal);
if (norm == NULL) {
/*
* 'norm' shouldn't ever be NULL, but we are careful.
*/
/* Do nothing */
if (retCd != NULL) {
fsPtr->freeInternalRepProc(retCd);
}
} else if (norm == tsdPtr->cwdPathPtr) {
goto cdEqual;
} else {
/*
* Determine whether the filesystem's answer is the same as the
* cached local value. Since both 'norm' and 'tsdPtr->cwdPathPtr'
* are normalized pathnames, do something more efficient than
* calling 'Tcl_FSEqualPaths', and in addition avoid a nasty
* infinite loop bug when trying to normalize tsdPtr->cwdPathPtr.
*/
|
| ︙ | ︙ | |||
2900 2901 2902 2903 2904 2905 2906 |
/*
* stat was successful, and the file is a directory and is
* readable. Can proceed to change the current directory.
*/
retVal = 0;
} else {
| | > | | | < < | 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 |
/*
* stat was successful, and the file is a directory and is
* readable. Can proceed to change the current directory.
*/
retVal = 0;
} else {
/*
* 'Tcl_SetErrno()' has already been called.
*/
}
}
} else {
Tcl_SetErrno(ENOENT);
}
if (retVal == 0) {
/* Assume that the cwd was actually changed to the normalized value
* just calculated, and cache that information. */
/*
* If the filesystem epoch changed recently, the normalized pathname or
* its internal handle may be different from what was found above.
* This can easily be the case with scripted documents . Therefore get
* the normalized pathname again. The correct value will have been
* cached as a result of the Tcl_FSGetFileSystemForPath call, above.
*/
Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr);
if (normDirName == NULL) {
/* Not really true, but what else to do? */
Tcl_SetErrno(ENOENT);
return -1;
}
if (normDirName != pathPtr) { Tcl_IncrRefCount(normDirName); }
if (fsPtr == &tclNativeFilesystem) {
void *cd;
void *oldcd = tsdPtr->cwdClientData;
/*
* Assume that the native filesystem has a getCwdProc and that it
|
| ︙ | ︙ | |||
2982 2983 2984 2985 2986 2987 2988 | /* * The filesystem of the current directory is not the same as the * filesystem of the previous current directory. Invalidate All * FsPath objects. */ Tcl_FSMountsChanged(NULL); } | | < < | 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 |
/*
* The filesystem of the current directory is not the same as the
* filesystem of the previous current directory. Invalidate All
* FsPath objects.
*/
Tcl_FSMountsChanged(NULL);
}
if (normDirName != pathPtr) { Tcl_DecrRefCount(normDirName); }
} else {
/*
* The current directory is now changed or an error occurred and an
* error message is now set. Just continue.
*/
}
|
| ︙ | ︙ | |||
3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 | * from getting properly loaded. Only the first is ok. Work around the issue * by not unlinking, i.e., emulating the behaviour of the older HPUX which * denied removal. * * Doing the unlink is also an issue within docker containers, whose AUFS * bungles this as well, see * https://github.com/dotcloud/docker/issues/1911 */ #ifdef _WIN32 #define getenv(x) _wgetenv(L##x) #define atoi(x) _wtoi(x) #else #define WCHAR char #endif static int | > | | 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 |
* from getting properly loaded. Only the first is ok. Work around the issue
* by not unlinking, i.e., emulating the behaviour of the older HPUX which
* denied removal.
*
* Doing the unlink is also an issue within docker containers, whose AUFS
* bungles this as well, see
* https://github.com/dotcloud/docker/issues/1911
*
*/
#ifdef _WIN32
#define getenv(x) _wgetenv(L##x)
#define atoi(x) _wtoi(x)
#else
#define WCHAR char
#endif
static int
skipUnlink(
Tcl_Obj *shlibFile)
{
/*
* Unlinking is not performed in the following cases:
*
* 1. The operating system is HPUX.
*
|
| ︙ | ︙ | |||
3170 3171 3172 3173 3174 3175 3176 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Obj *pathPtr, /* Pathname of the file containing the dynamic
* shared object. */
const char *const symbols[],/* A null-terminated array of names of
* functions to find in the loaded object. */
int flags, /* Flags */
void *procVPtrs, /* A place to store pointers to the functions
| | | 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 |
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Obj *pathPtr, /* Pathname of the file containing the dynamic
* shared object. */
const char *const symbols[],/* A null-terminated array of names of
* functions to find in the loaded object. */
int flags, /* Flags */
void *procVPtrs, /* A place to store pointers to the functions
* named by symbols[]. */
Tcl_LoadHandle *handlePtr) /* A place to hold a token for the loaded object.
* Can be used by TclpFindSymbol. */
{
void **procPtrs = (void **) procVPtrs;
const Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
const Tcl_Filesystem *copyFsPtr;
Tcl_FSUnloadFileProc *unloadProcPtr;
|
| ︙ | ︙ | |||
3288 3289 3290 3291 3292 3293 3294 |
if ((copyFsPtr == NULL) || (copyFsPtr == fsPtr)) {
/*
* Tcl_FSLoadFile isn't available for the filesystem of the temporary
* file. In order to avoid a possible infinite loop, do not attempt to
* load further.
*/
| | | | | 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 |
if ((copyFsPtr == NULL) || (copyFsPtr == fsPtr)) {
/*
* Tcl_FSLoadFile isn't available for the filesystem of the temporary
* file. In order to avoid a possible infinite loop, do not attempt to
* load further.
*/
/*
* Try to delete the file we probably created and then exit.
*/
Tcl_FSDeleteFile(copyToPtr);
Tcl_DecrRefCount(copyToPtr);
if (interp) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"couldn't load from current filesystem", -1));
}
|
| ︙ | ︙ | |||
3349 3350 3351 3352 3353 3354 3355 |
}
/*
* Try to delete the file immediately. Some operatings systems allow this,
* and it avoids leaving the copy laying around after exit.
*/
| | | 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 |
}
/*
* Try to delete the file immediately. Some operatings systems allow this,
* and it avoids leaving the copy laying around after exit.
*/
if (!skipUnlink(copyToPtr) &&
(Tcl_FSDeleteFile(copyToPtr) == TCL_OK)) {
Tcl_DecrRefCount(copyToPtr);
/*
* Tell the caller all the details: The package list maintained by
* 'load' stores the original (vfs) pathname, the handle of object
* loaded from the temporary file, and the unloadProcPtr.
|
| ︙ | ︙ | |||
3381 3382 3383 3384 3385 3386 3387 |
* load completely on platforms which allow proper unloading of code.
*/
tvdlPtr->loadHandle = newLoadHandle;
tvdlPtr->unloadProcPtr = newUnloadProcPtr;
if (copyFsPtr != &tclNativeFilesystem) {
| | | 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 |
* load completely on platforms which allow proper unloading of code.
*/
tvdlPtr->loadHandle = newLoadHandle;
tvdlPtr->unloadProcPtr = newUnloadProcPtr;
if (copyFsPtr != &tclNativeFilesystem) {
/* refCount of copyToPtr is already incremented. */
tvdlPtr->divertedFile = copyToPtr;
/*
* This is the filesystem for the temporary file the object was loaded
* from. A reference to copyToPtr is already stored in
* tvdlPtr->divertedFile, so need need to increment the refCount again.
*/
|
| ︙ | ︙ | |||
3567 3568 3569 3570 3571 3572 3573 | * Previously filesystem-specific, but has been made portable by having * TclpDlopen return a structure that includes procedure pointers. * * Results: * Returns a pointer to the symbol if found. Otherwise, sets * an error message in the interpreter result and returns NULL. * | < < < | | 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 |
* Previously filesystem-specific, but has been made portable by having
* TclpDlopen return a structure that includes procedure pointers.
*
* Results:
* Returns a pointer to the symbol if found. Otherwise, sets
* an error message in the interpreter result and returns NULL.
*
*----------------------------------------------------------------------
*/
void *
Tcl_FindSymbol(
Tcl_Interp *interp, /* The relevant interpreter. */
Tcl_LoadHandle loadHandle, /* A handle for the loaded object. */
const char *symbol) /* The name of the symbol to resolve. */
{
return loadHandle->findSymbolProcPtr(interp, loadHandle, symbol);
}
/*
*----------------------------------------------------------------------
*
* Tcl_FSUnloadFile --
*
* Unloads a loaded object if unloading is supported for the object.
*
*----------------------------------------------------------------------
*/
int
Tcl_FSUnloadFile(
Tcl_Interp *interp, /* The relevant interpreter. */
|
| ︙ | ︙ | |||
4023 4024 4025 4026 4027 4028 4029 |
if (pathLen < len) {
continue;
}
if (strncmp(strVol, path, len) == 0) {
type = TCL_PATH_ABSOLUTE;
matched = true;
} else if (len > 2 && strVol[len - 1] == '/' &&
| | | | 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 |
if (pathLen < len) {
continue;
}
if (strncmp(strVol, path, len) == 0) {
type = TCL_PATH_ABSOLUTE;
matched = true;
} else if (len > 2 && strVol[len - 1] == '/' &&
strVol[len - 2] == ':' &&
strncmp(strVol, path, len - 2) == 0) {
matched = true;
type = TCL_PATH_VOLUME_RELATIVE;
len--;
Tcl_SetObjLength(vol, len);
}
if (matched) {
if (filesystemPtrPtr != NULL) {
|
| ︙ | ︙ | |||
4360 4361 4362 4363 4364 4365 4366 |
*/
int
Tcl_FSRemoveDirectory(
Tcl_Obj *pathPtr, /* The pathname of the directory to be removed. */
int recursive, /* If zero, removes only an empty directory.
* Otherwise, removes the directory and all its
| | | 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 |
*/
int
Tcl_FSRemoveDirectory(
Tcl_Obj *pathPtr, /* The pathname of the directory to be removed. */
int recursive, /* If zero, removes only an empty directory.
* Otherwise, removes the directory and all its
* contents. */
Tcl_Obj **errorPtr) /* If not NULL and an error occurs, stores a
* place to store a pointer to a new
* object having a refCount of 1 and containing
* the name of the file that produced an error. */
{
const Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
|
| ︙ | ︙ | |||
4479 4480 4481 4482 4483 4484 4485 |
continue;
}
if (fsRecPtr->fsPtr->pathInFilesystemProc(pathPtr, &clientData)!=-1) {
/* This is the filesystem for pathPtr. Assume the type of pathPtr
* hasn't been changed by the above call to the
* pathInFilesystemProc, and cache this result in the internal
| | | | 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 |
continue;
}
if (fsRecPtr->fsPtr->pathInFilesystemProc(pathPtr, &clientData)!=-1) {
/* This is the filesystem for pathPtr. Assume the type of pathPtr
* hasn't been changed by the above call to the
* pathInFilesystemProc, and cache this result in the internal
* representation of pathPtr. */
TclFSSetPathDetails(pathPtr, fsRecPtr->fsPtr, clientData);
Disclaim();
return fsRecPtr->fsPtr;
}
}
Disclaim();
return NULL;
}
/*
*---------------------------------------------------------------------------
*
* Tcl_FSGetNativePath --
*
* See Tcl_FSGetInternalRep.
*
*---------------------------------------------------------------------------
*/
const void *
Tcl_FSGetNativePath(
Tcl_Obj *pathPtr)
|
| ︙ | ︙ | |||
4535 4536 4537 4538 4539 4540 4541 |
Tcl_Free(clientData);
}
/*
*---------------------------------------------------------------------------
*
* Tcl_FSFileSystemInfo --
| < | 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 |
Tcl_Free(clientData);
}
/*
*---------------------------------------------------------------------------
*
* Tcl_FSFileSystemInfo --
* Produce the type of a pathname and the type of its filesystem.
*
*
* Results:
* A list where the first item is the name of the filesystem (e.g.
* "native" or "vfs"), and the second item is the type of the given
* pathname within that filesystem.
|
| ︙ | ︙ |
Changes to generic/tclIcu.c.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 |
UCNV_IRREGULAR = 2,
UCNV_RESET = 3,
UCNV_CLOSE = 4,
UCNV_CLONE = 5
} UConverterCallbackReasonx;
typedef enum UNormalizationCheckResultx {
| | | | | > | > | | > > | | | > | > > | | > | > > | > > | > | > > | | > > | > > | | > | > | | > | > | | | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
UCNV_IRREGULAR = 2,
UCNV_RESET = 3,
UCNV_CLOSE = 4,
UCNV_CLONE = 5
} UConverterCallbackReasonx;
typedef enum UNormalizationCheckResultx {
UNORM_NO,
UNORM_YES,
UNORM_MAYBE
} UNormalizationCheckResultx;
typedef struct UEnumeration UEnumeration;
typedef struct UCharsetDetector UCharsetDetector;
typedef struct UCharsetMatch UCharsetMatch;
typedef struct UBreakIterator UBreakIterator;
typedef struct UNormalizer2 UNormalizer2;
typedef struct UConverter UConverter;
typedef struct UConverterFromUnicodeArgs UConverterFromUnicodeArgs;
typedef struct UConverterToUnicodeArgs UConverterToUnicodeArgs;
typedef void (*UConverterFromUCallback)(const void *context,
UConverterFromUnicodeArgs *args,
const UCharx *codeUnits,
int32_t length, UChar32x codePoint,
UConverterCallbackReasonx reason,
UErrorCodex *pErrorCode);
typedef void (*UConverterToUCallback)(const void *context,
UConverterToUnicodeArgs *args,
const char *codeUnits,
int32_t length,
UConverterCallbackReasonx reason,
UErrorCodex *pErrorCode);
/*
* Prototypes for ICU functions sorted by category.
*/
typedef void (*fn_u_cleanup)(void);
typedef const char *(*fn_u_errorName)(UErrorCodex);
typedef UCharx *(*fn_u_strFromUTF32)(UCharx *dest,
int32_t destCapacity,
int32_t *pDestLength,
const UChar32x *src,
int32_t srcLength,
UErrorCodex *pErrorCode);
typedef UCharx *(*fn_u_strFromUTF32WithSub)(UCharx *dest,
int32_t destCapacity,
int32_t *pDestLength,
const UChar32x *src,
int32_t srcLength,
UChar32x subchar,
int32_t *pNumSubstitutions,
UErrorCodex *pErrorCode);
typedef UChar32x *(*fn_u_strToUTF32)(UChar32x *dest,
int32_t destCapacity,
int32_t *pDestLength,
const UCharx *src,
int32_t srcLength,
UErrorCodex *pErrorCode);
typedef UChar32x *(*fn_u_strToUTF32WithSub)(UChar32x *dest,
int32_t destCapacity,
int32_t *pDestLength,
const UCharx *src,
int32_t srcLength,
UChar32x subchar,
int32_t *pNumSubstitutions,
UErrorCodex *pErrorCode);
typedef void (*fn_ucnv_close)(UConverter *);
typedef uint16_t (*fn_ucnv_countAliases)(const char *, UErrorCodex *);
typedef int32_t (*fn_ucnv_countAvailable)(void);
typedef int32_t (*fn_ucnv_fromUChars)(UConverter *, char *dest,
int32_t destCapacity, const UCharx *src, int32_t srcLen, UErrorCodex *);
typedef const char *(*fn_ucnv_getAlias)(const char *, uint16_t, UErrorCodex *);
typedef const char *(*fn_ucnv_getAvailableName)(int32_t);
typedef UConverter *(*fn_ucnv_open)(const char *converterName, UErrorCodex *);
typedef void (*fn_ucnv_setFromUCallBack)(UConverter *,
UConverterFromUCallback newAction,
const void *newContext,
UConverterFromUCallback *oldAction,
const void **oldContext,
UErrorCodex *err);
typedef void (*fn_ucnv_setToUCallBack)(UConverter *,
UConverterToUCallback newAction,
const void *newContext,
UConverterToUCallback *oldAction,
const void **oldContext,
UErrorCodex *err);
typedef int32_t (*fn_ucnv_toUChars)(UConverter *, UCharx *dest,
int32_t destCapacity, const char *src, int32_t srcLen, UErrorCodex *);
typedef UConverterFromUCallback fn_UCNV_FROM_U_CALLBACK_STOP;
typedef UConverterToUCallback fn_UCNV_TO_U_CALLBACK_STOP;
typedef UBreakIterator *(*fn_ubrk_open)(
UBreakIteratorTypex, const char *, const uint16_t *, int32_t,
UErrorCodex *);
typedef void (*fn_ubrk_close)(UBreakIterator *);
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 | typedef int32_t (*fn_uenum_count)(UEnumeration *, UErrorCodex *); typedef const char *(*fn_uenum_next)(UEnumeration *, int32_t *, UErrorCodex *); typedef UNormalizer2 *(*fn_unorm2_getNFCInstance)(UErrorCodex *); typedef UNormalizer2 *(*fn_unorm2_getNFDInstance)(UErrorCodex *); typedef UNormalizer2 *(*fn_unorm2_getNFKCInstance)(UErrorCodex *); typedef UNormalizer2 *(*fn_unorm2_getNFKDInstance)(UErrorCodex *); | | > > > > | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
typedef int32_t (*fn_uenum_count)(UEnumeration *, UErrorCodex *);
typedef const char *(*fn_uenum_next)(UEnumeration *, int32_t *, UErrorCodex *);
typedef UNormalizer2 *(*fn_unorm2_getNFCInstance)(UErrorCodex *);
typedef UNormalizer2 *(*fn_unorm2_getNFDInstance)(UErrorCodex *);
typedef UNormalizer2 *(*fn_unorm2_getNFKCInstance)(UErrorCodex *);
typedef UNormalizer2 *(*fn_unorm2_getNFKDInstance)(UErrorCodex *);
typedef int32_t (*fn_unorm2_normalize)(const UNormalizer2 *,
const UCharx *,
int32_t,
UCharx *,
int32_t,
UErrorCodex *);
#define FIELD(name) fn_ ## name _ ## name
static struct {
size_t nopen; /* Total number of references to ALL libraries */
/*
* Depending on platform, ICU symbols may be distributed amongst
|
| ︙ | ︙ | |||
194 195 196 197 198 199 200 |
FIELD(unorm2_getNFCInstance);
FIELD(unorm2_getNFDInstance);
FIELD(unorm2_getNFKCInstance);
FIELD(unorm2_getNFKDInstance);
FIELD(unorm2_normalize);
} icu_fns = {
0, {NULL, NULL}, /* Reference count, library handles */
| | | | | | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
FIELD(unorm2_getNFCInstance);
FIELD(unorm2_getNFDInstance);
FIELD(unorm2_getNFKCInstance);
FIELD(unorm2_getNFKDInstance);
FIELD(unorm2_normalize);
} icu_fns = {
0, {NULL, NULL}, /* Reference count, library handles */
NULL, NULL, NULL, NULL, NULL, NULL, /* u_* */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* ubrk* */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* ucnv_* .. */
NULL, NULL, NULL, /* .. ucnv_ */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* ucsdet* */
NULL, NULL, NULL, /* uenum_* */
NULL, NULL, NULL, NULL, NULL, /* unorm2_* */
};
#define u_cleanup icu_fns._u_cleanup
#define u_errorName icu_fns._u_errorName
#define u_strFromUTF32 icu_fns._u_strFromUTF32
#define u_strFromUTF32WithSub icu_fns._u_strFromUTF32WithSub
#define u_strToUTF32 icu_fns._u_strToUTF32
|
| ︙ | ︙ | |||
254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
#define unorm2_normalize icu_fns._unorm2_normalize
TCL_DECLARE_MUTEX(icu_mutex);
/* Options used by multiple normalization functions */
static const char *const normalizationForms[] = {"nfc", "nfd", "nfkc", "nfkd", NULL};
typedef enum { MODE_NFC, MODE_NFD, MODE_NFKC, MODE_NFKD } NormalizationMode;
/* Error handlers. */
static int
FunctionNotAvailableError(
Tcl_Interp *interp)
{
| > | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
#define unorm2_normalize icu_fns._unorm2_normalize
TCL_DECLARE_MUTEX(icu_mutex);
/* Options used by multiple normalization functions */
static const char *const normalizationForms[] = {"nfc", "nfd", "nfkc", "nfkd", NULL};
typedef enum { MODE_NFC, MODE_NFD, MODE_NFKC, MODE_NFKD } NormalizationMode;
/* Error handlers. */
static int
FunctionNotAvailableError(
Tcl_Interp *interp)
{
|
| ︙ | ︙ | |||
292 293 294 295 296 297 298 |
codeMessage ? codeMessage : ""));
Tcl_SetErrorCode(interp, "TCL", "ICU", codeMessage, (char *)NULL);
}
return TCL_ERROR;
}
/*
| < < < < | < < < | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
codeMessage ? codeMessage : ""));
Tcl_SetErrorCode(interp, "TCL", "ICU", codeMessage, (char *)NULL);
}
return TCL_ERROR;
}
/*
* Detect the likely encoding of the string encoded in the given byte array.
*/
static int
DetectEncoding(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
int all)
{
|
| ︙ | ︙ | |||
329 330 331 332 333 334 335 |
}
bytes = (char *)Tcl_GetBytesFromObj(interp, objPtr, &len);
if (bytes == NULL) {
return TCL_ERROR;
}
if (len > INT_MAX) {
| | | < | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
}
bytes = (char *)Tcl_GetBytesFromObj(interp, objPtr, &len);
if (bytes == NULL) {
return TCL_ERROR;
}
if (len > INT_MAX) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("Max length supported by ICU exceeded.", TCL_INDEX_NONE));
return TCL_ERROR;
}
UErrorCodex status = U_ZERO_ERRORZ;
UCharsetDetector* csd = ucsdet_open(&status);
if (U_FAILURE(status)) {
return IcuError(interp, "Could not open charset detector", status);
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 | } /* *------------------------------------------------------------------------ * * IcuObjToUCharDString -- * | | | | | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
}
/*
*------------------------------------------------------------------------
*
* IcuObjToUCharDString --
*
* Encodes a Tcl_Obj value in ICU UChars and stores in dsPtr.
*
* Results:
* Return TCL_OK / TCL_ERROR.
*
* Side effects:
* *dsPtr should be cleared by caller only if return code is TCL_OK.
*
*------------------------------------------------------------------------
*/
static int
IcuObjToUCharDString(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
|
| ︙ | ︙ | |||
475 476 477 478 479 480 481 |
return TCL_ERROR;
}
int result;
char *s;
Tcl_Size len;
s = Tcl_GetStringFromObj(objPtr, &len);
| | > > > | > | > | | | | | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
return TCL_ERROR;
}
int result;
char *s;
Tcl_Size len;
s = Tcl_GetStringFromObj(objPtr, &len);
result = Tcl_UtfToExternalDStringEx(interp,
encoding,
s,
len,
strict ? TCL_ENCODING_PROFILE_STRICT
: TCL_ENCODING_PROFILE_REPLACE,
dsPtr,
NULL);
if (result != TCL_OK) {
Tcl_DStringFree(dsPtr); /* Must be done on error */
/* TCL_CONVER_* errors -> TCL_ERROR */
result = TCL_ERROR;
}
Tcl_FreeEncoding(encoding);
return result;
}
/*
*------------------------------------------------------------------------
*
* IcuObjFromUCharDString --
*
* Stores a Tcl_Obj value by decoding ICU UChars in dsPtr.
*
* Results:
* Return Tcl_Obj or NULL on error.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static Tcl_Obj *
IcuObjFromUCharDString(
Tcl_Interp *interp,
Tcl_DString *dsPtr,
|
| ︙ | ︙ | |||
525 526 527 528 529 530 531 |
return NULL;
}
Tcl_Obj *objPtr = NULL;
char *s = Tcl_DStringValue(dsPtr);
Tcl_Size len = Tcl_DStringLength(dsPtr);
Tcl_DString dsOut;
int result;
| | > > > | > | > > | | | < > | | | | 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
return NULL;
}
Tcl_Obj *objPtr = NULL;
char *s = Tcl_DStringValue(dsPtr);
Tcl_Size len = Tcl_DStringLength(dsPtr);
Tcl_DString dsOut;
int result;
result = Tcl_ExternalToUtfDStringEx(interp,
encoding,
s,
len,
strict ? TCL_ENCODING_PROFILE_STRICT
: TCL_ENCODING_PROFILE_REPLACE,
&dsOut,
NULL);
if (result == TCL_OK) {
objPtr = Tcl_DStringToObj(&dsOut); /* Clears dsPtr! */
}
Tcl_FreeEncoding(encoding);
return objPtr;
}
/*
*------------------------------------------------------------------------
*
* IcuDetectObjCmd --
*
* Implements the Tcl command ::tcl::unsupported::icu::detect.
* ::tcl::unsupported::icu::detect - returns names of all detectable encodings
* ::tcl::unsupported::icu::detect BYTES ?-all? - return detected encoding(s)
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds result or error message.
*
*------------------------------------------------------------------------
*/
static int
IcuDetectObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc > 3) {
Tcl_WrongNumArgs(interp, 1 , objv, "?bytes ?-all??");
return TCL_ERROR;
}
if (objc == 1) {
return DetectableEncodings(interp);
}
int all = 0;
if (objc == 3) {
if (strcmp("-all", Tcl_GetString(objv[2]))) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Invalid option %s, must be \"-all\"",
Tcl_GetString(objv[2])));
return TCL_ERROR;
}
all = 1;
}
return DetectEncoding(interp, objv[1], all);
}
/*
*------------------------------------------------------------------------
*
* IcuConverterNamesObjCmd --
*
* Sets interp result to list of available ICU converters.
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds list of converter names.
*
*------------------------------------------------------------------------
*/
static int
IcuConverterNamesObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1 , objv, "");
return TCL_ERROR;
}
if (ucnv_countAvailable == NULL || ucnv_getAvailableName == NULL) {
|
| ︙ | ︙ | |||
642 643 644 645 646 647 648 | *------------------------------------------------------------------------ * * IcuConverterAliasesObjCmd -- * * Sets interp result to list of available ICU converters. * * Results: | > | | | | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 |
*------------------------------------------------------------------------
*
* IcuConverterAliasesObjCmd --
*
* Sets interp result to list of available ICU converters.
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds list of converter names.
*
*------------------------------------------------------------------------
*/
static int
IcuConverterAliasesObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1 , objv, "convertername");
return TCL_ERROR;
}
if (ucnv_countAliases == NULL || ucnv_getAlias == NULL) {
return FunctionNotAvailableError(interp);
|
| ︙ | ︙ | |||
699 700 701 702 703 704 705 | } /* *------------------------------------------------------------------------ * * IcuConverttoDString -- * | | | | | | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
}
/*
*------------------------------------------------------------------------
*
* IcuConverttoDString --
*
* Converts a string in ICU default encoding to the specified encoding.
*
* Results:
* TCL_OK / TCL_ERROR
*
* Side effects:
* On success, encoded string is stored in output dsOutPtr
*
*------------------------------------------------------------------------
*/
static int
IcuConverttoDString(
Tcl_Interp *interp,
Tcl_DString *dsInPtr, /* Input UTF16 */
const char *icuEncName,
int strict,
Tcl_DString *dsOutPtr) /* Output encoded string. */
{
if (ucnv_open == NULL || ucnv_close == NULL ||
ucnv_fromUChars == NULL || UCNV_FROM_U_CALLBACK_STOP == NULL) {
return FunctionNotAvailableError(interp);
}
UErrorCodex status = U_ZERO_ERRORZ;
UConverter *ucnvPtr = ucnv_open(icuEncName, &status);
if (ucnvPtr == NULL) {
return IcuError(interp, "Could not get encoding converter", status);
|
| ︙ | ︙ | |||
740 741 742 743 744 745 746 |
}
}
UCharx *utf16 = (UCharx *) Tcl_DStringValue(dsInPtr);
Tcl_Size utf16len = Tcl_DStringLength(dsInPtr) / sizeof(UCharx);
Tcl_Size dstLen, dstCapacity;
if (utf16len > INT_MAX) {
| | | < | | | | | | | | < | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 |
}
}
UCharx *utf16 = (UCharx *) Tcl_DStringValue(dsInPtr);
Tcl_Size utf16len = Tcl_DStringLength(dsInPtr) / sizeof(UCharx);
Tcl_Size dstLen, dstCapacity;
if (utf16len > INT_MAX) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("Max length supported by ICU exceeded.", TCL_INDEX_NONE));
return TCL_ERROR;
}
dstCapacity = utf16len;
Tcl_DStringInit(dsOutPtr);
Tcl_DStringSetLength(dsOutPtr, dstCapacity);
dstLen = ucnv_fromUChars(ucnvPtr, Tcl_DStringValue(dsOutPtr), (int)dstCapacity,
utf16, (int)utf16len, &status);
if (U_FAILURE(status)) {
switch (status) {
case U_STRING_NOT_TERMINATED_WARNING:
break; /* We don't care */
case U_BUFFER_OVERFLOW_ERROR:
Tcl_DStringSetLength(dsOutPtr, (int)dstLen);
status = U_ZERO_ERRORZ; /* Reset before call */
dstLen = ucnv_fromUChars(ucnvPtr, Tcl_DStringValue(dsOutPtr), (int)dstLen,
utf16, (int)utf16len, &status);
if (U_SUCCESS(status)) {
break;
}
TCL_FALLTHROUGH();
default:
Tcl_DStringFree(dsOutPtr);
ucnv_close(ucnvPtr);
return IcuError(interp, "ICU error while encoding", status);
}
}
Tcl_DStringSetLength(dsOutPtr, dstLen);
ucnv_close(ucnvPtr);
return TCL_OK;
}
/*
*------------------------------------------------------------------------
*
* IcuBytesToUCharDString --
*
* Converts encoded bytes to ICU UChars in a Tcl_DString
*
* Results:
* TCL_OK / TCL_ERROR
*
* Side effects:
* On success, encoded string is stored in output dsOutPtr
*
*------------------------------------------------------------------------
*/
static int
IcuBytesToUCharDString(
Tcl_Interp *interp,
const unsigned char *bytes,
Tcl_Size nbytes,
const char *icuEncName,
int strict,
Tcl_DString *dsOutPtr) /* Output UChar string. */
{
if (ucnv_open == NULL || ucnv_close == NULL ||
ucnv_toUChars == NULL || UCNV_TO_U_CALLBACK_STOP == NULL) {
return FunctionNotAvailableError(interp);
}
if (nbytes > INT_MAX) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("Max length supported by ICU exceeded.", TCL_INDEX_NONE));
return TCL_ERROR;
}
UErrorCodex status = U_ZERO_ERRORZ;
UConverter *ucnvPtr = ucnv_open(icuEncName, &status);
if (ucnvPtr == NULL) {
return IcuError(interp, "Could not get encoding converter", status);
|
| ︙ | ︙ | |||
830 831 832 833 834 835 836 |
}
int dstLen;
int dstCapacity = (int)nbytes; /* In UChar's */
Tcl_DStringInit(dsOutPtr);
Tcl_DStringSetLength(dsOutPtr, dstCapacity);
dstLen = ucnv_toUChars(ucnvPtr, (UCharx *)Tcl_DStringValue(dsOutPtr), dstCapacity,
| | | > | | | | | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 |
}
int dstLen;
int dstCapacity = (int)nbytes; /* In UChar's */
Tcl_DStringInit(dsOutPtr);
Tcl_DStringSetLength(dsOutPtr, dstCapacity);
dstLen = ucnv_toUChars(ucnvPtr, (UCharx *)Tcl_DStringValue(dsOutPtr), dstCapacity,
(const char *)bytes, (int)nbytes, &status);
if (U_FAILURE(status)) {
switch (status) {
case U_STRING_NOT_TERMINATED_WARNING:
break; /* We don't care */
case U_BUFFER_OVERFLOW_ERROR:
dstCapacity = sizeof(UCharx) * dstLen;
Tcl_DStringSetLength(dsOutPtr, dstCapacity);
status = U_ZERO_ERRORZ; /* Reset before call */
dstLen = ucnv_toUChars(ucnvPtr, (UCharx *)Tcl_DStringValue(dsOutPtr), dstCapacity,
(const char *)bytes, (int)nbytes, &status);
if (U_SUCCESS(status)) {
break;
}
TCL_FALLTHROUGH();
default:
Tcl_DStringFree(dsOutPtr);
ucnv_close(ucnvPtr);
return IcuError(interp, "ICU error while decoding", status);
}
}
Tcl_DStringSetLength(dsOutPtr, sizeof(UCharx)*dstLen);
ucnv_close(ucnvPtr);
return TCL_OK;
}
/*
*------------------------------------------------------------------------
*
* IcuNormalizeUCharDString --
*
* Normalizes the UTF-16 encoded data
*
* Results:
* TCL_OK / TCL_ERROR
*
* Side effects:
* Normalized data is stored in dsOutPtr which should only be
* Tcl_DStringFree-ed if return code is TCL_OK.
*
*------------------------------------------------------------------------
*/
static int
IcuNormalizeUCharDString(
Tcl_Interp *interp,
Tcl_DString *dsInPtr, /* Input UTF16 */
|
| ︙ | ︙ | |||
914 915 916 917 918 919 920 |
Tcl_Size utf16len;
UCharx *normPtr;
int32_t normLen;
utf16 = (UCharx *) Tcl_DStringValue(dsInPtr);
utf16len = Tcl_DStringLength(dsInPtr) / sizeof(UCharx);
if (utf16len > INT_MAX) {
| | | < | | < < < < | < < < | | | | | | | | < | | | | < | | < | | > | | | | | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 |
Tcl_Size utf16len;
UCharx *normPtr;
int32_t normLen;
utf16 = (UCharx *) Tcl_DStringValue(dsInPtr);
utf16len = Tcl_DStringLength(dsInPtr) / sizeof(UCharx);
if (utf16len > INT_MAX) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("Max length supported by ICU exceeded.", TCL_INDEX_NONE));
return TCL_ERROR;
}
Tcl_DStringInit(dsOutPtr);
Tcl_DStringSetLength(dsOutPtr, utf16len * sizeof(UCharx));
normPtr = (UCharx *) Tcl_DStringValue(dsOutPtr);
normLen = unorm2_normalize(
normalizer, utf16, (int)utf16len, normPtr, (int)utf16len, &status);
if (U_FAILURE(status)) {
switch (status) {
case U_STRING_NOT_TERMINATED_WARNING:
/* No problem, don't need it terminated */
break;
case U_BUFFER_OVERFLOW_ERROR:
/* Expand buffer */
Tcl_DStringSetLength(dsOutPtr, normLen * sizeof(UCharx));
normPtr = (UCharx *) Tcl_DStringValue(dsOutPtr);
status = U_ZERO_ERRORZ; /* Need to clear error! */
normLen = unorm2_normalize(
normalizer, utf16, (int)utf16len, normPtr, normLen, &status);
if (U_SUCCESS(status)) {
break;
}
TCL_FALLTHROUGH();
default:
Tcl_DStringFree(dsOutPtr);
return IcuError(interp, "String normalization failed", status);
}
}
Tcl_DStringSetLength(dsOutPtr, normLen * sizeof(UCharx));
return TCL_OK;
}
/*
* Common function for parsing convert options.
*/
static int IcuParseConvertOptions(
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[],
int *strictPtr,
Tcl_Obj **failindexVarPtr)
{
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?-profile PROFILE? ICUENCNAME STRING");
return TCL_ERROR;
}
objc -= 2; /* truncate fixed arguments */
/* Use GetIndexFromObj for option parsing so -failindex can be added later */
static const char *const optNames[] = {"-profile", "-failindex", NULL};
enum { OPT_PROFILE, OPT_FAILINDEX } opt;
int i;
int strict = 1;
for (i = 1; i < objc; ++i) {
if (Tcl_GetIndexFromObj(
interp, objv[i], optNames, "option", 0, &opt) != TCL_OK) {
return TCL_ERROR;
}
++i;
if (i == objc) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("Missing value for option %s.",
Tcl_GetString(objv[i - 1])));
return TCL_ERROR;
}
const char *s = Tcl_GetString(objv[i]);
switch (opt) {
case OPT_PROFILE:
if (!strcmp(s, "replace")) {
strict = 0;
} else if (strcmp(s, "strict")) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("Invalid value \"%s\" supplied for option"
" \"-profile\". Must be \"strict\" or \"replace\".",
s));
return TCL_ERROR;
}
break;
case OPT_FAILINDEX:
/* TBD */
Tcl_SetObjResult(interp,
Tcl_NewStringObj("Option -failindex not implemented.", TCL_INDEX_NONE));
return TCL_ERROR;
default:
TCL_UNREACHABLE();
}
}
*strictPtr = strict;
*failindexVarPtr = NULL;
return TCL_OK;
}
/*
*------------------------------------------------------------------------
*
* IcuConvertfromObjCmd --
*
* Implements the Tcl command "icu convertfrom"
* icu convertfrom ?-profile replace|strict? encoding string
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds result or error message.
*
*------------------------------------------------------------------------
*/
static int
IcuConvertfromObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int strict;
Tcl_Obj *failindexVar;
if (IcuParseConvertOptions(interp, objc, objv, &strict, &failindexVar) != TCL_OK) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1077 1078 1079 1080 1081 1082 1083 | } /* *------------------------------------------------------------------------ * * IcuConverttoObjCmd -- * | | | > | | | | | | | | | | | > | | | | | | | | | < | | | | < | < | | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 |
}
/*
*------------------------------------------------------------------------
*
* IcuConverttoObjCmd --
*
* Implements the Tcl command "icu convertto"
* icu convertto ?-profile replace|strict? encoding string
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds result or error message.
*
*------------------------------------------------------------------------
*/
static int
IcuConverttoObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int strict;
Tcl_Obj *failindexVar;
if (IcuParseConvertOptions(interp, objc, objv, &strict, &failindexVar) != TCL_OK) {
return TCL_ERROR;
}
Tcl_DString dsIn;
Tcl_DString dsOut;
if (IcuObjToUCharDString(interp, objv[objc - 1], strict, &dsIn) != TCL_OK ||
IcuConverttoDString(interp, &dsIn,
Tcl_GetString(objv[objc-2]), strict, &dsOut) != TCL_OK) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp,
Tcl_NewByteArrayObj((unsigned char *)Tcl_DStringValue(&dsOut),
Tcl_DStringLength(&dsOut)));
Tcl_DStringFree(&dsOut);
return TCL_OK;
}
/*
*------------------------------------------------------------------------
*
* IcuNormalizeObjCmd --
*
* Implements the Tcl command "icu normalize"
* icu normalize ?-profile replace|strict? ?-mode nfc|nfd|nfkc|nfkd? string
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds result or error message.
*
*------------------------------------------------------------------------
*/
static int
IcuNormalizeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const optNames[] = {"-profile", "-mode", NULL};
enum { OPT_PROFILE, OPT_MODE } opt;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?-profile PROFILE? ?-mode MODE? STRING");
return TCL_ERROR;
}
int i;
int strict = 1;
NormalizationMode mode = MODE_NFC;
for (i = 1; i < objc - 1; ++i) {
if (Tcl_GetIndexFromObj(
interp, objv[i], optNames, "option", 0, &opt) != TCL_OK) {
return TCL_ERROR;
}
++i;
if (i == (objc-1)) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("Missing value for option %s.",
Tcl_GetString(objv[i - 1])));
return TCL_ERROR;
}
const char *s = Tcl_GetString(objv[i]);
switch (opt) {
case OPT_PROFILE:
if (!strcmp(s, "replace")) {
strict = 0;
} else if (strcmp(s, "strict")) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("Invalid value \"%s\" supplied for option \"-profile\". Must be "
"\"strict\" or \"replace\".",
s));
return TCL_ERROR;
}
break;
case OPT_MODE:
if (Tcl_GetIndexFromObj(interp, objv[i], normalizationForms, "normalization mode", 0, &mode) != TCL_OK) {
return TCL_ERROR;
}
break;
default:
TCL_UNREACHABLE();
}
}
Tcl_DString dsIn;
Tcl_DString dsNorm;
if (IcuObjToUCharDString(interp, objv[objc - 1], strict, &dsIn) != TCL_OK ||
IcuNormalizeUCharDString(interp, &dsIn, mode, &dsNorm) != TCL_OK) {
return TCL_ERROR;
}
Tcl_DStringFree(&dsIn);
Tcl_Obj *objPtr = IcuObjFromUCharDString(interp, &dsNorm, strict);
Tcl_DStringFree(&dsNorm);
if (objPtr) {
Tcl_SetObjResult(interp, objPtr);
|
| ︙ | ︙ | |||
1244 1245 1246 1247 1248 1249 1250 | /* *------------------------------------------------------------------------ * * IcuFindSymbol -- * * Finds an ICU symbol in a shared library and returns its value. * | | | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | /* *------------------------------------------------------------------------ * * IcuFindSymbol -- * * Finds an ICU symbol in a shared library and returns its value. * * Caller must be holding icu_mutex lock. * * Results: * Returns the symbol value or NULL if not found. * *------------------------------------------------------------------------ */ static void * |
| ︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 |
value = Tcl_FindSymbol(NULL, loadH, symbol);
if (value) {
suffixConvention = 1;
}
}
return value;
}
| | | 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 |
value = Tcl_FindSymbol(NULL, loadH, symbol);
if (value) {
suffixConvention = 1;
}
}
return value;
}
/*
*------------------------------------------------------------------------
*
* TclIcuInit --
*
* Load the ICU commands into the given interpreter. If the ICU
* commands have never previously been loaded, the ICU libraries are
|
| ︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 |
* ICU shared library names as well as function names *may* be versioned.
* See https://unicode-org.github.io/icu/userguide/icu4c/packaging.html
* for the gory details.
*/
if (icu_fns.nopen == 0) {
int i = 0;
Tcl_Obj *nameobj;
| | | 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 |
* ICU shared library names as well as function names *may* be versioned.
* See https://unicode-org.github.io/icu/userguide/icu4c/packaging.html
* for the gory details.
*/
if (icu_fns.nopen == 0) {
int i = 0;
Tcl_Obj *nameobj;
static const char * const iculibs[] = {
#if defined(_WIN32)
# define DLLNAME "icu%s%s.dll"
"icuuc??.dll", /* Windows, user-provided */
NULL,
"cygicuuc??.dll", /* When running under Cygwin */
#elif defined(__CYGWIN__)
# define DLLNAME "cygicu%s%s.dll"
|
| ︙ | ︙ | |||
1418 1419 1420 1421 1422 1423 1424 | } Tcl_DecrRefCount(nameobj); } #endif // _WIN32 /* Symbol may have version (Linux), or not (Windows, FreeBSD) */ | | | | | | 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 |
}
Tcl_DecrRefCount(nameobj);
}
#endif // _WIN32
/* Symbol may have version (Linux), or not (Windows, FreeBSD) */
#define ICUUC_SYM(name) \
do { \
icu_fns._##name = \
(fn_##name)IcuFindSymbol(icu_fns.libs[0], #name, icuversion); \
} while (0)
if (icu_fns.libs[0] != NULL) {
ICUUC_SYM(u_cleanup);
ICUUC_SYM(u_errorName);
ICUUC_SYM(u_strFromUTF32);
ICUUC_SYM(u_strFromUTF32WithSub);
|
| ︙ | ︙ | |||
1465 1466 1467 1468 1469 1470 1471 | ICUUC_SYM(unorm2_getNFDInstance); ICUUC_SYM(unorm2_getNFKCInstance); ICUUC_SYM(unorm2_getNFKDInstance); ICUUC_SYM(unorm2_normalize); #undef ICUUC_SYM } | | | | | | 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 |
ICUUC_SYM(unorm2_getNFDInstance);
ICUUC_SYM(unorm2_getNFKCInstance);
ICUUC_SYM(unorm2_getNFKDInstance);
ICUUC_SYM(unorm2_normalize);
#undef ICUUC_SYM
}
#define ICUIN_SYM(name) \
do { \
icu_fns._##name = \
(fn_##name)IcuFindSymbol(icu_fns.libs[1], #name, icuversion); \
} while (0)
if (icu_fns.libs[1] != NULL) {
ICUIN_SYM(ucsdet_close);
ICUIN_SYM(ucsdet_detect);
ICUIN_SYM(ucsdet_detectAll);
ICUIN_SYM(ucsdet_getName);
|
| ︙ | ︙ | |||
1493 1494 1495 1496 1497 1498 1499 |
* against self redefinition.
*/
if (icu_fns.libs[1] != NULL) {
/* Commands needing both libraries */
/* Ref count number of commands */
icu_fns.nopen += 3;
| | | | | | | | | > | | | | 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 |
* against self redefinition.
*/
if (icu_fns.libs[1] != NULL) {
/* Commands needing both libraries */
/* Ref count number of commands */
icu_fns.nopen += 3;
Tcl_CreateObjCommand(interp, "::tcl::unsupported::icu::convertto",
IcuConverttoObjCmd, 0, TclIcuCleanup);
Tcl_CreateObjCommand(interp, "::tcl::unsupported::icu::convertfrom",
IcuConvertfromObjCmd, 0, TclIcuCleanup);
Tcl_CreateObjCommand(interp, "::tcl::unsupported::icu::detect",
IcuDetectObjCmd, 0, TclIcuCleanup);
}
/* Commands needing only libs[0] (icuuc) */
/* Ref count number of commands */
icu_fns.nopen += 3; /* UPDATE AS CMDS ADDED/DELETED BELOW */
Tcl_CreateObjCommand(interp, "::tcl::unsupported::icu::converters",
IcuConverterNamesObjCmd, 0, TclIcuCleanup);
Tcl_CreateObjCommand(interp, "::tcl::unsupported::icu::aliases",
IcuConverterAliasesObjCmd, 0, TclIcuCleanup);
Tcl_CreateObjCommand(interp, "::tcl::unsupported::icu::normalize",
IcuNormalizeObjCmd, 0, TclIcuCleanup);
}
Tcl_MutexUnlock(&icu_mutex);
}
/*
*------------------------------------------------------------------------
*
* TclLoadIcuObjCmd --
*
* Loads and initializes ICU
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds result or error message.
*
*------------------------------------------------------------------------
*/
int
TclLoadIcuObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1 , objv, "");
return TCL_ERROR;
}
TclIcuInit(interp);
return TCL_OK;
|
| ︙ | ︙ |
Changes to generic/tclIndexObj.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | static int GetIndexFromObjList(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *tableObjPtr, const char *msg, int flags, Tcl_Size *indexPtr); static void UpdateStringOfIndex(Tcl_Obj *objPtr); static void DupIndex(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr); static void FreeIndex(Tcl_Obj *objPtr); | | | | < < < < < < < | | | | | | < | < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
static int GetIndexFromObjList(Tcl_Interp *interp,
Tcl_Obj *objPtr, Tcl_Obj *tableObjPtr,
const char *msg, int flags, Tcl_Size *indexPtr);
static void UpdateStringOfIndex(Tcl_Obj *objPtr);
static void DupIndex(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr);
static void FreeIndex(Tcl_Obj *objPtr);
static Tcl_ObjCmdProc PrefixAllObjCmd;
static Tcl_ObjCmdProc PrefixLongestObjCmd;
static Tcl_ObjCmdProc PrefixMatchObjCmd;
static void PrintUsage(Tcl_Interp *interp,
const Tcl_ArgvInfo *argTable);
/*
* The structure below defines the index Tcl object type by means of functions
* that can be invoked by generic object code.
*/
const Tcl_ObjType tclIndexType = {
"index", /* name */
FreeIndex, /* freeIntRepProc */
DupIndex, /* dupIntRepProc */
UpdateStringOfIndex, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
/*
* The definition of the internal representation of the "index" object; The
* internalRep.twoPtrValue.ptr1 field of an object of "index" type will be a
* pointer to one of these structures.
*
* Keep this structure declaration in sync with tclTestObj.c
*/
typedef struct {
void *tablePtr; /* Pointer to the table of strings */
Tcl_Size offset; /* Offset between table entries */
Tcl_Size index; /* Selected index into table. */
} IndexRep;
/*
* The following macros greatly simplify moving through a table...
*/
#define STRING_AT(table, offset) \
(*((const char *const *)(((char *)(table)) + (offset))))
#define NEXT_ENTRY(table, offset) \
(&(STRING_AT(table, offset)))
#define EXPAND_OF(indexRep) \
(((indexRep)->index != TCL_INDEX_NONE) ? STRING_AT((indexRep)->tablePtr, (indexRep)->offset*(indexRep)->index) : "")
/*
*----------------------------------------------------------------------
*
* GetIndexFromObjList --
*
* This procedure looks up an object's value in a table of strings and
|
| ︙ | ︙ | |||
100 101 102 103 104 105 106 | * Side effects: * Removes any internal representation that the object might have. (TODO: * find a way to cache the lookup.) * *---------------------------------------------------------------------- */ | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
* Side effects:
* Removes any internal representation that the object might have. (TODO:
* find a way to cache the lookup.)
*
*----------------------------------------------------------------------
*/
int
GetIndexFromObjList(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* Object containing the string to lookup. */
Tcl_Obj *tableObjPtr, /* List of strings to compare against the
* value of objPtr. */
const char *msg, /* Identifying word to use in error
* messages. */
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
/*
* Cache the found representation. Note that we want to avoid allocating a
* new internal-rep if at all possible since that is potentially a slow
* operation.
*/
if (objPtr && (index != TCL_INDEX_NONE) && !(flags & TCL_INDEX_TEMP_TABLE)) {
| | | | | | | | | | | | | | | | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
/*
* Cache the found representation. Note that we want to avoid allocating a
* new internal-rep if at all possible since that is potentially a slow
* operation.
*/
if (objPtr && (index != TCL_INDEX_NONE) && !(flags & TCL_INDEX_TEMP_TABLE)) {
irPtr = TclFetchInternalRep(objPtr, &tclIndexType);
if (irPtr) {
indexRep = (IndexRep *)irPtr->twoPtrValue.ptr1;
} else {
Tcl_ObjInternalRep ir;
indexRep = (IndexRep*)Tcl_Alloc(sizeof(IndexRep));
ir.twoPtrValue.ptr1 = indexRep;
Tcl_StoreInternalRep(objPtr, &tclIndexType, &ir);
}
indexRep->tablePtr = (void *) tablePtr;
indexRep->offset = offset;
indexRep->index = index;
}
uncachedDone:
if (indexPtr != NULL) {
flags &= (30-(int)(sizeof(int)<<1));
if (flags) {
if (flags == sizeof(uint16_t)<<1) {
*(uint16_t *)indexPtr = index;
return TCL_OK;
} else if (flags == (int)(sizeof(uint8_t)<<1)) {
*(uint8_t *)indexPtr = index;
return TCL_OK;
} else if (flags == (int)(sizeof(int64_t)<<1)) {
*(int64_t *)indexPtr = index;
return TCL_OK;
} else if (flags == (int)(sizeof(int32_t)<<1)) {
*(int32_t *)indexPtr = index;
return TCL_OK;
}
}
*(int *)indexPtr = index;
}
return TCL_OK;
error:
if (interp != NULL) {
/*
* Produce a fancy error message.
|
| ︙ | ︙ | |||
368 369 370 371 372 373 374 |
Tcl_SetObjResult(interp, resultPtr);
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", msg, key, (char *)NULL);
}
return TCL_ERROR;
}
/* #define again, needed below */
#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \
| | < | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
Tcl_SetObjResult(interp, resultPtr);
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", msg, key, (char *)NULL);
}
return TCL_ERROR;
}
/* #define again, needed below */
#define Tcl_GetIndexFromObjStruct(interp, objPtr, tablePtr, offset, msg, flags, indexPtr) \
((Tcl_GetIndexFromObjStruct)((interp), (objPtr), (tablePtr), (offset), (msg), (flags)|(int)(sizeof(*(indexPtr))<<1), (indexPtr)))
/*
*----------------------------------------------------------------------
*
* UpdateStringOfIndex --
*
* This function is called to convert a Tcl object from index internal
|
| ︙ | ︙ | |||
392 393 394 395 396 397 398 |
*----------------------------------------------------------------------
*/
static void
UpdateStringOfIndex(
Tcl_Obj *objPtr)
{
| < | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
*----------------------------------------------------------------------
*/
static void
UpdateStringOfIndex(
Tcl_Obj *objPtr)
{
IndexRep *indexRep = (IndexRep *)TclFetchInternalRep(objPtr, &tclIndexType)->twoPtrValue.ptr1;
const char *indexStr = EXPAND_OF(indexRep);
size_t len = strlen(indexStr);
TclOOM(Tcl_InitStringRep(objPtr, indexStr, len), len+1);
}
/*
|
| ︙ | ︙ | |||
461 462 463 464 465 466 467 |
Tcl_Free(TclFetchInternalRep(objPtr, &tclIndexType)->twoPtrValue.ptr1);
objPtr->typePtr = NULL;
}
/*
*----------------------------------------------------------------------
*
| | | | | | | > > > > > > > | | > | > | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
Tcl_Free(TclFetchInternalRep(objPtr, &tclIndexType)->twoPtrValue.ptr1);
objPtr->typePtr = NULL;
}
/*
*----------------------------------------------------------------------
*
* TclInitPrefixCmd --
*
* This procedure creates the "prefix" Tcl command. See the user
* documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitPrefixCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap prefixImplMap[] = {
{"all", PrefixAllObjCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"longest", PrefixLongestObjCmd,TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"match", PrefixMatchObjCmd, TclCompileBasicMin2ArgCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
Tcl_Command prefixCmd;
prefixCmd = TclMakeEnsemble(interp, "::tcl::prefix", prefixImplMap);
Tcl_Export(interp, Tcl_FindNamespace(interp, "::tcl", NULL, 0),
"prefix", 0);
return prefixCmd;
}
/*----------------------------------------------------------------------
*
* PrefixMatchObjCmd --
*
* This function implements the 'prefix match' Tcl command. Refer to the
|
| ︙ | ︙ | |||
504 505 506 507 508 509 510 |
*----------------------------------------------------------------------
*/
static int
PrefixMatchObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
*----------------------------------------------------------------------
*/
static int
PrefixMatchObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int flags = 0, result;
Tcl_Size errorLength, i;
Tcl_Obj *errorPtr = NULL;
const char *message = "option";
Tcl_Obj *tablePtr, *objPtr, *resultPtr;
static const char *const matchOptions[] = {
|
| ︙ | ︙ | |||
628 629 630 631 632 633 634 |
*----------------------------------------------------------------------
*/
static int
PrefixAllObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
*----------------------------------------------------------------------
*/
static int
PrefixAllObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result;
Tcl_Size length, elemLength, tableObjc, t;
const char *string, *elemString;
Tcl_Obj **tableObjv, *resultPtr;
if (objc != 3) {
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 |
*----------------------------------------------------------------------
*/
static int
PrefixLongestObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 |
*----------------------------------------------------------------------
*/
static int
PrefixLongestObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result;
Tcl_Size i, length, elemLength, resultLength, tableObjc, t;
const char *string, *elemString, *resultString;
Tcl_Obj **tableObjv;
if (objc != 3) {
|
| ︙ | ︙ | |||
805 806 807 808 809 810 811 |
*
*----------------------------------------------------------------------
*/
void
Tcl_WrongNumArgs(
Tcl_Interp *interp, /* Current interpreter. */
| | | | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 |
*
*----------------------------------------------------------------------
*/
void
Tcl_WrongNumArgs(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments to print from objv. */
Tcl_Obj *const objv[], /* Initial argument objects, which should be
* included in the error message. */
const char *message) /* Error message to print after the leading
* objects in objv. The message may be
* NULL. */
{
Tcl_Obj *objPtr;
Tcl_Size i, len, elemLen;
|
| ︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 |
const Tcl_ArgvInfo *infoPtr;
/* Pointer to the current entry in the table
* of argument descriptions. */
const Tcl_ArgvInfo *matchPtr;
/* Descriptor that matches current argument */
Tcl_Obj *curArg; /* Current argument */
const char *str = NULL;
| | | | | 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 |
const Tcl_ArgvInfo *infoPtr;
/* Pointer to the current entry in the table
* of argument descriptions. */
const Tcl_ArgvInfo *matchPtr;
/* Descriptor that matches current argument */
Tcl_Obj *curArg; /* Current argument */
const char *str = NULL;
char c; /* Second character of current arg (used for
* quick check for matching; use 2nd char.
* because first char. will almost always be
* '-'). */
Tcl_Size srcIndex; /* Location from which to read next argument
* from objv. */
Tcl_Size dstIndex; /* Used to keep track of current arguments
* being processed, primarily for error
* reporting. */
Tcl_Size objc; /* # arguments in objv still to process. */
Tcl_Size length; /* Number of characters in current argument */
Tcl_Size gf_ret; /* Return value from Tcl_ArgvGenFuncProc*/
if (remObjv != NULL) {
|
| ︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 |
* Take the appropriate action based on the option type
*/
gotMatch:
infoPtr = matchPtr;
switch (infoPtr->type) {
case TCL_ARGV_CONSTANT:
| | | 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 |
* Take the appropriate action based on the option type
*/
gotMatch:
infoPtr = matchPtr;
switch (infoPtr->type) {
case TCL_ARGV_CONSTANT:
*((int *) infoPtr->dstPtr) = PTR2INT(infoPtr->srcPtr);
break;
case TCL_ARGV_INT:
if (objc == 0) {
goto missingArg;
}
if (Tcl_GetIntFromObj(interp, objv[srcIndex],
(int *) infoPtr->dstPtr) == TCL_ERROR) {
|
| ︙ | ︙ | |||
1138 1139 1140 1141 1142 1143 1144 |
case TCL_ARGV_REST:
/*
* Only store the point where we got to if it's not to be written
* to NULL, so that TCL_ARGV_AUTO_REST works.
*/
if (infoPtr->dstPtr != NULL) {
| | | | 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 |
case TCL_ARGV_REST:
/*
* Only store the point where we got to if it's not to be written
* to NULL, so that TCL_ARGV_AUTO_REST works.
*/
if (infoPtr->dstPtr != NULL) {
*((int *) infoPtr->dstPtr) = dstIndex;
}
goto argsDone;
case TCL_ARGV_FLOAT:
if (objc == 0) {
goto missingArg;
}
if (Tcl_GetDoubleFromObj(interp, objv[srcIndex],
(double *) infoPtr->dstPtr) == TCL_ERROR) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected floating-point argument for \"%s\" but got \"%s\"",
infoPtr->keyStr, TclGetString(objv[srcIndex])));
goto error;
}
srcIndex++;
objc--;
|
| ︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 |
srcIndex++;
objc--;
}
break;
}
case TCL_ARGV_GENFUNC: {
Tcl_ArgvGenFuncProc *handlerProc = (Tcl_ArgvGenFuncProc *)
infoPtr->srcPtr;
gf_ret = handlerProc(infoPtr->clientData, interp, objc,
&objv[srcIndex], infoPtr->dstPtr);
if (gf_ret < 0) {
goto error;
| > > > > > | 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 |
srcIndex++;
objc--;
}
break;
}
case TCL_ARGV_GENFUNC: {
if (objc > INT_MAX) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"too many (%" TCL_SIZE_MODIFIER "d) arguments for TCL_ARGV_GENFUNC", objc));
goto error;
}
Tcl_ArgvGenFuncProc *handlerProc = (Tcl_ArgvGenFuncProc *)
infoPtr->srcPtr;
gf_ret = handlerProc(infoPtr->clientData, interp, objc,
&objv[srcIndex], infoPtr->dstPtr);
if (gf_ret < 0) {
goto error;
|
| ︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 |
Tcl_Interp *interp, /* Place information in this interp's result
* area. */
const Tcl_ArgvInfo *argTable)
/* Array of command-specific argument
* descriptions. */
{
const Tcl_ArgvInfo *infoPtr;
| | | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 |
Tcl_Interp *interp, /* Place information in this interp's result
* area. */
const Tcl_ArgvInfo *argTable)
/* Array of command-specific argument
* descriptions. */
{
const Tcl_ArgvInfo *infoPtr;
int width, numSpaces;
#define NUM_SPACES 20
static const char spaces[] = " ";
Tcl_Obj *msg;
/*
* First, compute the width of the widest option key, so that we can make
* everything line up.
|
| ︙ | ︙ |
Changes to generic/tclInt.decls.
| ︙ | ︙ | |||
118 119 120 121 122 123 124 |
#declare 44 {
# int TclGuessPackageName(const char *fileName, Tcl_DString *bufPtr)
#}
declare 45 {
int TclHideUnsafeCommands(Tcl_Interp *interp)
}
declare 46 {
| | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
#declare 44 {
# int TclGuessPackageName(const char *fileName, Tcl_DString *bufPtr)
#}
declare 45 {
int TclHideUnsafeCommands(Tcl_Interp *interp)
}
declare 46 {
int TclInExit(void)
}
# Removed in 9.0:
#declare 50 {
# void TclInitCompiledLocals(Tcl_Interp *interp, CallFrame *framePtr,
# Namespace *nsPtr)
#}
declare 51 {
|
| ︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 |
}
declare 61 {
Tcl_Obj *TclNewProcBodyObj(Proc *procPtr)
}
declare 62 {
int TclObjCommandComplete(Tcl_Obj *cmdPtr)
}
declare 64 {
int TclObjInvoke(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[],
int flags)
}
declare 69 {
| > > > > > | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
}
declare 61 {
Tcl_Obj *TclNewProcBodyObj(Proc *procPtr)
}
declare 62 {
int TclObjCommandComplete(Tcl_Obj *cmdPtr)
}
# Removed in 9.0:
#declare 63 {
# int TclObjInterpProc(void *clientData, Tcl_Interp *interp,
# Tcl_Size objc, Tcl_Obj *const objv[])
#}
declare 64 {
int TclObjInvoke(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[],
int flags)
}
declare 69 {
void *TclpAlloc(TCL_HASH_TYPE size)
}
declare 74 {
void TclpFree(void *ptr)
}
declare 75 {
unsigned long long TclpGetClicks(void)
}
declare 76 {
unsigned long long TclpGetSeconds(void)
}
# Removed in 9.0:
#declare 77 {
# void TclpGetTime(Tcl_Time *time)
#}
declare 81 {
void *TclpRealloc(void *ptr, TCL_HASH_TYPE size)
}
# Removed in 9.0:
#declare 88 {
# char *TclPrecTraceProc(void *clientData, Tcl_Interp *interp,
# const char *name1, const char *name2, int flags)
#}
declare 89 {
|
| ︙ | ︙ | |||
394 395 396 397 398 399 400 |
}
declare 171 {
int TclCheckExecutionTraces(Tcl_Interp *interp, const char *command,
Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags,
Tcl_Size objc, Tcl_Obj *const objv[])
}
declare 172 {
| | | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
}
declare 171 {
int TclCheckExecutionTraces(Tcl_Interp *interp, const char *command,
Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags,
Tcl_Size objc, Tcl_Obj *const objv[])
}
declare 172 {
int TclInThreadExit(void)
}
declare 173 {
int TclUniCharMatch(const Tcl_UniChar *string, Tcl_Size strLen,
const Tcl_UniChar *pattern, Tcl_Size ptnLen, int flags)
}
declare 175 {
int TclCallVarTraces(Interp *iPtr, Var *arrayPtr, Var *varPtr,
const char *part1, const char *part2, int flags, int leaveErrMsg)
}
declare 176 {
|
| ︙ | ︙ | |||
456 457 458 459 460 461 462 |
declare 213 {
Tcl_Obj *TclGetObjNameOfExecutable(void)
}
declare 214 {
void TclSetObjNameOfExecutable(Tcl_Obj *name, Tcl_Encoding encoding)
}
declare 215 {
| | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
declare 213 {
Tcl_Obj *TclGetObjNameOfExecutable(void)
}
declare 214 {
void TclSetObjNameOfExecutable(Tcl_Obj *name, Tcl_Encoding encoding)
}
declare 215 {
void *TclStackAlloc(Tcl_Interp *interp, TCL_HASH_TYPE numBytes)
}
declare 216 {
void TclStackFree(Tcl_Interp *interp, void *freePtr)
}
declare 217 {
int TclPushStackFrame(Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr,
Tcl_Namespace *namespacePtr, int isProcCallFrame)
|
| ︙ | ︙ | |||
504 505 506 507 508 509 510 |
}
declare 227 {
void TclSetNsPath(Namespace *nsPtr, Tcl_Size pathLength,
Tcl_Namespace *pathAry[])
}
declare 229 {
int TclPtrMakeUpvar(Tcl_Interp *interp, Var *otherP1Ptr,
| | | | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
}
declare 227 {
void TclSetNsPath(Namespace *nsPtr, Tcl_Size pathLength,
Tcl_Namespace *pathAry[])
}
declare 229 {
int TclPtrMakeUpvar(Tcl_Interp *interp, Var *otherP1Ptr,
const char *myName, int myFlags, int index)
}
declare 230 {
Var *TclObjLookupVar(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
const char *part2, int flags, const char *msg,
int createPart1, int createPart2, Var **arrayPtrPtr)
}
declare 231 {
int TclGetNamespaceFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
Tcl_Namespace **nsPtrPtr)
}
# Bits and pieces of TIP#280's guts
declare 232 {
int TclEvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags,
const CmdFrame *invoker, int word)
}
declare 233 {
void TclGetSrcInfoForPc(CmdFrame *contextPtr)
}
# Exports for VarReform compat: Itcl, XOTcl like to peek into our varTables :(
declare 234 {
|
| ︙ | ︙ | |||
551 552 553 554 555 556 557 |
}
declare 239 {
int TclNRInterpProcCore(Tcl_Interp *interp, Tcl_Obj *procNameObj,
Tcl_Size skip, ProcErrorProc *errorProc)
}
declare 240 {
int TclNRRunCallbacks(Tcl_Interp *interp, int result,
| | | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
}
declare 239 {
int TclNRInterpProcCore(Tcl_Interp *interp, Tcl_Obj *procNameObj,
Tcl_Size skip, ProcErrorProc *errorProc)
}
declare 240 {
int TclNRRunCallbacks(Tcl_Interp *interp, int result,
struct NRE_callback *rootPtr)
}
declare 241 {
int TclNREvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags,
const CmdFrame *invoker, int word)
}
declare 242 {
int TclNREvalObjv(Tcl_Interp *interp, Tcl_Size objc,
Tcl_Obj *const objv[], int flags, Command *cmdPtr)
}
# Tcl_Obj leak detection support.
declare 243 {
void TclDbDumpActiveObjects(FILE *outFile)
}
|
| ︙ | ︙ | |||
589 590 591 592 593 594 595 |
declare 248 {
int TclCopyChannel(Tcl_Interp *interp, Tcl_Channel inChan,
Tcl_Channel outChan, long long toRead, Tcl_Obj *cmdPtr)
}
declare 249 {
char *TclDoubleDigits(double dv, int ndigits, int flags,
| | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
declare 248 {
int TclCopyChannel(Tcl_Interp *interp, Tcl_Channel inChan,
Tcl_Channel outChan, long long toRead, Tcl_Obj *cmdPtr)
}
declare 249 {
char *TclDoubleDigits(double dv, int ndigits, int flags,
int *decpt, int *signum, char **endPtr)
}
# TIP #285: Script cancellation support.
declare 250 {
void TclSetChildCancelFlags(Tcl_Interp *interp, int flags, int force)
}
# Allow extensions for optimization
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 |
}
declare 15 {
int TclpCreateProcess(Tcl_Interp *interp, size_t argc,
const char **argv, TclFile inputFile, TclFile outputFile,
TclFile errorFile, Tcl_Pid *pidPtr)
}
declare 16 {
| | | 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
}
declare 15 {
int TclpCreateProcess(Tcl_Interp *interp, size_t argc,
const char **argv, TclFile inputFile, TclFile outputFile,
TclFile errorFile, Tcl_Pid *pidPtr)
}
declare 16 {
int TclpIsAtty(int fd)
}
declare 17 {
int TclUnixCopyFile(const char *src, const char *dst,
const Tcl_StatBuf *statBufPtr, int dontCopyAtts)
}
declare 20 {
void TclWinAddProcess(void *hProcess, Tcl_Size id)
|
| ︙ | ︙ |
Changes to generic/tclInt.h.
1 2 3 4 5 | /* * tclInt.h -- * * Declarations of things used internally by the Tcl interpreter. * | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * tclInt.h -- * * Declarations of things used internally by the Tcl interpreter. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1993-1997 Lucent Technologies. * Copyright (c) 1994-1998 Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved. * Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net> * Copyright (c) 2006-2008 by Joe Mistachkin. All rights reserved. * Copyright (c) 2008 by Miguel Sofer. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLINT #define _TCLINT |
| ︙ | ︙ | |||
165 166 167 168 169 170 171 172 173 174 175 176 177 178 | #define TCL_FALLTHROUGH() __attribute__((fallthrough)) #else // Nothing documented as an alternative to the standard [[fallthrough]]. #define TCL_FALLTHROUGH() ((void) 0) #endif #endif // TCL_FALLTHROUGH /* * The following procedures allow namespaces to be customized to support * special name resolution rules for commands/variables. */ struct Tcl_ResolvedVarInfo; | > > > > > > > | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | #define TCL_FALLTHROUGH() __attribute__((fallthrough)) #else // Nothing documented as an alternative to the standard [[fallthrough]]. #define TCL_FALLTHROUGH() ((void) 0) #endif #endif // TCL_FALLTHROUGH #if (TCL_MAJOR_VERSION < 9) && !defined(Tcl_Size) # define Tcl_Size int # define Tcl_ObjCmdProc2 Tcl_ObjCmdProc # define Tcl_CmdObjTraceProc2 Tcl_CmdObjTraceProc # define _TCLSIZEHANDLED # endif /* * The following procedures allow namespaces to be customized to support * special name resolution rules for commands/variables. */ struct Tcl_ResolvedVarInfo; |
| ︙ | ︙ | |||
220 221 222 223 224 225 226 | * TCL_NAMESPACE_ONLY, or TCL_LEAVE_ERR_MSG; it signals that the variable * lookup is performed for upvar (or similar) purposes, with slightly * different rules: * - Bug #696893 - variable is either proc-local or in the current * namespace; never follow the second (global) resolution path * - Bug #631741 - do not use special namespace or interp resolvers */ | | | < > > | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
* TCL_NAMESPACE_ONLY, or TCL_LEAVE_ERR_MSG; it signals that the variable
* lookup is performed for upvar (or similar) purposes, with slightly
* different rules:
* - Bug #696893 - variable is either proc-local or in the current
* namespace; never follow the second (global) resolution path
* - Bug #631741 - do not use special namespace or interp resolvers
*/
#define TCL_AVOID_RESOLVERS 0x40000
/*
*----------------------------------------------------------------
* Data structures related to namespaces.
*----------------------------------------------------------------
*/
typedef struct Tcl_Ensemble Tcl_Ensemble;
typedef struct NamespacePathEntry NamespacePathEntry;
/*
* Special hashtable for variables: This is just a Tcl_HashTable with nsPtr
* and arrayPtr fields added at the end so that variables can find their
* namespace and possibly containing array without having to copy a pointer in
* their struct by accessing them via their hPtr->tablePtr.
*/
typedef struct TclVarHashTable {
Tcl_HashTable table; /* "Inherit" from Tcl_HashTable. */
struct Namespace *nsPtr; /* The namespace containing the variables. */
#if TCL_MAJOR_VERSION > 8
struct Var *arrayPtr; /* The array containing the variables, if they
* are variables in an array at all. */
#endif /* TCL_MAJOR_VERSION > 8 */
} TclVarHashTable;
/*
* Define this to reduce the amount of space that the average namespace
* consumes by only allocating the table of child namespaces when necessary.
* Defining it breaks compatibility for Tcl extensions (e.g., itcl) which
* reach directly into the Namespace structure.
|
| ︙ | ︙ | |||
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
* strings; values have type (Namespace *). */
#else
Tcl_HashTable *childTablePtr;
/* Contains any child namespaces. Indexed by
* strings; values have type (Namespace *). If
* NULL, there are no children. */
#endif
size_t nsId; /* Unique id for the namespace. */
Tcl_Interp *interp; /* The interpreter containing this
* namespace. */
int flags; /* OR-ed combination of the namespace status
* flags NS_DYING and NS_DEAD listed below. */
Tcl_Size activationCount; /* Number of "activations" or active call
* frames for this namespace that are on the
* Tcl call stack. The namespace won't be
| > > > > | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
* strings; values have type (Namespace *). */
#else
Tcl_HashTable *childTablePtr;
/* Contains any child namespaces. Indexed by
* strings; values have type (Namespace *). If
* NULL, there are no children. */
#endif
#if TCL_MAJOR_VERSION > 8
size_t nsId; /* Unique id for the namespace. */
#else
unsigned long nsId;
#endif
Tcl_Interp *interp; /* The interpreter containing this
* namespace. */
int flags; /* OR-ed combination of the namespace status
* flags NS_DYING and NS_DEAD listed below. */
Tcl_Size activationCount; /* Number of "activations" or active call
* frames for this namespace that are on the
* Tcl call stack. The namespace won't be
|
| ︙ | ︙ | |||
400 401 402 403 404 405 406 | /* Linked list pointers or NULL at either end * of the list that hangs off Namespace's * commandPathSourceList field. */ }; /* * Flags used to represent the status of a namespace: | < < > | < | | | < | < > > | < | | < | | < | | < < < | | | > | > > > > > > > < > > > > | | | | < < < | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | /* Linked list pointers or NULL at either end * of the list that hangs off Namespace's * commandPathSourceList field. */ }; /* * Flags used to represent the status of a namespace: * * NS_DYING - 1 means Tcl_DeleteNamespace has been called to delete the * namespace. There may still be active call frames on the Tcl * stack that refer to the namespace. When the last call frame * referring to it has been popped, its remaining variables and * commands are destroyed and it is marked "dead" (NS_DEAD). * NS_TEARDOWN -1 means that TclTeardownNamespace has already been called on * this namespace and it should not be called again [Bug 1355942]. * NS_DEAD - 1 means Tcl_DeleteNamespace has been called to delete the * namespace and no call frames still refer to it. It is no longer * accessible by name. Its variables and commands have already * been destroyed. When the last namespaceName object in any byte * code unit that refers to the namespace has been freed (i.e., * when the namespace's refCount is 0), the namespace's storage * will be freed. * NS_SUPPRESS_COMPILATION - * Marks the commands in this namespace for not being compiled, * forcing them to be looked up every time. */ #define NS_DYING 0x01 #define NS_DEAD 0x02 #define NS_TEARDOWN 0x04 #ifndef TCL_NO_DEPRECATED # define NS_KILLED 0x04 /* Same as NS_TEARDOWN */ #endif #define NS_SUPPRESS_COMPILATION 0x08 /* * Flags passed to TclGetNamespaceForQualName: * * TCL_GLOBAL_ONLY - (see tcl.h) Look only in the global ns. * TCL_NAMESPACE_ONLY - (see tcl.h) Look only in the context ns. * TCL_CREATE_NS_IF_UNKNOWN - Create unknown namespaces. * TCL_FIND_ONLY_NS - The name sought is a namespace name. * TCL_FIND_IF_NOT_SIMPLE - Retrieve last namespace even if the rest of * name is not simple name (contains ::). */ #define TCL_CREATE_NS_IF_UNKNOWN 0x800 #define TCL_FIND_ONLY_NS 0x1000 #define TCL_FIND_IF_NOT_SIMPLE 0x2000 /* * The client data for an ensemble command. This consists of the table of * commands that are actually exported by the namespace, and an epoch counter * that, combined with the exportLookupEpoch field of the namespace structure, * defines whether the table contains valid data or will need to be recomputed * next time the ensemble command is called. |
| ︙ | ︙ | |||
524 525 526 527 528 529 530 | * the length of the list in the parameterList * field. */ } EnsembleConfig; /* * Various bits for the EnsembleConfig.flags field. */ | | | | < | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | * the length of the list in the parameterList * field. */ } EnsembleConfig; /* * Various bits for the EnsembleConfig.flags field. */ #define ENSEMBLE_DEAD 0x1 /* Flag value to say that the ensemble is dead * and on its way out. */ #define ENSEMBLE_COMPILE 0x4 /* Flag to enable bytecode compilation of an * ensemble. */ /* *---------------------------------------------------------------- * Data structures related to variables. These are used primarily in tclVar.c *---------------------------------------------------------------- */ |
| ︙ | ︙ | |||
594 595 596 597 598 599 600 |
struct ActiveCommandTrace *nextPtr;
/* Next in list of all active command traces
* for the interpreter, or NULL if no more. */
CommandTrace *nextTracePtr; /* Next trace to check after current trace
* procedure returns; if this trace gets
* deleted, must update pointer to avoid using
* free'd memory. */
| | | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
struct ActiveCommandTrace *nextPtr;
/* Next in list of all active command traces
* for the interpreter, or NULL if no more. */
CommandTrace *nextTracePtr; /* Next trace to check after current trace
* procedure returns; if this trace gets
* deleted, must update pointer to avoid using
* free'd memory. */
int reverseScan; /* Boolean set true when traces are scanning
* in reverse order. */
} ActiveCommandTrace;
/*
* When a variable trace is active (i.e. its associated procedure is
* executing) one of the following structures is linked into a list associated
* with the variable's interpreter. The information in the structure is needed
|
| ︙ | ︙ | |||
731 732 733 734 735 736 737 | * temporary variable. Temporaries have a NULL * name. * VAR_RESOLVED - 1 if name resolution has been done for this * variable. * VAR_IS_ARGS 1 if this variable is the last argument and is * named "args". */ | | | > | > > > > > > > > | | | > | < | | | | | | | | | | | | | | < < < < < < | | | | < | 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 | * temporary variable. Temporaries have a NULL * name. * VAR_RESOLVED - 1 if name resolution has been done for this * variable. * VAR_IS_ARGS 1 if this variable is the last argument and is * named "args". */ /* * FLAGS RENUMBERED: everything breaks already, make things simpler. * * IMPORTANT: skip the values 0x10, 0x20, 0x40, 0x800 corresponding to * TCL_TRACE_(READS/WRITES/UNSETS/ARRAY): makes code simpler in tclTrace.c * * Keep the flag values for VAR_ARGUMENT and VAR_TEMPORARY so that old values * in precompiled scripts keep working. */ /* Type of value (0 is scalar) */ #define VAR_ARRAY 0x1 #define VAR_LINK 0x2 #define VAR_CONSTANT 0x10000 #define VAR_TYPE \ (VAR_ARRAY | VAR_LINK | VAR_CONSTANT) /* Type of storage (0 is compiled local) */ #define VAR_IN_HASHTABLE 0x4 #define VAR_DEAD_HASH 0x8 #define VAR_ARRAY_ELEMENT 0x1000 #define VAR_NAMESPACE_VAR 0x80 /* KEEP OLD VALUE for Itcl */ #define VAR_ALL_HASH \ (VAR_IN_HASHTABLE|VAR_DEAD_HASH|VAR_NAMESPACE_VAR|VAR_ARRAY_ELEMENT) /* Trace and search state. */ #define VAR_TRACED_READ 0x10 /* TCL_TRACE_READS */ #define VAR_TRACED_WRITE 0x20 /* TCL_TRACE_WRITES */ #define VAR_TRACED_UNSET 0x40 /* TCL_TRACE_UNSETS */ #define VAR_TRACED_ARRAY 0x800 /* TCL_TRACE_ARRAY */ #define VAR_TRACE_ACTIVE 0x2000 #define VAR_SEARCH_ACTIVE 0x4000 #define VAR_ALL_TRACES \ (VAR_TRACED_READ|VAR_TRACED_WRITE|VAR_TRACED_ARRAY|VAR_TRACED_UNSET) /* Special handling on initialisation (only CompiledLocal). */ #define VAR_ARGUMENT 0x100 /* KEEP OLD VALUE! See tclProc.c */ #define VAR_TEMPORARY 0x200 /* KEEP OLD VALUE! See tclProc.c */ #define VAR_IS_ARGS 0x400 #define VAR_RESOLVED 0x8000 #define TCL_HASH_FIND ((int *)-1) /* * Macros to ensure that various flag bits are set properly for variables. * The ANSI C "prototypes" for these macros are: * |
| ︙ | ︙ | |||
804 805 806 807 808 809 810 |
#define TclSetVarConstant(varPtr) \
(varPtr)->flags = ((varPtr)->flags & ~(VAR_ARRAY|VAR_LINK)) | VAR_CONSTANT
#define TclSetVarArrayElement(varPtr) \
(varPtr)->flags = ((varPtr)->flags & ~VAR_ARRAY) | VAR_ARRAY_ELEMENT
#define TclSetVarUndefined(varPtr) \
| | | | | | | | | | | | | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 |
#define TclSetVarConstant(varPtr) \
(varPtr)->flags = ((varPtr)->flags & ~(VAR_ARRAY|VAR_LINK)) | VAR_CONSTANT
#define TclSetVarArrayElement(varPtr) \
(varPtr)->flags = ((varPtr)->flags & ~VAR_ARRAY) | VAR_ARRAY_ELEMENT
#define TclSetVarUndefined(varPtr) \
(varPtr)->flags &= ~(VAR_ARRAY|VAR_LINK|VAR_CONSTANT);\
(varPtr)->value.objPtr = NULL
#define TclClearVarUndefined(varPtr)
#define TclSetVarTraceActive(varPtr) \
(varPtr)->flags |= VAR_TRACE_ACTIVE
#define TclClearVarTraceActive(varPtr) \
(varPtr)->flags &= ~VAR_TRACE_ACTIVE
#define TclSetVarNamespaceVar(varPtr) \
if (!TclIsVarNamespaceVar(varPtr)) {\
(varPtr)->flags |= VAR_NAMESPACE_VAR;\
if (TclIsVarInHash(varPtr)) {\
((VarInHash *)(varPtr))->refCount++;\
}\
}
#define TclClearVarNamespaceVar(varPtr) \
if (TclIsVarNamespaceVar(varPtr)) {\
(varPtr)->flags &= ~VAR_NAMESPACE_VAR;\
if (TclIsVarInHash(varPtr)) {\
((VarInHash *)(varPtr))->refCount--;\
}\
}
/*
* Macros to read various flag bits of variables.
* The ANSI C "prototypes" for these macros are:
*
* MODULE_SCOPE int TclIsVarScalar(Var *varPtr);
|
| ︙ | ︙ | |||
915 916 917 918 919 920 921 |
#define VarHashGetKey(varPtr) \
(((VarInHash *)(varPtr))->entry.key.objPtr)
/*
* Macros for direct variable access by TEBC.
*/
| | | | | | | | 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
#define VarHashGetKey(varPtr) \
(((VarInHash *)(varPtr))->entry.key.objPtr)
/*
* Macros for direct variable access by TEBC.
*/
#define TclIsVarTricky(varPtr,trickyFlags) \
( ((varPtr)->flags & (VAR_ARRAY|VAR_LINK|trickyFlags)) \
|| (TclIsVarInHash(varPtr) \
&& (TclVarParentArray(varPtr) != NULL) \
&& (TclVarParentArray(varPtr)->flags & (trickyFlags))))
#define TclIsVarDirectReadable(varPtr) \
( (!TclIsVarTricky(varPtr,VAR_TRACED_READ)) \
&& (varPtr)->value.objPtr)
#define TclIsVarDirectWritable(varPtr) \
(!TclIsVarTricky(varPtr,VAR_TRACED_WRITE|VAR_DEAD_HASH|VAR_CONSTANT))
#define TclIsVarDirectUnsettable(varPtr) \
(!TclIsVarTricky(varPtr,VAR_TRACED_READ|VAR_TRACED_WRITE|VAR_TRACED_UNSET|VAR_DEAD_HASH|VAR_CONSTANT))
#define TclIsVarDirectModifyable(varPtr) \
( (!TclIsVarTricky(varPtr,VAR_TRACED_READ|VAR_TRACED_WRITE|VAR_CONSTANT)) \
&& (varPtr)->value.objPtr)
#define TclIsVarDirectReadable2(varPtr, arrayPtr) \
(TclIsVarDirectReadable(varPtr) &&\
(!(arrayPtr) || !((arrayPtr)->flags & VAR_TRACED_READ)))
#define TclIsVarDirectWritable2(varPtr, arrayPtr) \
(TclIsVarDirectWritable(varPtr) &&\
(!(arrayPtr) || !((arrayPtr)->flags & VAR_TRACED_WRITE)))
#define TclIsVarDirectModifyable2(varPtr, arrayPtr) \
(TclIsVarDirectModifyable(varPtr) &&\
(!(arrayPtr) || !((arrayPtr)->flags & (VAR_TRACED_READ|VAR_TRACED_WRITE))))
/*
*----------------------------------------------------------------
* Data structures related to procedures. These are used primarily in
* tclProc.c, tclCompile.c, and tclExecute.c.
*----------------------------------------------------------------
|
| ︙ | ︙ | |||
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
/* Next compiler-recognized local variable for
* this procedure, or NULL if this is the last
* local. */
Tcl_Size nameLength; /* The number of bytes in local variable's name.
* Among others used to speed up var lookups. */
Tcl_Size frameIndex; /* Index in the array of compiler-assigned
* variables in the procedure call frame. */
Tcl_Obj *defValuePtr; /* Pointer to the default value of an
* argument, if any. NULL if not an argument
* or, if an argument, no default value. */
Tcl_ResolvedVarInfo *resolveInfo;
/* Customized variable resolution info
* supplied by the Tcl_ResolveCompiledVarProc
* associated with a namespace. Each variable
* is marked by a unique tag during
* compilation, and that same tag is used to
* find the variable at runtime. */
int flags; /* Flag bits for the local variable. Same as
* the flags for the Var structure above,
* although only VAR_ARGUMENT, VAR_TEMPORARY,
* and VAR_RESOLVED make sense. */
char name[TCLFLEXARRAY]; /* Name of the local variable starts here. If
* the name is NULL, this will just be '\0'.
* The actual size of this field will be large
* enough to hold the name. MUST BE THE LAST
* FIELD IN THE STRUCTURE! */
} CompiledLocal;
| > > > > > | 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 |
/* Next compiler-recognized local variable for
* this procedure, or NULL if this is the last
* local. */
Tcl_Size nameLength; /* The number of bytes in local variable's name.
* Among others used to speed up var lookups. */
Tcl_Size frameIndex; /* Index in the array of compiler-assigned
* variables in the procedure call frame. */
#if TCL_MAJOR_VERSION < 9
int flags;
#endif
Tcl_Obj *defValuePtr; /* Pointer to the default value of an
* argument, if any. NULL if not an argument
* or, if an argument, no default value. */
Tcl_ResolvedVarInfo *resolveInfo;
/* Customized variable resolution info
* supplied by the Tcl_ResolveCompiledVarProc
* associated with a namespace. Each variable
* is marked by a unique tag during
* compilation, and that same tag is used to
* find the variable at runtime. */
#if TCL_MAJOR_VERSION > 8
int flags; /* Flag bits for the local variable. Same as
* the flags for the Var structure above,
* although only VAR_ARGUMENT, VAR_TEMPORARY,
* and VAR_RESOLVED make sense. */
#endif
char name[TCLFLEXARRAY]; /* Name of the local variable starts here. If
* the name is NULL, this will just be '\0'.
* The actual size of this field will be large
* enough to hold the name. MUST BE THE LAST
* FIELD IN THE STRUCTURE! */
} CompiledLocal;
|
| ︙ | ︙ | |||
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 |
* compiler-allocated local variables, or NULL
* if none. The first numArgs entries in this
* list describe the procedure's formal
* arguments. */
CompiledLocal *lastLocalPtr;/* Pointer to the last allocated local
* variable or NULL if none. This has frame
* index (numCompiledLocals-1). */
} Proc;
/*
* The type of functions called to process errors found during the execution
* of a procedure (or lambda term or ...).
*/
typedef void (ProcErrorProc)(Tcl_Interp *interp, Tcl_Obj *procNameObj);
| > > > > | 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 |
* compiler-allocated local variables, or NULL
* if none. The first numArgs entries in this
* list describe the procedure's formal
* arguments. */
CompiledLocal *lastLocalPtr;/* Pointer to the last allocated local
* variable or NULL if none. This has frame
* index (numCompiledLocals-1). */
int flags; /* Miscellaneous bits of proc. */
} Proc;
#define PROC_CMD_OWNED 0x80
/*
* The type of functions called to process errors found during the execution
* of a procedure (or lambda term or ...).
*/
typedef void (ProcErrorProc)(Tcl_Interp *interp, Tcl_Obj *procNameObj);
|
| ︙ | ︙ | |||
1087 1088 1089 1090 1091 1092 1093 |
struct ActiveInterpTrace *nextPtr;
/* Next in list of all active command traces
* for the interpreter, or NULL if no more. */
Trace *nextTracePtr; /* Next trace to check after current trace
* procedure returns; if this trace gets
* deleted, must update pointer to avoid using
* free'd memory. */
| | < < > | | | | | | > | > > > | 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 |
struct ActiveInterpTrace *nextPtr;
/* Next in list of all active command traces
* for the interpreter, or NULL if no more. */
Trace *nextTracePtr; /* Next trace to check after current trace
* procedure returns; if this trace gets
* deleted, must update pointer to avoid using
* free'd memory. */
int reverseScan; /* Boolean set true when traces are scanning
* in reverse order. */
} ActiveInterpTrace;
/*
* Flag values designating types of execution traces. See tclTrace.c for
* related flag values.
*
* TCL_TRACE_ENTER_EXEC - triggers enter/enterstep traces.
* - passed to Tcl_CreateObjTrace to set up
* "enterstep" traces.
* TCL_TRACE_LEAVE_EXEC - triggers leave/leavestep traces.
* - passed to Tcl_CreateObjTrace to set up
* "leavestep" traces.
*/
#define TCL_TRACE_ENTER_EXEC 1
#define TCL_TRACE_LEAVE_EXEC 2
#if TCL_MAJOR_VERSION > 8
#define TclObjTypeHasProc(objPtr, proc) (((objPtr)->typePtr \
&& ((offsetof(Tcl_ObjType, proc) < offsetof(Tcl_ObjType, version)) \
|| (offsetof(Tcl_ObjType, proc) < (objPtr)->typePtr->version))) ? \
((objPtr)->typePtr)->proc : NULL)
MODULE_SCOPE Tcl_Size TclLengthOne(Tcl_Obj *);
|
| ︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 |
Tcl_Obj *valueObj,
Tcl_Obj *listObj,
int *boolResult)
{
Tcl_ObjTypeInOperatorProc *proc = TclObjTypeHasProc(listObj, inOperProc);
return proc(interp, valueObj, listObj, boolResult);
}
| | < | 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 |
Tcl_Obj *valueObj,
Tcl_Obj *listObj,
int *boolResult)
{
Tcl_ObjTypeInOperatorProc *proc = TclObjTypeHasProc(listObj, inOperProc);
return proc(interp, valueObj, listObj, boolResult);
}
#endif /* TCL_MAJOR_VERSION > 8 */
/*
* The structure below defines an entry in the assocData hash table which is
* associated with an interpreter. The entry contains a pointer to a function
* to call when the interpreter is deleted, and a pointer to a user-defined
* piece of data.
*/
|
| ︙ | ︙ | |||
1260 1261 1262 1263 1264 1265 1266 |
* commands and global variables. */
int isProcCallFrame; /* If 0, the frame was pushed to execute a
* namespace command and var references are
* treated as references to namespace vars;
* varTablePtr and compiledLocals are ignored.
* If FRAME_IS_PROC is set, the frame was
* pushed to execute a Tcl procedure and may
| | < | | | | 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 |
* commands and global variables. */
int isProcCallFrame; /* If 0, the frame was pushed to execute a
* namespace command and var references are
* treated as references to namespace vars;
* varTablePtr and compiledLocals are ignored.
* If FRAME_IS_PROC is set, the frame was
* pushed to execute a Tcl procedure and may
* have local vars. */
Tcl_Size objc; /* This and objv below describe the arguments
* for this procedure call. */
Tcl_Obj *const *objv; /* Array of argument objects. */
struct CallFrame *callerPtr;/* Value of interp->framePtr when this
* procedure was invoked (i.e. next higher in
* stack of all active procedures). */
struct CallFrame *callerVarPtr;
/* Value of interp->varFramePtr when this
* procedure was invoked (i.e. determines
* variable scoping within caller). Same as
* callerPtr unless an "uplevel" command or
* something equivalent was active in the
* caller). */
Tcl_Size level; /* Level of this procedure, for "uplevel"
* purposes (i.e. corresponds to nesting of
* callerVarPtr's, not callerPtr's). 1 for
* outermost procedure, 0 for top-level. */
Proc *procPtr; /* Points to the structure defining the called
* procedure. Used to get information such as
* the number of compiled local variables
|
| ︙ | ︙ | |||
1310 1311 1312 1313 1314 1315 1316 |
* specify. */
LocalCache *localCachePtr; /* Pointer to the start of the cached variable
* names and initialisation data for local
* variables. */
Tcl_Obj *tailcallPtr; /* NULL if no tailcall is scheduled */
} CallFrame;
| < | | | | | < | 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 |
* specify. */
LocalCache *localCachePtr; /* Pointer to the start of the cached variable
* names and initialisation data for local
* variables. */
Tcl_Obj *tailcallPtr; /* NULL if no tailcall is scheduled */
} CallFrame;
#define FRAME_IS_PROC 0x1 /* Frame is a procedure body. */
#define FRAME_IS_LAMBDA 0x2 /* Frame is a lambda term body. */
#define FRAME_IS_METHOD 0x4 /* The frame is a method body, and the frame's
* clientData field contains a CallContext
* reference. Part of TIP#257. */
#define FRAME_IS_OO_DEFINE 0x8 /* The frame is part of the inside workings of
* the [oo::define] command; the clientData
* 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
* The structure below defines a command frame. A command frame provides
* location information for all commands executing a tcl script (source, eval,
* uplevel, procedure bodies, ...). The runtime structure essentially contains
* the stack trace as it would be if the currently executing command were to
|
| ︙ | ︙ | |||
1353 1354 1355 1356 1357 1358 1359 |
/*
* General data. Always available.
*/
int type; /* Values see below. */
int level; /* Number of frames in stack, prevent O(n)
* scan of list. */
| | | 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 |
/*
* General data. Always available.
*/
int type; /* Values see below. */
int level; /* Number of frames in stack, prevent O(n)
* scan of list. */
Tcl_Size *line; /* Lines the words of the command start on. */
Tcl_Size nline; /* Number of lines in CmdFrame.line. */
CallFrame *framePtr; /* Procedure activation record, may be
* NULL. */
struct CmdFrame *nextPtr; /* Link to calling frame. */
/*
* Data needed for Eval vs TEBC
*
|
| ︙ | ︙ | |||
1443 1444 1445 1446 1447 1448 1449 | * file "tclBasic.c", and stored in the thread-global hash table "lineCLPtr" in * file "tclObj.c". They are used by the functions TclSetByteCodeFromAny() and * TclCompileScript(), both found in the file "tclCompile.c". Their memory is * released by the function TclFreeObj(), in the file "tclObj.c", and also by * the function TclThreadFinalizeObjects(), in the same file. */ | < | < | 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 |
* file "tclBasic.c", and stored in the thread-global hash table "lineCLPtr" in
* file "tclObj.c". They are used by the functions TclSetByteCodeFromAny() and
* TclCompileScript(), both found in the file "tclCompile.c". Their memory is
* released by the function TclFreeObj(), in the file "tclObj.c", and also by
* the function TclThreadFinalizeObjects(), in the same file.
*/
#define CLL_END (-1)
typedef struct ContLineLoc {
Tcl_Size num; /* Number of entries in loc, not counting the
* final -1 marker entry. */
Tcl_Size loc[TCLFLEXARRAY]; /* Table of locations, as character offsets.
* The table is allocated as part of the
* structure, extending behind the nominal end
|
| ︙ | ︙ | |||
1473 1474 1475 1476 1477 1478 1479 | * TCL_LOCATION_SOURCE : Frame is for a script evaluated by EvalEx, from a * sourced file. * TCL_LOCATION_PROC : Frame is for bytecode of a procedure. * * A TCL_LOCATION_BC type in a frame can be overridden by _SOURCE and _PROC * types, per the context of the byte code in execution. */ | | | | | | | | | < | 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 | * TCL_LOCATION_SOURCE : Frame is for a script evaluated by EvalEx, from a * sourced file. * TCL_LOCATION_PROC : Frame is for bytecode of a procedure. * * A TCL_LOCATION_BC type in a frame can be overridden by _SOURCE and _PROC * types, per the context of the byte code in execution. */ #define TCL_LOCATION_EVAL (0) /* Location in a dynamic eval script. */ #define TCL_LOCATION_BC (2) /* Location in byte code. */ #define TCL_LOCATION_PREBC (3) /* Location in precompiled byte code, no * location. */ #define TCL_LOCATION_SOURCE (4) /* Location in a file. */ #define TCL_LOCATION_PROC (5) /* Location in a dynamic proc. */ #define TCL_LOCATION_LAST (6) /* Number of values in the enum. */ /* * Structure passed to describe procedure-like "procedures" that are not * procedures (e.g. a lambda) so that their details can be reported correctly * by [info frame]. Contains a sub-structure for each extra field. */ |
| ︙ | ︙ | |||
1521 1522 1523 1524 1525 1526 1527 | /* *---------------------------------------------------------------- * Experimental flag value passed to Tcl_GetRegExpFromObj. Intended for use * only by Expect. It will probably go away in a later release. *---------------------------------------------------------------- */ | | | < | 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | /* *---------------------------------------------------------------- * Experimental flag value passed to Tcl_GetRegExpFromObj. Intended for use * only by Expect. It will probably go away in a later release. *---------------------------------------------------------------- */ #define TCL_REG_BOSONLY 002000 /* Prepend \A to pattern so it only matches at * the beginning of the string. */ /* * These are a thin layer over TclpThreadKeyDataGet and TclpThreadKeyDataSet * when threads are used, or an emulation if there are no threads. These are * really internal and Tcl clients should use Tcl_GetThreadData. */ |
| ︙ | ︙ | |||
1668 1669 1670 1671 1672 1673 1674 |
* because a context is being deleted (e.g.,
* the current coroutine has been deleted). */
} ExecEnv;
#define COR_IS_SUSPENDED(corPtr) \
((corPtr)->stackLevel == NULL)
| < < < < | 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 |
* because a context is being deleted (e.g.,
* the current coroutine has been deleted). */
} ExecEnv;
#define COR_IS_SUSPENDED(corPtr) \
((corPtr)->stackLevel == NULL)
/*
* The definitions for the LiteralTable and LiteralEntry structures. Each
* interpreter contains a LiteralTable. It is used to reduce the storage
* needed for all the Tcl objects that hold the literals of scripts compiled
* by the interpreter. A literal's object is shared by all the ByteCodes that
* refer to the literal. Each distinct literal has one LiteralEntry entry in
* the LiteralTable. A literal table is a specialized hash table that is
|
| ︙ | ︙ | |||
1697 1698 1699 1700 1701 1702 1703 |
/* Points to next entry in this hash bucket or
* NULL if end of chain. */
Tcl_Obj *objPtr; /* Points to Tcl object that holds the
* literal's bytes and length. */
Tcl_Size refCount; /* If in an interpreter's global literal
* table, the number of ByteCode structures
* that share the literal object; the literal
| | | | | | | | 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 |
/* Points to next entry in this hash bucket or
* NULL if end of chain. */
Tcl_Obj *objPtr; /* Points to Tcl object that holds the
* literal's bytes and length. */
Tcl_Size refCount; /* If in an interpreter's global literal
* table, the number of ByteCode structures
* that share the literal object; the literal
* entry can be freed when refCount drops to
* 0. If in a local literal table, TCL_INDEX_NONE. */
Namespace *nsPtr; /* Namespace in which this literal is used. We
* try to avoid sharing literal non-FQ command
* names among different namespaces to reduce
* shimmering. */
} LiteralEntry;
typedef struct LiteralTable {
LiteralEntry **buckets; /* Pointer to bucket array. Each element
* points to first entry in bucket's hash
* chain, or NULL. */
LiteralEntry *staticBuckets[TCL_SMALL_HASH_TABLE];
/* Bucket array used for small tables to avoid
* mallocs and frees. */
TCL_HASH_TYPE numBuckets; /* Total number of buckets allocated at
* **buckets. */
TCL_HASH_TYPE numEntries; /* Total number of entries present in
* table. */
TCL_HASH_TYPE rebuildSize; /* Enlarge table when numEntries gets to be
* this large. */
TCL_HASH_TYPE mask; /* Mask value used in hashing function. */
} LiteralTable;
/*
* The following structure defines for each Tcl interpreter various
* statistics-related information about the bytecode compiler and
* interpreter's operation in that interpreter.
*/
|
| ︙ | ︙ | |||
1766 1767 1768 1769 1770 1771 1772 | /* * Structure used in implementation of those core ensembles which are * partially compiled. Used as an array of these, with a terminating field * whose 'name' is NULL. */ | | | | | 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 |
/*
* Structure used in implementation of those core ensembles which are
* partially compiled. Used as an array of these, with a terminating field
* whose 'name' is NULL.
*/
typedef struct {
const char *name; /* The name of the subcommand. */
Tcl_ObjCmdProc *proc; /* The implementation of the subcommand. */
CompileProc *compileProc; /* The compiler for the subcommand. */
Tcl_ObjCmdProc *nreProc; /* NRE implementation of this command. */
void *clientData; /* Any clientData to give the command. */
int unsafe; /* Whether this command is to be hidden by
* default in a safe interpreter. */
} EnsembleImplMap;
/*
*----------------------------------------------------------------
|
| ︙ | ︙ | |||
1847 1848 1849 1850 1851 1852 1853 |
* instruction sequence. This structure can be
* freed when refCount becomes zero. */
Tcl_Size cmdEpoch; /* Incremented to invalidate any references
* that point to this command when it is
* renamed, deleted, hidden, or exposed. */
CompileProc *compileProc; /* Procedure called to compile command. NULL
* if no compile proc exists for command. */
| | | | < < < > | | | | | | < | > | | | < | | | < < < < < < < < < < < < < | | < | | > > | > > > > > > > | 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 |
* instruction sequence. This structure can be
* freed when refCount becomes zero. */
Tcl_Size cmdEpoch; /* Incremented to invalidate any references
* that point to this command when it is
* renamed, deleted, hidden, or exposed. */
CompileProc *compileProc; /* Procedure called to compile command. NULL
* if no compile proc exists for command. */
Tcl_ObjCmdProc *objProc; /* Object-based command procedure. */
void *objClientData; /* Arbitrary value passed to object proc. */
Tcl_CmdProc *proc; /* String-based command procedure. */
void *clientData; /* Arbitrary value passed to string proc. */
Tcl_CmdDeleteProc *deleteProc;
/* Procedure invoked when deleting command to,
* e.g., free all client data. */
void *deleteData; /* Arbitrary value passed to deleteProc. */
int flags; /* Miscellaneous bits of information about
* command. See below for definitions. */
ImportRef *importRefPtr; /* List of each imported Command created in
* another namespace when this command is
* imported. These imported commands redirect
* invocations back to this command. The list
* is used to remove all those imported
* commands when deleting this "real"
* command. */
CommandTrace *tracePtr; /* First in list of all traces set for this
* command. */
Tcl_ObjCmdProc *nreProc; /* NRE implementation of this command. */
} Command;
/*
* Flag bits for commands.
*
* CMD_DYING - If 1 the command is in the process of
* being deleted (its deleteProc is currently
* executing). Other attempts to delete the
* command should be ignored.
* CMD_TRACE_ACTIVE - If 1 the trace processing is currently
* underway for a rename/delete change. See the
* two flags below for which is currently being
* processed.
* CMD_HAS_EXEC_TRACES - If 1 means that this command has at least one
* execution trace (as opposed to simple
* delete/rename traces) in its tracePtr list.
* CMD_COMPILES_EXPANDED - If 1 this command has a compiler that
* can handle expansion (provided it is not the
* first word).
* TCL_TRACE_RENAME - A rename trace is in progress. Further
* recursive renames will not be traced.
* TCL_TRACE_DELETE - A delete trace is in progress. Further
* recursive deletes will not be traced.
* (these last two flags are defined in tcl.h)
*/
#define CMD_DYING 0x01
#define CMD_TRACE_ACTIVE 0x02
#define CMD_HAS_EXEC_TRACES 0x04
#define CMD_COMPILES_EXPANDED 0x08
#define CMD_REDEF_IN_PROGRESS 0x10
#define CMD_VIA_RESOLVER 0x20
#define CMD_DEAD 0x40
/*
*----------------------------------------------------------------
* Data structures related to name resolution procedures.
*----------------------------------------------------------------
*/
|
| ︙ | ︙ | |||
1952 1953 1954 1955 1956 1957 1958 |
/*
* TIP #268.
* Values for the selection mode, i.e the package require preferences.
*/
enum PkgPreferOptions {
| | < | 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 |
/*
* TIP #268.
* Values for the selection mode, i.e the package require preferences.
*/
enum PkgPreferOptions {
PKG_PREFER_LATEST, PKG_PREFER_STABLE
};
/*
*----------------------------------------------------------------
* This structure shadows the first few fields of the memory cache for the
* allocator defined in tclThreadAlloc.c; it has to be kept in sync with the
* definition there.
|
| ︙ | ︙ | |||
2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 |
Tcl_HashTable *hiddenCmdTablePtr;
/* Hash table used by tclBasic.c to keep track
* of hidden commands on a per-interp
* basis. */
void *interpInfo; /* Information used by tclInterp.c to keep
* track of parent/child interps on a
* per-interp basis. */
void (*optimizer)(void *envPtr);
/*
* Information related to procedures and variables. See tclProc.c and
* tclVar.c for usage.
*/
Tcl_Size numLevels; /* Keeps track of how many nested calls to
* Tcl_Eval are in progress for this
| > > > > > > > > > > > > > | 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 |
Tcl_HashTable *hiddenCmdTablePtr;
/* Hash table used by tclBasic.c to keep track
* of hidden commands on a per-interp
* basis. */
void *interpInfo; /* Information used by tclInterp.c to keep
* track of parent/child interps on a
* per-interp basis. */
#if TCL_MAJOR_VERSION > 8
void (*optimizer)(void *envPtr);
/* Reference to the bytecode optimizer, if one
* is set. */
#else
union {
void (*optimizer)(void *envPtr);
Tcl_HashTable unused2; /* No longer used (was mathFuncTable). The
* unused space in interp was repurposed for
* pluggable bytecode optimizers. The core
* contains one optimizer, which can be
* selectively overridden by extensions. */
} extra;
#endif
/*
* Information related to procedures and variables. See tclProc.c and
* tclVar.c for usage.
*/
Tcl_Size numLevels; /* Keeps track of how many nested calls to
* Tcl_Eval are in progress for this
|
| ︙ | ︙ | |||
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 |
* or NULL if no active traces. */
int returnCode; /* [return -code] parameter. */
CallFrame *rootFramePtr; /* Global frame pointer for this
* interpreter. */
Namespace *lookupNsPtr; /* Namespace to use ONLY on the next
* TCL_EVAL_INVOKE call to Tcl_EvalObjv. */
/*
* Information about packages. Used only in tclPkg.c.
*/
Tcl_HashTable packageTable; /* Describes all of the packages loaded in or
* available to this interpreter. Keys are
* package names, values are (Package *)
| > > > > > > | 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 |
* or NULL if no active traces. */
int returnCode; /* [return -code] parameter. */
CallFrame *rootFramePtr; /* Global frame pointer for this
* interpreter. */
Namespace *lookupNsPtr; /* Namespace to use ONLY on the next
* TCL_EVAL_INVOKE call to Tcl_EvalObjv. */
#if TCL_MAJOR_VERSION < 9
char *appendResultDontUse;
int appendAvlDontUse;
int appendUsedDontUse;
#endif
/*
* Information about packages. Used only in tclPkg.c.
*/
Tcl_HashTable packageTable; /* Describes all of the packages loaded in or
* available to this interpreter. Keys are
* package names, values are (Package *)
|
| ︙ | ︙ | |||
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 |
Tcl_Size cmdCount; /* Total number of times a command procedure
* has been called for this interpreter. */
int evalFlags; /* Flags to control next call to Tcl_Eval.
* Normally zero, but may be set before
* calling Tcl_Eval. See below for valid
* values. */
LiteralTable literalTable; /* Contains LiteralEntry's describing all Tcl
* objects holding literals of scripts
* compiled by the interpreter. Indexed by the
* string representations of literals. Used to
* avoid creating duplicate objects. */
Tcl_Size compileEpoch; /* Holds the current "compilation epoch" for
* this interpreter. This is incremented to
| > > > | 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 |
Tcl_Size cmdCount; /* Total number of times a command procedure
* has been called for this interpreter. */
int evalFlags; /* Flags to control next call to Tcl_Eval.
* Normally zero, but may be set before
* calling Tcl_Eval. See below for valid
* values. */
#if TCL_MAJOR_VERSION < 9
int unused1; /* No longer used (was termOffset) */
#endif
LiteralTable literalTable; /* Contains LiteralEntry's describing all Tcl
* objects holding literals of scripts
* compiled by the interpreter. Indexed by the
* string representations of literals. Used to
* avoid creating duplicate objects. */
Tcl_Size compileEpoch; /* Holds the current "compilation epoch" for
* this interpreter. This is incremented to
|
| ︙ | ︙ | |||
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 |
struct ExecEnv *execEnvPtr; /* Execution environment for Tcl bytecode
* execution. Contains a pointer to the Tcl
* evaluation stack. */
Tcl_Obj *emptyObjPtr; /* Points to an object holding an empty
* string. Returned by Tcl_ObjSetVar2 when
* variable traces change a variable in a
* gross way. */
Tcl_Obj *objResultPtr; /* If the last command returned an object
* result, this points to it. Should not be
* accessed directly; see comment above. */
Tcl_ThreadId threadId; /* ID of thread that owns the interpreter. */
ActiveCommandTrace *activeCmdTracePtr;
/* First in list of active command traces for
| > > > | 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 |
struct ExecEnv *execEnvPtr; /* Execution environment for Tcl bytecode
* execution. Contains a pointer to the Tcl
* evaluation stack. */
Tcl_Obj *emptyObjPtr; /* Points to an object holding an empty
* string. Returned by Tcl_ObjSetVar2 when
* variable traces change a variable in a
* gross way. */
#if TCL_MAJOR_VERSION < 9
char resultSpaceDontUse[TCL_DSTRING_STATIC_SIZE+1];
#endif
Tcl_Obj *objResultPtr; /* If the last command returned an object
* result, this points to it. Should not be
* accessed directly; see comment above. */
Tcl_ThreadId threadId; /* ID of thread that owns the interpreter. */
ActiveCommandTrace *activeCmdTracePtr;
/* First in list of active command traces for
|
| ︙ | ︙ | |||
2157 2158 2159 2160 2161 2162 2163 | Tcl_Size cmdCount; /* Limit for how many commands to execute in * the interpreter. */ LimitHandler *cmdHandlers; /* Handlers to execute when the limit is * reached. */ int cmdGranularity; /* Mod factor used to determine how often to * evaluate the limit check. */ | > | < < < < < | 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 | Tcl_Size cmdCount; /* Limit for how many commands to execute in * the interpreter. */ LimitHandler *cmdHandlers; /* Handlers to execute when the limit is * reached. */ int cmdGranularity; /* Mod factor used to determine how often to * evaluate the limit check. */ Tcl_Time time; /* Time limit for execution within the * interpreter. */ LimitHandler *timeHandlers; /* Handlers to execute when the limit is * reached. */ int timeGranularity; /* Mod factor used to determine how often to * evaluate the limit check. */ Tcl_TimerToken timeEvent; /* Handle for a timer callback that will occur |
| ︙ | ︙ | |||
2219 2220 2221 2222 2223 2224 2225 |
* location information for the current
* command. */
const CmdFrame *invokeCmdFramePtr;
/* Points to the command frame which is the
* invoking context of the bytecode compiler.
* NULL when the byte code compiler is not
* active. */
| | | 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 |
* location information for the current
* command. */
const CmdFrame *invokeCmdFramePtr;
/* Points to the command frame which is the
* invoking context of the bytecode compiler.
* NULL when the byte code compiler is not
* active. */
int invokeWord; /* Index of the word in the command which
* is getting compiled. */
Tcl_HashTable *linePBodyPtr;/* This table remembers for each statically
* defined procedure the location information
* for its body. It is keyed by the address of
* the Proc structure for a procedure. The
* values are "struct CmdFrame*". */
Tcl_HashTable *lineBCPtr; /* This table remembers for each ByteCode
|
| ︙ | ︙ | |||
2286 2287 2288 2289 2290 2291 2292 |
* They are used by the macros defined below.
*/
AllocCache *allocCache; /* Allocator cache for stack frames. */
void *pendingObjDataPtr; /* Pointer to the Cache and PendingObjData
* structs for this interp's thread; see
* tclObj.c and tclThreadAlloc.c */
| | | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 |
* They are used by the macros defined below.
*/
AllocCache *allocCache; /* Allocator cache for stack frames. */
void *pendingObjDataPtr; /* Pointer to the Cache and PendingObjData
* structs for this interp's thread; see
* tclObj.c and tclThreadAlloc.c */
int *asyncReadyPtr; /* Pointer to the asyncReady indicator for
* this interp's thread; see tclAsync.c */
/*
* The pointer to the object system root ekeko. c.f. TIP #257.
*/
void *objectFoundation; /* Pointer to the Foundation structure of the
* object system, which contains things like
* references to key namespaces. See
|
| ︙ | ︙ | |||
2365 2366 2367 2368 2369 2370 2371 |
#define TclUnsetCancelFlags(iPtr) \
(iPtr)->flags &= (~(CANCELED | TCL_CANCEL_UNWIND))
/*
* Macros for splicing into and out of doubly linked lists. They assume
* existence of struct items 'prevPtr' and 'nextPtr'.
*
| | | | < | | | | | < | < | | | | | | | < < | > > > > > | | < < < | | | | < < < > | | | | | | | < | < < < < | < | | | < | | | | | | | > > | | < > | | | | < < | | | | | < | | | < | > > | > > > > > > > > > > | | > | | 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 |
#define TclUnsetCancelFlags(iPtr) \
(iPtr)->flags &= (~(CANCELED | TCL_CANCEL_UNWIND))
/*
* Macros for splicing into and out of doubly linked lists. They assume
* existence of struct items 'prevPtr' and 'nextPtr'.
*
* a = element to add or remove.
* b = list head.
*
* TclSpliceIn adds to the head of the list.
*/
#define TclSpliceIn(a,b) \
(a)->nextPtr = (b); \
if ((b) != NULL) { \
(b)->prevPtr = (a); \
} \
(a)->prevPtr = NULL, (b) = (a);
#define TclSpliceOut(a,b) \
if ((a)->prevPtr != NULL) { \
(a)->prevPtr->nextPtr = (a)->nextPtr; \
} else { \
(b) = (a)->nextPtr; \
} \
if ((a)->nextPtr != NULL) { \
(a)->nextPtr->prevPtr = (a)->prevPtr; \
}
/*
* EvalFlag bits for Interp structures:
*
* TCL_ALLOW_EXCEPTIONS 1 means it's OK for the script to terminate with a
* code other than TCL_OK or TCL_ERROR; 0 means codes
* other than these should be turned into errors.
*/
#define TCL_ALLOW_EXCEPTIONS 0x04
#define TCL_EVAL_FILE 0x02
#define TCL_EVAL_SOURCE_IN_FRAME 0x10
#define TCL_EVAL_NORESOLVE 0x20
#define TCL_EVAL_DISCARD_RESULT 0x40
/*
* Flag bits for Interp structures:
*
* DELETED: Non-zero means the interpreter has been deleted:
* don't process any more commands for it, and destroy
* the structure as soon as all nested invocations of
* Tcl_Eval are done.
* ERR_ALREADY_LOGGED: Non-zero means information has already been logged in
* iPtr->errorInfo for the current Tcl_Eval instance, so
* Tcl_Eval needn't log it (used to implement the "error
* message log" command).
* DONT_COMPILE_CMDS_INLINE: Non-zero means that the bytecode compiler should
* not compile any commands into an inline sequence of
* instructions. This is set 1, for example, when command
* traces are requested.
* RAND_SEED_INITIALIZED: Non-zero means that the randSeed value of the interp
* has not be initialized. This is set 1 when we first
* use the rand() or srand() functions.
* SAFE_INTERP: Non zero means that the current interp is a safe
* interp (i.e. it has only the safe commands installed,
* less privilege than a regular interp).
* INTERP_DEBUG_FRAME: Used for switching on various extra interpreter
* debug/info mechanisms (e.g. info frame eval/uplevel
* tracing) which are performance intensive.
* INTERP_TRACE_IN_PROGRESS: Non-zero means that an interp trace is currently
* active; so no further trace callbacks should be
* invoked.
* INTERP_ALTERNATE_WRONG_ARGS: Used for listing second and subsequent forms
* of the wrong-num-args string in Tcl_WrongNumArgs.
* Makes it append instead of replacing and uses
* different intermediate text.
* CANCELED: Non-zero means that the script in progress should be
* canceled as soon as possible. This can be checked by
* extensions (and the core itself) by calling
* Tcl_Canceled and checking if TCL_ERROR is returned.
* This is a one-shot flag that is reset immediately upon
* being detected; however, if the TCL_CANCEL_UNWIND flag
* is set Tcl_Canceled will continue to report that the
* script in progress has been canceled thereby allowing
* the evaluation stack for the interp to be fully
* unwound.
*/
#define DELETED 1
#define ERR_ALREADY_LOGGED 4
#define INTERP_DEBUG_FRAME 0x10
#define DONT_COMPILE_CMDS_INLINE 0x20
#define RAND_SEED_INITIALIZED 0x40
#define SAFE_INTERP 0x80
#define INTERP_TRACE_IN_PROGRESS 0x200
#define INTERP_ALTERNATE_WRONG_ARGS 0x400
#define ERR_LEGACY_COPY 0x800
#define CANCELED 0x1000
/*
* Maximum number of levels of nesting permitted in Tcl commands (used to
* catch infinite recursion).
*/
#define MAX_NESTING_DEPTH 1000
/*
* The macro below is used to modify a "char" value (e.g. by casting it to an
* unsigned character) so that it can be used safely with macros such as
* isspace.
*/
#define UCHAR(c) ((unsigned char) (c))
/*
* This macro is used to properly align the memory allocated by Tcl, giving
* the same alignment as the native malloc.
*/
#if defined(__APPLE__)
#define TCL_ALLOCALIGN 16
#else
#define TCL_ALLOCALIGN (2*sizeof(void *))
#endif
/*
* TCL_ALIGN is used to determine the offset needed to safely allocate any
* data structure in memory. Given a starting offset or size, it "rounds up"
* or "aligns" the offset to the next aligned (typically 8-byte) boundary so
* that any data structure can be placed at the resulting offset without fear
|
| ︙ | ︙ | |||
2545 2546 2547 2548 2549 2550 2551 |
TCL_TRANSLATE_AUTO, /* Eol == \r, \n and \r\n. */
TCL_TRANSLATE_CR, /* Eol == \r. */
TCL_TRANSLATE_LF, /* Eol == \n. */
TCL_TRANSLATE_CRLF /* Eol == \r\n. */
} TclEolTranslation;
/*
| < < < | > | > | | > > | | > > > | > > > | 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 |
TCL_TRANSLATE_AUTO, /* Eol == \r, \n and \r\n. */
TCL_TRANSLATE_CR, /* Eol == \r. */
TCL_TRANSLATE_LF, /* Eol == \n. */
TCL_TRANSLATE_CRLF /* Eol == \r\n. */
} TclEolTranslation;
/*
* Flags for TclInvoke:
*
* TCL_INVOKE_HIDDEN Invoke a hidden command; if not set, invokes
* an exposed command.
* TCL_INVOKE_NO_UNKNOWN If set, "unknown" is not invoked if the
* command to be invoked is not found. Only has
* an effect if invoking an exposed command,
* i.e. if TCL_INVOKE_HIDDEN is not also set.
* TCL_INVOKE_NO_TRACEBACK Does not record traceback information if the
* invoked command returns an error. Used if the
* caller plans on recording its own traceback
* information.
*/
#define TCL_INVOKE_HIDDEN (1<<0)
#define TCL_INVOKE_NO_UNKNOWN (1<<1)
#define TCL_INVOKE_NO_TRACEBACK (1<<2)
/*
* ListStore --
*
* A Tcl list's internal representation is defined through three structures.
*
* A ListStore struct is a structure that includes a variable size array that
|
| ︙ | ︙ | |||
2590 2591 2592 2593 2594 2595 2596 |
Tcl_Size numUsed; /* Number of slots in use (starting firstUsed) */
Tcl_Size numAllocated; /* Total number of slots[] array slots. */
size_t refCount; /* Number of references to this instance. */
int flags; /* LISTSTORE_* flags */
Tcl_Obj *slots[TCLFLEXARRAY];
/* Variable size array. Grown as needed */
} ListStore;
| | | < | 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 |
Tcl_Size numUsed; /* Number of slots in use (starting firstUsed) */
Tcl_Size numAllocated; /* Total number of slots[] array slots. */
size_t refCount; /* Number of references to this instance. */
int flags; /* LISTSTORE_* flags */
Tcl_Obj *slots[TCLFLEXARRAY];
/* Variable size array. Grown as needed */
} ListStore;
#define LISTSTORE_CANONICAL 0x1 /* All Tcl_Obj's referencing this
* store have their string representation
* derived from the list representation */
/* Max number of elements that can be contained in a list */
#define LIST_MAX \
((Tcl_Size)(((size_t)TCL_SIZE_MAX - offsetof(ListStore, slots)) \
/ sizeof(Tcl_Obj *)))
/* Memory size needed for a ListStore to hold numSlots_ elements */
#define LIST_SIZE(numSlots_) \
|
| ︙ | ︙ | |||
2758 2759 2760 2761 2762 2763 2764 | ? ListObjIsCanonical((listObj_)) \ : 0) /* * Modes for collecting (or not) in the implementations of TclNRForeachCmd, * TclNRLmapCmd and their compilations. */ | | | | < < > > > > > > > > > | 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 |
? ListObjIsCanonical((listObj_)) \
: 0)
/*
* Modes for collecting (or not) in the implementations of TclNRForeachCmd,
* TclNRLmapCmd and their compilations.
*/
#define TCL_EACH_KEEP_NONE 0 /* Discard iteration result like [foreach] */
#define TCL_EACH_COLLECT 1 /* Collect iteration result like [lmap] */
/*
* Macros providing a faster path to booleans and integers:
* Tcl_GetBooleanFromObj, Tcl_GetLongFromObj, Tcl_GetIntFromObj
* and Tcl_GetIntForIndex.
*
* WARNING: these macros eval their args more than once.
*/
#if TCL_MAJOR_VERSION > 8
#define TclGetBooleanFromObj(interp, objPtr, intPtr) \
((TclHasInternalRep((objPtr), &tclIntType) \
|| TclHasInternalRep((objPtr), &tclBooleanType)) \
? (*(intPtr) = ((objPtr)->internalRep.wideValue!=0), TCL_OK) \
: Tcl_GetBooleanFromObj((interp), (objPtr), (intPtr)))
#else
#define TclGetBooleanFromObj(interp, objPtr, intPtr) \
((TclHasInternalRep((objPtr), &tclIntType)) \
? (*(intPtr) = ((objPtr)->internalRep.wideValue!=0), TCL_OK) \
: (TclHasInternalRep((objPtr), &tclBooleanType)) \
? (*(intPtr) = ((objPtr)->internalRep.longValue!=0), TCL_OK) \
: Tcl_GetBooleanFromObj((interp), (objPtr), (intPtr)))
#endif
#ifdef TCL_WIDE_INT_IS_LONG
#define TclGetLongFromObj(interp, objPtr, longPtr) \
((TclHasInternalRep((objPtr), &tclIntType)) \
? ((*(longPtr) = (objPtr)->internalRep.wideValue), TCL_OK) \
: Tcl_GetLongFromObj((interp), (objPtr), (longPtr)))
#else
|
| ︙ | ︙ | |||
2820 2821 2822 2823 2824 2825 2826 |
#define TclGetWideIntFromObj(interp, objPtr, wideIntPtr) \
((TclHasInternalRep((objPtr), &tclIntType)) \
? (*(wideIntPtr) = ((objPtr)->internalRep.wideValue), TCL_OK) \
: Tcl_GetWideIntFromObj((interp), (objPtr), (wideIntPtr)))
/*
* Flag values for TclTraceDictPath().
| < < > | | > | | | > | | < | | > > > > | | | < > > | 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 |
#define TclGetWideIntFromObj(interp, objPtr, wideIntPtr) \
((TclHasInternalRep((objPtr), &tclIntType)) \
? (*(wideIntPtr) = ((objPtr)->internalRep.wideValue), TCL_OK) \
: Tcl_GetWideIntFromObj((interp), (objPtr), (wideIntPtr)))
/*
* Flag values for TclTraceDictPath().
*
* DICT_PATH_READ indicates that all entries on the path must exist but no
* updates will be needed.
*
* DICT_PATH_UPDATE indicates that we are going to be doing an update at the
* tip of the path, so duplication of shared objects should be done along the
* way.
*
* DICT_PATH_EXISTS indicates that we are performing an existence test and a
* lookup failure should therefore not be an error. If (and only if) this flag
* is set, TclTraceDictPath() will return the special value
* DICT_PATH_NON_EXISTENT if the path is not traceable.
*
* DICT_PATH_CREATE (which also requires the DICT_PATH_UPDATE bit to be set)
* indicates that we are to create non-existent dictionaries on the path.
*/
#define DICT_PATH_READ 0
#define DICT_PATH_UPDATE 1
#define DICT_PATH_EXISTS 2
#define DICT_PATH_CREATE 5
#define DICT_PATH_NON_EXISTENT ((Tcl_Obj *) (void *) 1)
/*
*----------------------------------------------------------------
* Data structures related to the filesystem internals
*----------------------------------------------------------------
|
| ︙ | ︙ | |||
2859 2860 2861 2862 2863 2864 2865 | #define TCL_FILESYSTEM_VERSION_2 ((Tcl_FSVersion) 0x2) typedef void *(TclFSGetCwdProc2)(void *clientData); typedef int (Tcl_FSLoadFileProc2) (Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr, int flags); | < < < < < < < < < < < < < < < < < < | 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 | #define TCL_FILESYSTEM_VERSION_2 ((Tcl_FSVersion) 0x2) typedef void *(TclFSGetCwdProc2)(void *clientData); typedef int (Tcl_FSLoadFileProc2) (Tcl_Interp *interp, Tcl_Obj *pathPtr, Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr, int flags); /* * The following types are used for getting and storing platform-specific file * attributes in tclFCmd.c and the various platform-versions of that file. * This is done to have as much common code as possible in the file attributes * code. For more information about the callbacks, see TclFileAttrsCmd in * tclFCmd.c. */ |
| ︙ | ︙ | |||
2927 2928 2929 2930 2931 2932 2933 | /* *---------------------------------------------------------------- * Data structures for process-global values. *---------------------------------------------------------------- */ typedef void (TclInitProcessGlobalValueProc)(char **valuePtr, | | | 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 | /* *---------------------------------------------------------------- * Data structures for process-global values. *---------------------------------------------------------------- */ typedef void (TclInitProcessGlobalValueProc)(char **valuePtr, TCL_HASH_TYPE *lengthPtr, Tcl_Encoding *encodingPtr); #ifdef _WIN32 /* On Windows, all Unicode (except surrogates) are valid. */ # define TCLFSENCODING tclUtf8Encoding #else /* On Non-Windows, use the system encoding for validation checks. */ |
| ︙ | ︙ | |||
2949 2950 2951 2952 2953 2954 2955 |
* mutex control. Each ProcessGlobalValue struct should be a static variable in
* some file.
*/
typedef struct ProcessGlobalValue {
Tcl_Size epoch; /* Epoch counter to detect changes in the
* global value. */
| | | | > > | | > | | | > | > | | < < | < | 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 |
* mutex control. Each ProcessGlobalValue struct should be a static variable in
* some file.
*/
typedef struct ProcessGlobalValue {
Tcl_Size epoch; /* Epoch counter to detect changes in the
* global value. */
TCL_HASH_TYPE numBytes; /* Length of the global string. */
char *value; /* The global string value. */
Tcl_Encoding encoding; /* system encoding when global string was
* initialized. */
TclInitProcessGlobalValueProc *proc;
/* A procedure to initialize the global string
* copy when a "get" request comes in before
* any "set" request has been received. */
Tcl_Mutex mutex; /* Enforce orderly access from multiple
* threads. */
Tcl_ThreadDataKey key; /* Key for per-thread data holding the
* (Tcl_Obj) copy for each thread. */
} ProcessGlobalValue;
/*
*----------------------------------------------------------------------
* Flags for TclParseNumber
*----------------------------------------------------------------------
*/
#define TCL_PARSE_DECIMAL_ONLY 1
/* Leading zero doesn't denote octal or
* hex. */
#define TCL_PARSE_OCTAL_ONLY 2
/* Parse octal even without prefix. */
#define TCL_PARSE_HEXADECIMAL_ONLY 4
/* Parse hexadecimal even without prefix. */
#define TCL_PARSE_INTEGER_ONLY 8
/* Disable floating point parsing. */
#define TCL_PARSE_SCAN_PREFIXES 16
/* Use [scan] rules dealing with 0?
* prefixes. */
#define TCL_PARSE_NO_WHITESPACE 32
/* Reject leading/trailing whitespace. */
#define TCL_PARSE_BINARY_ONLY 64
/* Parse binary even without prefix. */
#define TCL_PARSE_NO_UNDERSCORE 128
/* Reject underscore digit separator */
/*
*----------------------------------------------------------------------
* Internal convenience macros for manipulating encoding flags. See
* TCL_ENCODING_PROFILE_* in tcl.h
*----------------------------------------------------------------------
*/
#define ENCODING_PROFILE_MASK 0xFF000000
#define ENCODING_PROFILE_GET(flags_) \
((flags_) & ENCODING_PROFILE_MASK)
#define ENCODING_PROFILE_SET(flags_, profile_) \
do { \
(flags_) &= ~ENCODING_PROFILE_MASK; \
(flags_) |= ((profile_) & ENCODING_PROFILE_MASK); \
} while (0)
|
| ︙ | ︙ | |||
3126 3127 3128 3129 3130 3131 3132 | MODULE_SCOPE Tcl_Encoding tclUtf8Encoding; MODULE_SCOPE int TclEncodingProfileNameToId(Tcl_Interp *interp, const char *profileName, int *profilePtr); MODULE_SCOPE const char *TclEncodingProfileIdToName(Tcl_Interp *interp, int profileId); MODULE_SCOPE void TclGetEncodingProfiles(Tcl_Interp *interp); | > > > > > > | > > > | > | > > | 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 |
MODULE_SCOPE Tcl_Encoding tclUtf8Encoding;
MODULE_SCOPE int TclEncodingProfileNameToId(Tcl_Interp *interp,
const char *profileName,
int *profilePtr);
MODULE_SCOPE const char *TclEncodingProfileIdToName(Tcl_Interp *interp,
int profileId);
MODULE_SCOPE void TclGetEncodingProfiles(Tcl_Interp *interp);
/* TIP 716 - MODULE_SCOPE for 9.0.2. Will be public in 9.1 */
#ifdef _WIN32
MODULE_SCOPE const char *Tcl_GetEncodingNameForUser(Tcl_DString *bufPtr);
#else
static inline const char *
Tcl_GetEncodingNameForUser(Tcl_DString *bufPtr)
{
return Tcl_GetEncodingNameFromEnvironment(bufPtr);
}
#endif
/*
* TIP #233 (Virtualized Time)
* Data for the time hooks, if any.
*/
MODULE_SCOPE Tcl_GetTimeProc *tclGetTimeProcPtr;
MODULE_SCOPE Tcl_ScaleTimeProc *tclScaleTimeProcPtr;
MODULE_SCOPE void *tclTimeClientData;
/*
* Variables denoting the Tcl object types defined in the core.
*/
MODULE_SCOPE const Tcl_ObjType tclBignumType;
MODULE_SCOPE const Tcl_ObjType tclBooleanType;
|
| ︙ | ︙ | |||
3161 3162 3163 3164 3165 3166 3167 | */ MODULE_SCOPE const Tcl_HashKeyType tclArrayHashKeyType; MODULE_SCOPE const Tcl_HashKeyType tclOneWordHashKeyType; MODULE_SCOPE const Tcl_HashKeyType tclStringHashKeyType; MODULE_SCOPE const Tcl_HashKeyType tclObjHashKeyType; | < < < < < < < < < < < < < < < < < < < < < < < < | 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 | */ MODULE_SCOPE const Tcl_HashKeyType tclArrayHashKeyType; MODULE_SCOPE const Tcl_HashKeyType tclOneWordHashKeyType; MODULE_SCOPE const Tcl_HashKeyType tclStringHashKeyType; MODULE_SCOPE const Tcl_HashKeyType tclObjHashKeyType; /* * The head of the list of free Tcl objects, and the total number of Tcl * objects ever allocated and freed. */ MODULE_SCOPE Tcl_Obj * tclFreeObjList; |
| ︙ | ︙ | |||
3208 3209 3210 3211 3212 3213 3214 |
* the value of an empty string representation for an object. This value is
* shared by all new objects allocated by Tcl_NewObj.
*/
MODULE_SCOPE char tclEmptyString;
enum CheckEmptyStringResult {
| | < < | | | | | | | | | < | | | | | < | | | | | | | < | 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 |
* the value of an empty string representation for an object. This value is
* shared by all new objects allocated by Tcl_NewObj.
*/
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,
* introduced by/for NRE.
*----------------------------------------------------------------
*/
MODULE_SCOPE Tcl_ObjCmdProc TclNRApplyObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNREvalObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRCatchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRExprObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRForObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRForeachCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRIfObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRLmapCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRPackageObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSourceObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSubstObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRSwitchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRTryObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRUplevelObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRWhileObjCmd;
MODULE_SCOPE Tcl_NRPostProc TclNRForIterCallback;
MODULE_SCOPE Tcl_NRPostProc TclNRCoroutineActivateCallback;
MODULE_SCOPE Tcl_ObjCmdProc TclNRTailcallObjCmd;
MODULE_SCOPE Tcl_NRPostProc TclNRTailcallEval;
MODULE_SCOPE Tcl_ObjCmdProc TclNRCoroutineObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldmObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRYieldToObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRInvoke;
MODULE_SCOPE Tcl_NRPostProc TclNRReleaseValues;
MODULE_SCOPE void TclSetTailcall(Tcl_Interp *interp,
Tcl_Obj *tailcallPtr);
MODULE_SCOPE void TclPushTailcallPoint(Tcl_Interp *interp);
/* These two can be considered for the public api */
|
| ︙ | ︙ | |||
3280 3281 3282 3283 3284 3285 3286 |
Tcl_Size word; /* Index of the body script in the command */
} ForIterData;
/* TIP #357 - Structure doing the bookkeeping of handles for Tcl_LoadFile
* and Tcl_FindSymbol. This structure corresponds to an opaque
* typedef in tcl.h */
| | | | | | | | | | < < < < < < < < < < < < < > | | | | | | | | | | | | | | 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 |
Tcl_Size word; /* Index of the body script in the command */
} ForIterData;
/* TIP #357 - Structure doing the bookkeeping of handles for Tcl_LoadFile
* and Tcl_FindSymbol. This structure corresponds to an opaque
* typedef in tcl.h */
typedef void* TclFindSymbolProc(Tcl_Interp* interp, Tcl_LoadHandle loadHandle,
const char* symbol);
struct Tcl_LoadHandle_ {
void *clientData; /* Client data is the load handle in the
* native filesystem if a module was loaded
* there, or an opaque pointer to a structure
* for further bookkeeping on load-from-VFS
* and load-from-memory */
TclFindSymbolProc* findSymbolProcPtr;
/* Procedure that resolves symbols in a
* loaded module */
Tcl_FSUnloadFileProc* unloadFileProcPtr;
/* Procedure that unloads a loaded module */
};
/* Flags for conversion of doubles to digit strings */
#define TCL_DD_E_FORMAT 0x2 /* Use a fixed-length string of digits,
* suitable for E format*/
#define TCL_DD_F_FORMAT 0x3 /* Use a fixed number of digits after the
* decimal point, suitable for F format */
#define TCL_DD_SHORTEST 0x4 /* Use the shortest possible string */
#define TCL_DD_NO_QUICK 0x8 /* Debug flag: forbid quick FP conversion */
#define TCL_DD_CONVERSION_TYPE_MASK 0x3
/* Mask to isolate the conversion type */
/*
*----------------------------------------------------------------
* Procedures shared among Tcl modules but not used by the outside world:
*----------------------------------------------------------------
*/
#if TCL_MAJOR_VERSION > 8
MODULE_SCOPE void TclAdvanceContinuations(Tcl_Size *line, Tcl_Size **next,
int loc);
MODULE_SCOPE void TclAdvanceLines(Tcl_Size *line, const char *start,
const char *end);
MODULE_SCOPE int TclAliasCreate(Tcl_Interp *interp,
Tcl_Interp *childInterp, Tcl_Interp *parentInterp,
Tcl_Obj *namePtr, Tcl_Obj *targetPtr, Tcl_Size objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE void TclAppendBytesToByteArray(Tcl_Obj *objPtr,
const unsigned char *bytes, Tcl_Size len);
MODULE_SCOPE void TclAppendUtfToUtf(Tcl_Obj *objPtr,
const char *bytes, Tcl_Size numBytes);
MODULE_SCOPE void TclArgumentEnter(Tcl_Interp *interp,
Tcl_Obj *objv[], Tcl_Size objc, CmdFrame *cf);
MODULE_SCOPE void TclArgumentRelease(Tcl_Interp *interp,
Tcl_Obj *objv[], Tcl_Size objc);
MODULE_SCOPE void TclArgumentBCEnter(Tcl_Interp *interp,
Tcl_Obj *objv[], Tcl_Size objc,
void *codePtr, CmdFrame *cfPtr, Tcl_Size cmd,
Tcl_Size pc);
MODULE_SCOPE void TclArgumentBCRelease(Tcl_Interp *interp,
CmdFrame *cfPtr);
MODULE_SCOPE void TclArgumentGet(Tcl_Interp *interp, Tcl_Obj *obj,
CmdFrame **cfPtrPtr, int *wordPtr);
MODULE_SCOPE int TclAsyncNotifier(int sigNumber, Tcl_ThreadId threadId,
void *clientData, int *flagPtr, int value);
MODULE_SCOPE void TclAsyncMarkFromNotifier(void);
MODULE_SCOPE double TclBignumToDouble(const void *bignum);
MODULE_SCOPE int TclByteArrayMatch(const unsigned char *string,
Tcl_Size strLen, const unsigned char *pattern,
Tcl_Size ptnLen, int flags);
MODULE_SCOPE double TclCeil(const void *a);
MODULE_SCOPE void TclChannelPreserve(Tcl_Channel chan);
MODULE_SCOPE void TclChannelRelease(Tcl_Channel chan);
MODULE_SCOPE int TclChannelGetBlockingMode(Tcl_Channel chan);
MODULE_SCOPE int TclCheckArrayTraces(Tcl_Interp *interp, Var *varPtr,
Var *arrayPtr, Tcl_Obj *name, int index);
MODULE_SCOPE int TclCheckEmptyString(Tcl_Obj *objPtr);
MODULE_SCOPE int TclChanCaughtErrorBypass(Tcl_Interp *interp,
Tcl_Channel chan);
MODULE_SCOPE Tcl_ObjCmdProc TclChannelNamesCmd;
MODULE_SCOPE int TclChanIsBinary(Tcl_Channel chan);
MODULE_SCOPE Tcl_NRPostProc TclClearRootEnsemble;
MODULE_SCOPE int TclCompareTwoNumbers(Tcl_Obj *valuePtr,
Tcl_Obj *value2Ptr);
MODULE_SCOPE ContLineLoc *TclContinuationsEnter(Tcl_Obj *objPtr, Tcl_Size num,
Tcl_Size *loc);
MODULE_SCOPE void TclContinuationsEnterDerived(Tcl_Obj *objPtr,
|
| ︙ | ︙ | |||
3389 3390 3391 3392 3393 3394 3395 | MODULE_SCOPE int TclCopyNamespaceVariables(Tcl_Interp *interp, Namespace *originNs, Namespace *targetNs); MODULE_SCOPE int TclCreateConstantInNS(Tcl_Interp *interp, Namespace *nsPtr, Tcl_Obj *nameObj, Tcl_Obj *valueObj); MODULE_SCOPE Tcl_Command TclCreateObjCommandInNs(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *nsPtr, | | | 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 | MODULE_SCOPE int TclCopyNamespaceVariables(Tcl_Interp *interp, Namespace *originNs, Namespace *targetNs); MODULE_SCOPE int TclCreateConstantInNS(Tcl_Interp *interp, Namespace *nsPtr, Tcl_Obj *nameObj, Tcl_Obj *valueObj); MODULE_SCOPE Tcl_Command TclCreateObjCommandInNs(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *nsPtr, Tcl_ObjCmdProc *proc, void *clientData, Tcl_CmdDeleteProc *deleteProc); MODULE_SCOPE Tcl_Command TclCreateEnsembleInNs(Tcl_Interp *interp, const char *name, Tcl_Namespace *nameNamespacePtr, Tcl_Namespace *ensembleNamespacePtr, int flags); MODULE_SCOPE void TclDeleteNamespaceVars(Namespace *nsPtr); MODULE_SCOPE void TclDeleteNamespaceChildren(Namespace *nsPtr); MODULE_SCOPE Tcl_Size TclDictGetSize(Tcl_Obj *dictPtr); |
| ︙ | ︙ | |||
3412 3413 3414 3415 3416 3417 3418 | const char *key, Tcl_Obj *valuePtr); MODULE_SCOPE int TclDictPutString(Tcl_Interp *interp, Tcl_Obj *dictPtr, const char *key, const char *value); MODULE_SCOPE int TclDictRemove(Tcl_Interp *interp, Tcl_Obj *dictPtr, const char *key); /* TIP #280 - Modified token based evaluation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, | | | | | | | | | | | | | | 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 | const char *key, Tcl_Obj *valuePtr); MODULE_SCOPE int TclDictPutString(Tcl_Interp *interp, Tcl_Obj *dictPtr, const char *key, const char *value); MODULE_SCOPE int TclDictRemove(Tcl_Interp *interp, Tcl_Obj *dictPtr, const char *key); /* TIP #280 - Modified token based evaluation, with line information. */ MODULE_SCOPE int TclEvalEx(Tcl_Interp *interp, const char *script, Tcl_Size numBytes, int flags, Tcl_Size line, Tcl_Size *clNextOuter, const char *outerScript); MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileDeleteCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileLinkCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileMakeDirsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileReadLinkCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTempDirCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileHomeCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTildeExpandCmd; MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc, void *clientData); MODULE_SCOPE void TclDeleteLateExitHandler(Tcl_ExitProc *proc, void *clientData); MODULE_SCOPE char * TclDStringAppendObj(Tcl_DString *dsPtr, Tcl_Obj *objPtr); MODULE_SCOPE char * TclDStringAppendDString(Tcl_DString *dsPtr, |
| ︙ | ︙ | |||
3467 3468 3469 3470 3471 3472 3473 | MODULE_SCOPE void TclFinalizeThreadObjects(void); MODULE_SCOPE double TclFloor(const void *a); MODULE_SCOPE void TclFormatNaN(double value, char *buffer); MODULE_SCOPE int TclFormatDouble(char *buffer, size_t size, const char *format, double value); MODULE_SCOPE int TclFSFileAttrIndex(Tcl_Obj *pathPtr, const char *attributeName, int *indexPtr); | < < | < | | < | | | | | | | | < | | | > | | | | | | | < < < < < < | | | | | | | 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 | MODULE_SCOPE void TclFinalizeThreadObjects(void); MODULE_SCOPE double TclFloor(const void *a); MODULE_SCOPE void TclFormatNaN(double value, char *buffer); MODULE_SCOPE int TclFormatDouble(char *buffer, size_t size, const char *format, double value); MODULE_SCOPE int TclFSFileAttrIndex(Tcl_Obj *pathPtr, const char *attributeName, int *indexPtr); MODULE_SCOPE Tcl_Obj * TclFSJoinPathHelper(Tcl_Obj *pathPtr, Tcl_Size objc, Tcl_Obj *const objv[], int forceRelative); MODULE_SCOPE Tcl_Command TclNRCreateCommandInNs(Tcl_Interp *interp, const char *cmdName, Tcl_Namespace *nsPtr, Tcl_ObjCmdProc *proc, Tcl_ObjCmdProc *nreProc, void *clientData, Tcl_CmdDeleteProc *deleteProc); MODULE_SCOPE int TclNREvalFile(Tcl_Interp *interp, Tcl_Obj *pathPtr, const char *encodingName); MODULE_SCOPE int * TclGetAsyncReadyPtr(void); MODULE_SCOPE Tcl_Obj * TclGetBgErrorHandler(Tcl_Interp *interp); MODULE_SCOPE int TclGetChannelFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Channel *chanPtr, int *modePtr, int flags); MODULE_SCOPE CmdFrame * TclGetCmdFrameForProcedure(Proc *procPtr); MODULE_SCOPE int TclGetCompletionCodeFromObj(Tcl_Interp *interp, Tcl_Obj *value, int *code); MODULE_SCOPE Proc * TclGetLambdaFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj **nsObjPtrPtr); MODULE_SCOPE Tcl_Obj * TclGetProcessGlobalValue(ProcessGlobalValue *pgvPtr); MODULE_SCOPE Tcl_Obj * TclGetSourceFromFrame(CmdFrame *cfPtr, Tcl_Size objc, Tcl_Obj *const objv[]); MODULE_SCOPE char * TclGetStringStorage(Tcl_Obj *objPtr, Tcl_Size *sizePtr); MODULE_SCOPE int TclGetLoadedLibraries(Tcl_Interp *interp, const char *targetName, const char *prefix); MODULE_SCOPE int TclGetWideBitsFromObj(Tcl_Interp *, Tcl_Obj *, Tcl_WideInt *); MODULE_SCOPE int TclCompareStringKeys(void *keyPtr, Tcl_HashEntry *hPtr); MODULE_SCOPE size_t TclHashStringKey(Tcl_HashTable *tablePtr, void *keyPtr); MODULE_SCOPE int TclIncrObj(Tcl_Interp *interp, Tcl_Obj *valuePtr, Tcl_Obj *incrPtr); MODULE_SCOPE Tcl_Obj * TclIncrObjVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr, int flags); MODULE_SCOPE Tcl_ObjCmdProc TclInfoExistsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInfoCoroutineCmd; MODULE_SCOPE Tcl_Obj * TclInfoFrame(Tcl_Interp *interp, CmdFrame *framePtr); MODULE_SCOPE Tcl_ObjCmdProc TclInfoGlobalsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInfoLocalsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInfoVarsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInfoConstsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInfoConstantCmd; MODULE_SCOPE void TclInitAlloc(void); MODULE_SCOPE void TclInitDbCkalloc(void); MODULE_SCOPE void TclInitDoubleConversion(void); MODULE_SCOPE void TclInitEmbeddedConfigurationInformation( Tcl_Interp *interp); MODULE_SCOPE void TclInitEncodingSubsystem(void); MODULE_SCOPE void TclInitIOSubsystem(void); MODULE_SCOPE void TclInitLimitSupport(Tcl_Interp *interp); MODULE_SCOPE void TclInitNamespaceSubsystem(void); MODULE_SCOPE void TclInitNotifier(void); MODULE_SCOPE void TclInitObjSubsystem(void); MODULE_SCOPE int TclInterpReady(Tcl_Interp *interp); MODULE_SCOPE int TclIsBareword(int byte); MODULE_SCOPE Tcl_Obj * TclJoinPath(Tcl_Size elements, Tcl_Obj * const objv[], int forceRelative); MODULE_SCOPE Tcl_Obj * TclGetHomeDirObj(Tcl_Interp *interp, const char *user); MODULE_SCOPE Tcl_Obj * TclResolveTildePath(Tcl_Interp *interp, Tcl_Obj *pathObj); MODULE_SCOPE Tcl_Obj * TclResolveTildePathList(Tcl_Obj *pathsObj); MODULE_SCOPE int TclJoinThread(Tcl_ThreadId id, int *result); MODULE_SCOPE void TclLimitRemoveAllHandlers(Tcl_Interp *interp); MODULE_SCOPE Tcl_Obj * TclLindexList(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *argPtr); MODULE_SCOPE Tcl_Obj * TclLindexFlat(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size indexCount, Tcl_Obj *const indexArray[]); MODULE_SCOPE Tcl_Obj * TclListObjGetElement(Tcl_Obj *listObj, Tcl_Size index); /* TIP #280 */ MODULE_SCOPE void TclListLines(Tcl_Obj *listObj, Tcl_Size line, Tcl_Size n, Tcl_Size *lines, Tcl_Obj *const *elems); MODULE_SCOPE Tcl_Obj * TclListObjCopy(Tcl_Interp *interp, Tcl_Obj *listPtr); MODULE_SCOPE int TclListObjAppendElements(Tcl_Interp *interp, Tcl_Obj *toObj, Tcl_Size elemCount, Tcl_Obj *const elemObjv[]); MODULE_SCOPE int TclListObjInsertIfAbsent(Tcl_Interp *interp, Tcl_Obj *toObj, Tcl_Obj *elem, Tcl_Size index); MODULE_SCOPE Tcl_Obj * TclListObjRange(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size fromIdx, Tcl_Size toIdx); MODULE_SCOPE Tcl_Obj * TclLsetList(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *indexPtr, Tcl_Obj *valuePtr); MODULE_SCOPE Tcl_Obj * TclLsetFlat(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size indexCount, Tcl_Obj *const indexArray[], Tcl_Obj *valuePtr); MODULE_SCOPE Tcl_Command TclMakeEnsemble(Tcl_Interp *interp, const char *name, const EnsembleImplMap map[]); MODULE_SCOPE Tcl_Size TclMaxListLength(const char *bytes, Tcl_Size numBytes, const char **endPtr); MODULE_SCOPE int TclMergeReturnOptions(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], Tcl_Obj **optionsPtrPtr, int *codePtr, int *levelPtr); MODULE_SCOPE Tcl_Obj * TclNoErrorStack(Tcl_Interp *interp, Tcl_Obj *options); MODULE_SCOPE int TclNokia770Doubles(void); MODULE_SCOPE void TclNsDecrRefCount(Namespace *nsPtr); MODULE_SCOPE int TclNamespaceDeleted(Namespace *nsPtr); MODULE_SCOPE void TclObjVarErrMsg(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, const char *operation, const char *reason, int index); MODULE_SCOPE int TclObjInvokeNamespace(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], Tcl_Namespace *nsPtr, int flags); MODULE_SCOPE int TclObjUnsetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags); MODULE_SCOPE int TclParseBackslash(const char *src, Tcl_Size numBytes, Tcl_Size *readPtr, char *dst); MODULE_SCOPE int TclParseNumber(Tcl_Interp *interp, Tcl_Obj *objPtr, const char *expected, const char *bytes, Tcl_Size numBytes, const char **endPtrPtr, int flags); MODULE_SCOPE void TclParseInit(Tcl_Interp *interp, const char *string, Tcl_Size numBytes, Tcl_Parse *parsePtr); MODULE_SCOPE Tcl_Size TclParseAllWhiteSpace(const char *src, Tcl_Size numBytes); MODULE_SCOPE int TclProcessReturn(Tcl_Interp *interp, int code, int level, Tcl_Obj *returnOpts); MODULE_SCOPE void TclUndoRefCount(Tcl_Obj *objPtr); MODULE_SCOPE int TclpObjLstat(Tcl_Obj *pathPtr, Tcl_StatBuf *buf); MODULE_SCOPE Tcl_Obj *TclpTempFileName(void); MODULE_SCOPE Tcl_Obj *TclpTempFileNameForLibrary(Tcl_Interp *interp, Tcl_Obj *pathPtr); MODULE_SCOPE Tcl_Obj *TclNewArithSeriesObj(Tcl_Interp *interp, int useDoubles, Tcl_Obj *startObj, Tcl_Obj *endObj, Tcl_Obj *stepObj, Tcl_Obj *lenObj); MODULE_SCOPE Tcl_Obj *TclNewFSPathObj(Tcl_Obj *dirPtr, const char *addStrRep, Tcl_Size len); MODULE_SCOPE Tcl_Obj *TclNewNamespaceObj(Tcl_Namespace *namespacePtr); MODULE_SCOPE void TclpAlertNotifier(void *clientData); MODULE_SCOPE void * TclpNotifierData(void); MODULE_SCOPE void TclpServiceModeHook(int mode); MODULE_SCOPE void TclpSetTimer(const Tcl_Time *timePtr); MODULE_SCOPE int TclpWaitForEvent(const Tcl_Time *timePtr); MODULE_SCOPE void TclpCreateFileHandler(int fd, int mask, Tcl_FileProc *proc, void *clientData); MODULE_SCOPE int TclpDeleteFile(const void *path); MODULE_SCOPE void TclpDeleteFileHandler(int fd); MODULE_SCOPE void TclpFinalizeCondition(Tcl_Condition *condPtr); MODULE_SCOPE void TclpFinalizeMutex(Tcl_Mutex *mutexPtr); MODULE_SCOPE void TclpFinalizeNotifier(void *clientData); |
| ︙ | ︙ | |||
3627 3628 3629 3630 3631 3632 3633 | struct addrinfo; /* forward declaration, needed for TclCreateSocketAddress */ MODULE_SCOPE int TclCreateSocketAddress(Tcl_Interp *interp, struct addrinfo **addrlist, const char *host, int port, int willBind, const char **errorMsgPtr); MODULE_SCOPE int TclpThreadCreate(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, void *clientData, | | | | 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 | struct addrinfo; /* forward declaration, needed for TclCreateSocketAddress */ MODULE_SCOPE int TclCreateSocketAddress(Tcl_Interp *interp, struct addrinfo **addrlist, const char *host, int port, int willBind, const char **errorMsgPtr); MODULE_SCOPE int TclpThreadCreate(Tcl_ThreadId *idPtr, Tcl_ThreadCreateProc *proc, void *clientData, TCL_HASH_TYPE stackSize, int flags); MODULE_SCOPE Tcl_Size TclpFindVariable(const char *name, Tcl_Size *lengthPtr); MODULE_SCOPE void TclpInitLibraryPath(char **valuePtr, TCL_HASH_TYPE *lengthPtr, Tcl_Encoding *encodingPtr); MODULE_SCOPE void TclpInitLock(void); MODULE_SCOPE void * TclpInitNotifier(void); MODULE_SCOPE void TclpInitPlatform(void); MODULE_SCOPE void TclpInitUnlock(void); MODULE_SCOPE Tcl_Obj * TclpObjListVolumes(void); MODULE_SCOPE void TclpGlobalLock(void); MODULE_SCOPE void TclpGlobalUnlock(void); |
| ︙ | ︙ | |||
3694 3695 3696 3697 3698 3699 3700 | MODULE_SCOPE void TclSetProcessGlobalValue(ProcessGlobalValue *pgvPtr, Tcl_Obj *newValue); MODULE_SCOPE void TclSignalExitThread(Tcl_ThreadId id, int result); MODULE_SCOPE void TclSpellFix(Tcl_Interp *interp, Tcl_Obj *const *objv, Tcl_Size objc, Tcl_Size subIdx, Tcl_Obj *bad, Tcl_Obj *fix); MODULE_SCOPE void * TclStackRealloc(Tcl_Interp *interp, void *ptr, | | | | | > > > | | 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 | MODULE_SCOPE void TclSetProcessGlobalValue(ProcessGlobalValue *pgvPtr, Tcl_Obj *newValue); MODULE_SCOPE void TclSignalExitThread(Tcl_ThreadId id, int result); MODULE_SCOPE void TclSpellFix(Tcl_Interp *interp, Tcl_Obj *const *objv, Tcl_Size objc, Tcl_Size subIdx, Tcl_Obj *bad, Tcl_Obj *fix); MODULE_SCOPE void * TclStackRealloc(Tcl_Interp *interp, void *ptr, TCL_HASH_TYPE 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, Tcl_Size reqlength); MODULE_SCOPE int TclStringMatch(const char *str, Tcl_Size strLen, const char *pattern, int ptnLen, int flags); MODULE_SCOPE int TclStringMatchObj(Tcl_Obj *stringObj, Tcl_Obj *patternObj, int flags); MODULE_SCOPE void TclSubstCompile(Tcl_Interp *interp, const char *bytes, Tcl_Size numBytes, int flags, Tcl_Size line, struct CompileEnv *envPtr); MODULE_SCOPE int TclSubstOptions(Tcl_Interp *interp, Tcl_Size numOpts, Tcl_Obj *const opts[], int *flagPtr); MODULE_SCOPE void TclSubstParse(Tcl_Interp *interp, const char *bytes, Tcl_Size numBytes, int flags, Tcl_Parse *parsePtr, Tcl_InterpState *statePtr); MODULE_SCOPE int TclSubstTokens(Tcl_Interp *interp, Tcl_Token *tokenPtr, Tcl_Size count, int *tokensLeftPtr, Tcl_Size line, Tcl_Size *clNextOuter, const char *outerScript); MODULE_SCOPE Tcl_Size TclTrim(const char *bytes, Tcl_Size numBytes, const char *trim, Tcl_Size numTrim, Tcl_Size *trimRight); MODULE_SCOPE Tcl_Size TclTrimLeft(const char *bytes, Tcl_Size numBytes, const char *trim, Tcl_Size numTrim); MODULE_SCOPE Tcl_Size TclTrimRight(const char *bytes, Tcl_Size numBytes, const char *trim, Tcl_Size numTrim); MODULE_SCOPE const char*TclGetCommandTypeName(Tcl_Command command); MODULE_SCOPE int TclObjInterpProc(void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); 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); MODULE_SCOPE Tcl_Obj * TclpNativeToNormalized(void *clientData); MODULE_SCOPE Tcl_Obj * TclpFilesystemPathType(Tcl_Obj *pathPtr); MODULE_SCOPE int TclpDlopen(Tcl_Interp *interp, Tcl_Obj *pathPtr, |
| ︙ | ︙ | |||
3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 | # define TCL_WIDE_CLICKS 1 MODULE_SCOPE long long TclpGetWideClicks(void); MODULE_SCOPE double TclpWideClickInMicrosec(void); # define TclpWideClicksToNanoseconds(clicks) \ ((double)(clicks) * TclpWideClickInMicrosec() * 1000) # endif #endif MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp); MODULE_SCOPE void * TclpThreadCreateKey(void); MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr); MODULE_SCOPE void TclpThreadSetGlobalTSD(void *tsdKeyPtr, void *ptr); MODULE_SCOPE void * TclpThreadGetGlobalTSD(void *tsdKeyPtr); MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp, const char *msg, Tcl_Size length); /* Tip 430 */ | > < | < < < | | | | > > | | | | < | | | | | | | | | | | < < | | | | | | | | | | | | | | | > > | | | | | | | | | | | | | | | < | | | | | | | | | | | | < | | | | > > | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 |
# define TCL_WIDE_CLICKS 1
MODULE_SCOPE long long TclpGetWideClicks(void);
MODULE_SCOPE double TclpWideClickInMicrosec(void);
# define TclpWideClicksToNanoseconds(clicks) \
((double)(clicks) * TclpWideClickInMicrosec() * 1000)
# endif
#endif
MODULE_SCOPE long long TclpGetMicroseconds(void);
MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp);
MODULE_SCOPE void * TclpThreadCreateKey(void);
MODULE_SCOPE void TclpThreadDeleteKey(void *keyPtr);
MODULE_SCOPE void TclpThreadSetGlobalTSD(void *tsdKeyPtr, void *ptr);
MODULE_SCOPE void * TclpThreadGetGlobalTSD(void *tsdKeyPtr);
MODULE_SCOPE void TclErrorStackResetIf(Tcl_Interp *interp,
const char *msg, Tcl_Size length);
/* Tip 430 */
MODULE_SCOPE int TclZipfs_Init(Tcl_Interp *interp);
MODULE_SCOPE int TclIsZipfsPath(const char *path);
MODULE_SCOPE void TclZipfsFinalize(void);
MODULE_SCOPE Tcl_Obj * TclGetObjNameOfShlib(void);
MODULE_SCOPE void TclSetObjNameOfShlib(Tcl_Obj *namePtr, Tcl_Encoding);
/*
* Many parsing tasks need a common definition of whitespace.
* Use this routine and macro to achieve that and place
* optimization (fragile on changes) in one place.
*/
MODULE_SCOPE int TclIsSpaceProc(int byte);
#define TclIsSpaceProcM(byte) \
(((unsigned)(byte) > 0x20) ? 0 : TclIsSpaceProc(byte))
/*
*----------------------------------------------------------------
* Command procedures in the generic core:
*----------------------------------------------------------------
*/
MODULE_SCOPE Tcl_ObjCmdProc Tcl_AfterObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_AppendObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ApplyObjCmd;
MODULE_SCOPE Tcl_Command TclInitArrayCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_Command TclInitBinaryCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc Tcl_BreakObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_CatchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_CdObjCmd;
MODULE_SCOPE Tcl_Command TclInitChanCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc TclChanCreateObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclChanPostEventObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclChanPopObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclChanPushObjCmd;
MODULE_SCOPE void TclClockInit(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc TclClockOldscanObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_CloseObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ConcatObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ConstObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ContinueObjCmd;
MODULE_SCOPE Tcl_TimerToken TclCreateAbsoluteTimerHandler(
Tcl_Time *timePtr, Tcl_TimerProc *proc,
void *clientData);
MODULE_SCOPE Tcl_ObjCmdProc TclDefaultBgErrorHandlerObjCmd;
MODULE_SCOPE Tcl_Command TclInitDictCmd(Tcl_Interp *interp);
MODULE_SCOPE int TclDictWithFinish(Tcl_Interp *interp, Var *varPtr,
Var *arrayPtr, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, int index, int pathc,
Tcl_Obj *const pathv[], Tcl_Obj *keysPtr);
MODULE_SCOPE Tcl_Obj * TclDictWithInit(Tcl_Interp *interp, Tcl_Obj *dictPtr,
Tcl_Size pathc, Tcl_Obj *const pathv[]);
MODULE_SCOPE Tcl_ObjCmdProc Tcl_DisassembleObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclLoadIcuObjCmd;
/* Assemble command function */
MODULE_SCOPE Tcl_ObjCmdProc Tcl_AssembleObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclNRAssembleObjCmd;
MODULE_SCOPE Tcl_Command TclInitEncodingCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc Tcl_EofObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ErrorObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_EvalObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ExecObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ExitObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ExprObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_FblockedObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_FconfigureObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_FcopyObjCmd;
MODULE_SCOPE Tcl_Command TclInitFileCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc Tcl_FileEventObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_FlushObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ForObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ForeachObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_FormatObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_GetsObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_GlobalObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_GlobObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_IfObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_IncrObjCmd;
MODULE_SCOPE Tcl_Command TclInitInfoCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc Tcl_InterpObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_JoinObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LappendObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LassignObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LeditObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LindexObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LinsertObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LlengthObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ListObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LmapObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LoadObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LpopObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LrangeObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LremoveObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LrepeatObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LreplaceObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LreverseObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LsearchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LseqObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LsetObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_LsortObjCmd;
MODULE_SCOPE Tcl_Command TclInitNamespaceCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc TclNamespaceEnsembleCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_OpenObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_PackageObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_PidObjCmd;
MODULE_SCOPE Tcl_Command TclInitPrefixCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc Tcl_PutsObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_PwdObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ReadObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_RegexpObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_RegsubObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_RenameObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_RepresentationCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ReturnObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ScanObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_SeekObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_SetObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_SplitObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_SocketObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_SourceObjCmd;
MODULE_SCOPE Tcl_Command TclInitStringCmd(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc Tcl_SubstObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_SwitchObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_TellObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_ThrowObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_TimeObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_TimeRateObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_TraceObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_TryObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_UnloadObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_UnsetObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_UpdateObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_UplevelObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_UpvarObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_VariableObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_VwaitObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc Tcl_WhileObjCmd;
/*
*----------------------------------------------------------------
* Compilation procedures for commands in the generic core:
*----------------------------------------------------------------
*/
|
| ︙ | ︙ | |||
3935 3936 3937 3938 3939 3940 3941 | MODULE_SCOPE CompileProc TclCompileDictForCmd; MODULE_SCOPE CompileProc TclCompileDictGetCmd; MODULE_SCOPE CompileProc TclCompileDictGetWithDefaultCmd; MODULE_SCOPE CompileProc TclCompileDictIncrCmd; MODULE_SCOPE CompileProc TclCompileDictLappendCmd; MODULE_SCOPE CompileProc TclCompileDictMapCmd; MODULE_SCOPE CompileProc TclCompileDictMergeCmd; | < < < < < < < | 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 | MODULE_SCOPE CompileProc TclCompileDictForCmd; MODULE_SCOPE CompileProc TclCompileDictGetCmd; MODULE_SCOPE CompileProc TclCompileDictGetWithDefaultCmd; MODULE_SCOPE CompileProc TclCompileDictIncrCmd; MODULE_SCOPE CompileProc TclCompileDictLappendCmd; MODULE_SCOPE CompileProc TclCompileDictMapCmd; MODULE_SCOPE CompileProc TclCompileDictMergeCmd; MODULE_SCOPE CompileProc TclCompileDictSetCmd; MODULE_SCOPE CompileProc TclCompileDictUnsetCmd; MODULE_SCOPE CompileProc TclCompileDictUpdateCmd; MODULE_SCOPE CompileProc TclCompileDictWithCmd; MODULE_SCOPE CompileProc TclCompileEnsemble; MODULE_SCOPE CompileProc TclCompileErrorCmd; MODULE_SCOPE CompileProc TclCompileExprCmd; MODULE_SCOPE CompileProc TclCompileForCmd; MODULE_SCOPE CompileProc TclCompileForeachCmd; MODULE_SCOPE CompileProc TclCompileFormatCmd; MODULE_SCOPE CompileProc TclCompileGlobalCmd; MODULE_SCOPE CompileProc TclCompileIfCmd; MODULE_SCOPE CompileProc TclCompileInfoCommandsCmd; MODULE_SCOPE CompileProc TclCompileInfoCoroutineCmd; MODULE_SCOPE CompileProc TclCompileInfoExistsCmd; MODULE_SCOPE CompileProc TclCompileInfoLevelCmd; MODULE_SCOPE CompileProc TclCompileInfoObjectClassCmd; MODULE_SCOPE CompileProc TclCompileInfoObjectIsACmd; MODULE_SCOPE CompileProc TclCompileInfoObjectNamespaceCmd; MODULE_SCOPE CompileProc TclCompileIncrCmd; MODULE_SCOPE CompileProc TclCompileLappendCmd; MODULE_SCOPE CompileProc TclCompileLassignCmd; MODULE_SCOPE CompileProc TclCompileLindexCmd; MODULE_SCOPE CompileProc TclCompileLinsertCmd; MODULE_SCOPE CompileProc TclCompileListCmd; MODULE_SCOPE CompileProc TclCompileLlengthCmd; MODULE_SCOPE CompileProc TclCompileLmapCmd; MODULE_SCOPE CompileProc TclCompileLrangeCmd; MODULE_SCOPE CompileProc TclCompileLreplaceCmd; MODULE_SCOPE CompileProc TclCompileLsetCmd; MODULE_SCOPE CompileProc TclCompileNamespaceCodeCmd; MODULE_SCOPE CompileProc TclCompileNamespaceCurrentCmd; MODULE_SCOPE CompileProc TclCompileNamespaceOriginCmd; MODULE_SCOPE CompileProc TclCompileNamespaceQualifiersCmd; MODULE_SCOPE CompileProc TclCompileNamespaceTailCmd; MODULE_SCOPE CompileProc TclCompileNamespaceUpvarCmd; |
| ︙ | ︙ | |||
4012 4013 4014 4015 4016 4017 4018 | MODULE_SCOPE CompileProc TclCompileStringTrimRCmd; MODULE_SCOPE CompileProc TclCompileSubstCmd; MODULE_SCOPE CompileProc TclCompileSwitchCmd; MODULE_SCOPE CompileProc TclCompileTailcallCmd; MODULE_SCOPE CompileProc TclCompileThrowCmd; MODULE_SCOPE CompileProc TclCompileTryCmd; MODULE_SCOPE CompileProc TclCompileUnsetCmd; | < | | | | | | | | | | | | | | | | | | | 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 | MODULE_SCOPE CompileProc TclCompileStringTrimRCmd; MODULE_SCOPE CompileProc TclCompileSubstCmd; MODULE_SCOPE CompileProc TclCompileSwitchCmd; MODULE_SCOPE CompileProc TclCompileTailcallCmd; MODULE_SCOPE CompileProc TclCompileThrowCmd; MODULE_SCOPE CompileProc TclCompileTryCmd; MODULE_SCOPE CompileProc TclCompileUnsetCmd; MODULE_SCOPE CompileProc TclCompileUpvarCmd; MODULE_SCOPE CompileProc TclCompileVariableCmd; MODULE_SCOPE CompileProc TclCompileWhileCmd; MODULE_SCOPE CompileProc TclCompileYieldCmd; MODULE_SCOPE CompileProc TclCompileYieldToCmd; MODULE_SCOPE CompileProc TclCompileBasic0ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic1ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic2ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic3ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic0Or1ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic1Or2ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic2Or3ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic0To2ArgCmd; MODULE_SCOPE CompileProc TclCompileBasic1To3ArgCmd; MODULE_SCOPE CompileProc TclCompileBasicMin0ArgCmd; MODULE_SCOPE CompileProc TclCompileBasicMin1ArgCmd; MODULE_SCOPE CompileProc TclCompileBasicMin2ArgCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInvertOpCmd; MODULE_SCOPE CompileProc TclCompileInvertOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNotOpCmd; MODULE_SCOPE CompileProc TclCompileNotOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclAddOpCmd; MODULE_SCOPE CompileProc TclCompileAddOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclMulOpCmd; MODULE_SCOPE CompileProc TclCompileMulOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclAndOpCmd; MODULE_SCOPE CompileProc TclCompileAndOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclOrOpCmd; MODULE_SCOPE CompileProc TclCompileOrOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclXorOpCmd; MODULE_SCOPE CompileProc TclCompileXorOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclPowOpCmd; MODULE_SCOPE CompileProc TclCompilePowOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclLshiftOpCmd; MODULE_SCOPE CompileProc TclCompileLshiftOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclRshiftOpCmd; MODULE_SCOPE CompileProc TclCompileRshiftOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclModOpCmd; MODULE_SCOPE CompileProc TclCompileModOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNeqOpCmd; MODULE_SCOPE CompileProc TclCompileNeqOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclStrneqOpCmd; MODULE_SCOPE CompileProc TclCompileStrneqOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclInOpCmd; MODULE_SCOPE CompileProc TclCompileInOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclNiOpCmd; MODULE_SCOPE CompileProc TclCompileNiOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclMinusOpCmd; MODULE_SCOPE CompileProc TclCompileMinusOpCmd; MODULE_SCOPE Tcl_ObjCmdProc TclDivOpCmd; MODULE_SCOPE CompileProc TclCompileDivOpCmd; MODULE_SCOPE CompileProc TclCompileLessOpCmd; MODULE_SCOPE CompileProc TclCompileLeqOpCmd; MODULE_SCOPE CompileProc TclCompileGreaterOpCmd; MODULE_SCOPE CompileProc TclCompileGeqOpCmd; MODULE_SCOPE CompileProc TclCompileEqOpCmd; MODULE_SCOPE CompileProc TclCompileStreqOpCmd; MODULE_SCOPE CompileProc TclCompileStrLtOpCmd; MODULE_SCOPE CompileProc TclCompileStrLeOpCmd; MODULE_SCOPE CompileProc TclCompileStrGtOpCmd; MODULE_SCOPE CompileProc TclCompileStrGeOpCmd; MODULE_SCOPE CompileProc TclCompileAssembleCmd; /* * Routines that provide the [string] ensemble functionality. Possible * candidates for public interface. */ MODULE_SCOPE Tcl_Obj * TclStringCat(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); MODULE_SCOPE Tcl_Obj * TclStringFirst(Tcl_Obj *needle, Tcl_Obj *haystack, Tcl_Size start); MODULE_SCOPE Tcl_Obj * TclStringLast(Tcl_Obj *needle, Tcl_Obj *haystack, Tcl_Size last); MODULE_SCOPE Tcl_Obj * TclStringRepeat(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Size count, int flags); MODULE_SCOPE Tcl_Obj * TclStringReplace(Tcl_Interp *interp, Tcl_Obj *objPtr, |
| ︙ | ︙ | |||
4117 4118 4119 4120 4121 4122 4123 | Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags, const char *msg, int createPart1, int createPart2, Var **arrayPtrPtr); MODULE_SCOPE Var * TclLookupArrayElement(Tcl_Interp *interp, Tcl_Obj *arrayNamePtr, Tcl_Obj *elNamePtr, int flags, const char *msg, int createPart1, int createPart2, | | | | | | | | | | | | | | | | | | | < | 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 |
Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags,
const char *msg, int createPart1,
int createPart2, Var **arrayPtrPtr);
MODULE_SCOPE Var * TclLookupArrayElement(Tcl_Interp *interp,
Tcl_Obj *arrayNamePtr, Tcl_Obj *elNamePtr,
int flags, const char *msg,
int createPart1, int createPart2,
Var *arrayPtr, int index);
MODULE_SCOPE Tcl_Obj * TclPtrGetVarIdx(Tcl_Interp *interp,
Var *varPtr, Var *arrayPtr, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, int flags, int index);
MODULE_SCOPE Tcl_Obj * TclPtrSetVarIdx(Tcl_Interp *interp,
Var *varPtr, Var *arrayPtr, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr,
int flags, int index);
MODULE_SCOPE Tcl_Obj * TclPtrIncrObjVarIdx(Tcl_Interp *interp,
Var *varPtr, Var *arrayPtr, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, Tcl_Obj *incrPtr,
int flags, int index);
MODULE_SCOPE int TclPtrObjMakeUpvarIdx(Tcl_Interp *interp,
Var *otherPtr, Tcl_Obj *myNamePtr, int myFlags,
int index);
MODULE_SCOPE int TclPtrUnsetVarIdx(Tcl_Interp *interp, Var *varPtr,
Var *arrayPtr, Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, int flags,
int index);
MODULE_SCOPE void TclInvalidateNsPath(Namespace *nsPtr);
MODULE_SCOPE void TclFindArrayPtrElements(Var *arrayPtr,
Tcl_HashTable *tablePtr);
/*
* The new extended interface to the variable traces.
*/
MODULE_SCOPE int TclObjCallVarTraces(Interp *iPtr, Var *arrayPtr,
Var *varPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr,
int flags, int leaveErrMsg, int index);
/*
* So tclObj.c and tclDictObj.c can share these implementations.
*/
MODULE_SCOPE int TclCompareObjKeys(void *keyPtr, Tcl_HashEntry *hPtr);
MODULE_SCOPE void TclFreeObjEntry(Tcl_HashEntry *hPtr);
MODULE_SCOPE TCL_HASH_TYPE TclHashObjKey(Tcl_HashTable *tablePtr, void *keyPtr);
MODULE_SCOPE int TclFullFinalizationRequested(void);
/*
* TIP #542
*/
MODULE_SCOPE size_t TclUniCharLen(const Tcl_UniChar *uniStr);
MODULE_SCOPE int TclUniCharNcmp(const Tcl_UniChar *ucs,
const Tcl_UniChar *uct, size_t numChars);
MODULE_SCOPE int TclUniCharNcasecmp(const Tcl_UniChar *ucs,
const Tcl_UniChar *uct, size_t numChars);
MODULE_SCOPE int TclUniCharCaseMatch(const Tcl_UniChar *uniStr,
const Tcl_UniChar *uniPattern, int nocase);
/*
* 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 TclChildObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclInvokeImportedCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOPublicObjectCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOPrivateObjectCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOMyClassObjCmd;
/*
* TIP #462.
*/
/*
* The following enum values give the status of a spawned process.
*/
typedef enum TclProcessWaitStatus {
TCL_PROCESS_ERROR = -1, /* Error waiting for process to exit */
TCL_PROCESS_UNCHANGED = 0, /* No change since the last call. */
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
/* Child wait status didn't make sense. */
} TclProcessWaitStatus;
MODULE_SCOPE Tcl_Command TclInitProcessCmd(Tcl_Interp *interp);
MODULE_SCOPE void TclProcessCreated(Tcl_Pid pid);
MODULE_SCOPE TclProcessWaitStatus TclProcessWait(Tcl_Pid pid, int options,
int *codePtr, Tcl_Obj **msgObjPtr,
Tcl_Obj **errorObjPtr);
MODULE_SCOPE int TclClose(Tcl_Interp *, Tcl_Channel chan);
/*
|
| ︙ | ︙ | |||
4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 | int before, int after, int *indexPtr); MODULE_SCOPE Tcl_Size TclIndexDecode(int encoded, Tcl_Size endValue); /* * Error message utility functions */ MODULE_SCOPE int TclListLimitExceededError(Tcl_Interp *interp); /* Constants used in index value encoding routines. */ #define TCL_INDEX_END ((Tcl_Size)-2) #define TCL_INDEX_START ((Tcl_Size)0) /* *---------------------------------------------------------------- * Macros used by the Tcl core to create and release Tcl objects. * TclNewObj(objPtr) creates a new object denoting an empty string. * TclDecrRefCount(objPtr) decrements the object's reference count, and frees * the object if its reference count is zero. These macros are inline versions | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 |
int before, int after, int *indexPtr);
MODULE_SCOPE Tcl_Size TclIndexDecode(int encoded, Tcl_Size endValue);
/*
* Error message utility functions
*/
MODULE_SCOPE int TclListLimitExceededError(Tcl_Interp *interp);
MODULE_SCOPE int TclCommandWordLimitError(Tcl_Interp *interp,
Tcl_Size count);
#endif /* TCL_MAJOR_VERSION > 8 */
/* Constants used in index value encoding routines. */
#define TCL_INDEX_END ((Tcl_Size)-2)
#define TCL_INDEX_START ((Tcl_Size)0)
/*
*----------------------------------------------------------------------
*
* TclScaleTime --
*
* TIP #233 (Virtualized Time): Wrapper around the time virutalisation
* rescale function to hide the binding of the clientData.
*
* This is static inline code; it's like a macro, but a function. It's
* used because this is a piece of code that ends up in places that are a
* bit performance sensitive.
*
* Results:
* None
*
* Side effects:
* Updates the time structure (given as an argument) with what the time
* should be after virtualisation.
*
*----------------------------------------------------------------------
*/
static inline void
TclScaleTime(
Tcl_Time *timePtr)
{
if (timePtr != NULL) {
tclScaleTimeProcPtr(timePtr, tclTimeClientData);
}
}
/*
*----------------------------------------------------------------
* Macros used by the Tcl core to create and release Tcl objects.
* TclNewObj(objPtr) creates a new object denoting an empty string.
* TclDecrRefCount(objPtr) decrements the object's reference count, and frees
* the object if its reference count is zero. These macros are inline versions
|
| ︙ | ︙ | |||
4311 4312 4313 4314 4315 4316 4317 |
if ((objPtr)->refCount-- > 1) ; else { \
if (!(objPtr)->typePtr || !(objPtr)->typePtr->freeIntRepProc) { \
TCL_DTRACE_OBJ_FREE(objPtr); \
if ((objPtr)->bytes \
&& ((objPtr)->bytes != &tclEmptyString)) { \
Tcl_Free((objPtr)->bytes); \
} \
| | | 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 |
if ((objPtr)->refCount-- > 1) ; else { \
if (!(objPtr)->typePtr || !(objPtr)->typePtr->freeIntRepProc) { \
TCL_DTRACE_OBJ_FREE(objPtr); \
if ((objPtr)->bytes \
&& ((objPtr)->bytes != &tclEmptyString)) { \
Tcl_Free((objPtr)->bytes); \
} \
(objPtr)->length = -1; \
TclFreeObjStorage(objPtr); \
TclIncrObjsFreed(); \
} else { \
TclFreeObj(objPtr); \
} \
}
|
| ︙ | ︙ | |||
4440 4441 4442 4443 4444 4445 4446 |
int line);
# define TclDbNewObj(objPtr, file, line) \
do { \
TclIncrObjsAllocated(); \
(objPtr) = (Tcl_Obj *) \
Tcl_DbCkalloc(sizeof(Tcl_Obj), (file), (line)); \
| < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 |
int line);
# define TclDbNewObj(objPtr, file, line) \
do { \
TclIncrObjsAllocated(); \
(objPtr) = (Tcl_Obj *) \
Tcl_DbCkalloc(sizeof(Tcl_Obj), (file), (line)); \
TclDbInitNewObj((objPtr), (file), (line)); \
TCL_DTRACE_OBJ_CREATE(objPtr); \
} while (0)
# define TclNewObj(objPtr) \
TclDbNewObj(objPtr, __FILE__, __LINE__);
# define TclDecrRefCount(objPtr) \
Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__)
#undef USE_THREAD_ALLOC
#endif /* TCL_MEM_DEBUG */
/*
*----------------------------------------------------------------
* Macros used by the Tcl core to set a Tcl_Obj's string representation to a
* copy of the "len" bytes starting at "bytePtr". The value of "len" must
* not be negative. When "len" is 0, then it is acceptable to pass
* "bytePtr" = NULL. When "len" > 0, "bytePtr" must not be NULL, and it
* must point to a location from which "len" bytes may be read. These
|
| ︙ | ︙ | |||
4517 4518 4519 4520 4521 4522 4523 |
((objPtr)->length = (((objPtr)->bytes = &tclEmptyString), 0))
#define TclInitStringRep(objPtr, bytePtr, len) \
if ((len) == 0) { \
TclInitEmptyStringRep(objPtr); \
} else { \
(objPtr)->bytes = (char *)Tcl_Alloc((len) + 1U); \
| | | | 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 |
((objPtr)->length = (((objPtr)->bytes = &tclEmptyString), 0))
#define TclInitStringRep(objPtr, bytePtr, len) \
if ((len) == 0) { \
TclInitEmptyStringRep(objPtr); \
} else { \
(objPtr)->bytes = (char *)Tcl_Alloc((len) + 1U); \
memcpy((objPtr)->bytes, (bytePtr) ? (bytePtr) : &tclEmptyString, (len)); \
(objPtr)->bytes[len] = '\0'; \
(objPtr)->length = (len); \
}
#define TclAttemptInitStringRep(objPtr, bytePtr, len) \
((((len) == 0) ? ( \
TclInitEmptyStringRep(objPtr) \
) : ( \
(objPtr)->bytes = (char *)Tcl_AttemptAlloc((len) + 1U), \
(objPtr)->length = ((objPtr)->bytes) ? \
(memcpy((objPtr)->bytes, (bytePtr) ? (bytePtr) : &tclEmptyString, (len)), \
(objPtr)->bytes[len] = '\0', (Tcl_Size)(len)) : (-1) \
)), (objPtr)->bytes)
/*
*----------------------------------------------------------------
* Macro used by the Tcl core to get the string representation's byte array
* pointer from a Tcl_Obj. This is an inline version of Tcl_GetString(). The
|
| ︙ | ︙ | |||
4728 4729 4730 4731 4732 4733 4734 |
*----------------------------------------------------------------
*/
#define TclNumUtfCharsM(numChars, bytes, numBytes) \
do { \
Tcl_Size _count, _i = (numBytes); \
unsigned char *_str = (unsigned char *) (bytes); \
| | < < < | 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 |
*----------------------------------------------------------------
*/
#define TclNumUtfCharsM(numChars, bytes, numBytes) \
do { \
Tcl_Size _count, _i = (numBytes); \
unsigned char *_str = (unsigned char *) (bytes); \
while (_i > 0 && (*_str < 0xC0)) { _i--; _str++; } \
_count = (numBytes) - _i; \
if (_i) { \
_count += Tcl_NumUtfChars((bytes) + _count, _i); \
} \
(numChars) = _count; \
} while (0);
|
| ︙ | ︙ | |||
5182 5183 5184 5185 5186 5187 5188 | #if !defined(USE_TCL_STUBS) && !defined(TCL_MEM_DEBUG) #define Tcl_AttemptAlloc TclpAlloc #define Tcl_AttemptRealloc TclpRealloc #define Tcl_Free TclpFree #endif | < < < < < < < < < > > > > > > > | 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 |
#if !defined(USE_TCL_STUBS) && !defined(TCL_MEM_DEBUG)
#define Tcl_AttemptAlloc TclpAlloc
#define Tcl_AttemptRealloc TclpRealloc
#define Tcl_Free TclpFree
#endif
/*
* Special hack for macOS, where the static linker (technically the 'ar'
* command) hates empty object files, and accepts no flags to make it shut up.
*
* These symbols are otherwise completely useless.
*
* They can't be written to or written through. They can't be seen by any
* other code. They use a separate attribute (supported by all macOS
* compilers, which are derivatives of clang or gcc) to stop the compilation
* from moaning. They will be excluded during the final linking stage.
*
* Other platforms get nothing at all. That's good.
*/
#ifdef MAC_OSX_TCL
#define TCL_MAC_EMPTY_FILE(name) \
static __attribute__((used)) const void *const TclUnusedFile_ ## name = NULL;
#else
#define TCL_MAC_EMPTY_FILE(name)
#endif /* MAC_OSX_TCL */
#ifdef _TCLSIZEHANDLED
# undef _TCLSIZEHANDLED
# undef Tcl_Size
# undef Tcl_ObjCmdProc2
# undef Tcl_CmdObjTraceProc2
#endif
/*
* Other externals.
*/
MODULE_SCOPE size_t TclEnvEpoch; /* Epoch of the tcl environment
* (if changed with tcl-env). */
|
| ︙ | ︙ |
Changes to generic/tclIntDecls.h.
1 2 3 4 5 6 7 8 | /* * tclIntDecls.h -- * * This file contains the declarations for all unsupported * functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * | | > < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | /* * tclIntDecls.h -- * * This file contains the declarations for all unsupported * functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLINTDECLS #define _TCLINTDECLS #undef TCL_STORAGE_CLASS #ifdef BUILD_tcl # define TCL_STORAGE_CLASS DLLEXPORT #else # ifdef USE_TCL_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT # endif #endif /* * WARNING: This file is automatically generated by the tools/genStubs.tcl * script. Any modifications to the function declarations below should be made * in the generic/tclInt.decls script. */ /* !BEGIN!: Do not edit below this line. */ |
| ︙ | ︙ | |||
135 136 137 138 139 140 141 | Tcl_DString *bufferPtr); /* 43 */ EXTERN Tcl_ObjCmdProc2 * TclGetObjInterpProc2(void); /* Slot 44 is reserved */ /* 45 */ EXTERN int TclHideUnsafeCommands(Tcl_Interp *interp); /* 46 */ | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | Tcl_DString *bufferPtr); /* 43 */ EXTERN Tcl_ObjCmdProc2 * TclGetObjInterpProc2(void); /* Slot 44 is reserved */ /* 45 */ EXTERN int TclHideUnsafeCommands(Tcl_Interp *interp); /* 46 */ EXTERN int TclInExit(void); /* Slot 47 is reserved */ /* Slot 48 is reserved */ /* Slot 49 is reserved */ /* Slot 50 is reserved */ /* 51 */ EXTERN int TclInterpInit(Tcl_Interp *interp); /* Slot 52 is reserved */ |
| ︙ | ︙ | |||
170 171 172 173 174 175 176 | EXTERN int TclObjInvoke(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* Slot 65 is reserved */ /* Slot 66 is reserved */ /* Slot 67 is reserved */ /* Slot 68 is reserved */ /* 69 */ | | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | EXTERN int TclObjInvoke(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* Slot 65 is reserved */ /* Slot 66 is reserved */ /* Slot 67 is reserved */ /* Slot 68 is reserved */ /* 69 */ EXTERN void * TclpAlloc(TCL_HASH_TYPE size); /* Slot 70 is reserved */ /* Slot 71 is reserved */ /* Slot 72 is reserved */ /* Slot 73 is reserved */ /* 74 */ EXTERN void TclpFree(void *ptr); /* 75 */ EXTERN unsigned long long TclpGetClicks(void); /* 76 */ EXTERN unsigned long long TclpGetSeconds(void); /* Slot 77 is reserved */ /* Slot 78 is reserved */ /* Slot 79 is reserved */ /* Slot 80 is reserved */ /* 81 */ EXTERN void * TclpRealloc(void *ptr, TCL_HASH_TYPE size); /* Slot 82 is reserved */ /* Slot 83 is reserved */ /* Slot 84 is reserved */ /* Slot 85 is reserved */ /* Slot 86 is reserved */ /* Slot 87 is reserved */ /* Slot 88 is reserved */ |
| ︙ | ︙ | |||
364 365 366 367 368 369 370 | Tcl_Size objc, Tcl_Obj *const objv[]); /* 171 */ EXTERN int TclCheckExecutionTraces(Tcl_Interp *interp, const char *command, Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags, Tcl_Size objc, Tcl_Obj *const objv[]); /* 172 */ | | | | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | Tcl_Size objc, Tcl_Obj *const objv[]); /* 171 */ EXTERN int TclCheckExecutionTraces(Tcl_Interp *interp, const char *command, Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags, Tcl_Size objc, Tcl_Obj *const objv[]); /* 172 */ EXTERN int TclInThreadExit(void); /* 173 */ EXTERN int TclUniCharMatch(const Tcl_UniChar *string, Tcl_Size strLen, const Tcl_UniChar *pattern, Tcl_Size ptnLen, int flags); /* Slot 174 is reserved */ /* 175 */ EXTERN int TclCallVarTraces(Interp *iPtr, Var *arrayPtr, Var *varPtr, const char *part1, const char *part2, int flags, |
| ︙ | ︙ | |||
439 440 441 442 443 444 445 | EXTERN void TclpFindExecutable(const char *argv0); /* 213 */ EXTERN Tcl_Obj * TclGetObjNameOfExecutable(void); /* 214 */ EXTERN void TclSetObjNameOfExecutable(Tcl_Obj *name, Tcl_Encoding encoding); /* 215 */ | | > | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | EXTERN void TclpFindExecutable(const char *argv0); /* 213 */ EXTERN Tcl_Obj * TclGetObjNameOfExecutable(void); /* 214 */ EXTERN void TclSetObjNameOfExecutable(Tcl_Obj *name, Tcl_Encoding encoding); /* 215 */ EXTERN void * TclStackAlloc(Tcl_Interp *interp, TCL_HASH_TYPE numBytes); /* 216 */ EXTERN void TclStackFree(Tcl_Interp *interp, void *freePtr); /* 217 */ EXTERN int TclPushStackFrame(Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr, Tcl_Namespace *namespacePtr, int isProcCallFrame); |
| ︙ | ︙ | |||
475 476 477 478 479 480 481 | EXTERN int TclObjBeingDeleted(Tcl_Obj *objPtr); /* 227 */ EXTERN void TclSetNsPath(Namespace *nsPtr, Tcl_Size pathLength, Tcl_Namespace *pathAry[]); /* Slot 228 is reserved */ /* 229 */ EXTERN int TclPtrMakeUpvar(Tcl_Interp *interp, Var *otherP1Ptr, | | < | < | | < | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | EXTERN int TclObjBeingDeleted(Tcl_Obj *objPtr); /* 227 */ EXTERN void TclSetNsPath(Namespace *nsPtr, Tcl_Size pathLength, Tcl_Namespace *pathAry[]); /* Slot 228 is reserved */ /* 229 */ EXTERN int TclPtrMakeUpvar(Tcl_Interp *interp, Var *otherP1Ptr, const char *myName, int myFlags, int index); /* 230 */ EXTERN Var * TclObjLookupVar(Tcl_Interp *interp, Tcl_Obj *part1Ptr, const char *part2, int flags, const char *msg, int createPart1, int createPart2, Var **arrayPtrPtr); /* 231 */ EXTERN int TclGetNamespaceFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr); /* 232 */ EXTERN int TclEvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags, const CmdFrame *invoker, int word); /* 233 */ EXTERN void TclGetSrcInfoForPc(CmdFrame *contextPtr); /* 234 */ EXTERN Var * TclVarHashCreateVar(TclVarHashTable *tablePtr, const char *key, int *newPtr); /* 235 */ EXTERN void TclInitVarHashTable(TclVarHashTable *tablePtr, Namespace *nsPtr); /* Slot 236 is reserved */ /* 237 */ EXTERN int TclResetCancellation(Tcl_Interp *interp, int force); /* 238 */ EXTERN int TclNRInterpProc(void *clientData, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); /* 239 */ EXTERN int TclNRInterpProcCore(Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Size skip, ProcErrorProc *errorProc); /* 240 */ EXTERN int TclNRRunCallbacks(Tcl_Interp *interp, int result, struct NRE_callback *rootPtr); /* 241 */ EXTERN int TclNREvalObjEx(Tcl_Interp *interp, Tcl_Obj *objPtr, int flags, const CmdFrame *invoker, int word); /* 242 */ EXTERN int TclNREvalObjv(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags, Command *cmdPtr); /* 243 */ EXTERN void TclDbDumpActiveObjects(FILE *outFile); /* 244 */ |
| ︙ | ︙ | |||
628 629 630 631 632 633 634 |
Tcl_ObjCmdProc * (*tclGetObjInterpProc) (void); /* 39 */
int (*tclGetOpenMode) (Tcl_Interp *interp, const char *str, int *modeFlagsPtr); /* 40 */
Tcl_Command (*tclGetOriginalCommand) (Tcl_Command command); /* 41 */
const char * (*tclpGetUserHome) (const char *name, Tcl_DString *bufferPtr); /* 42 */
Tcl_ObjCmdProc2 * (*tclGetObjInterpProc2) (void); /* 43 */
void (*reserved44)(void);
int (*tclHideUnsafeCommands) (Tcl_Interp *interp); /* 45 */
| | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
Tcl_ObjCmdProc * (*tclGetObjInterpProc) (void); /* 39 */
int (*tclGetOpenMode) (Tcl_Interp *interp, const char *str, int *modeFlagsPtr); /* 40 */
Tcl_Command (*tclGetOriginalCommand) (Tcl_Command command); /* 41 */
const char * (*tclpGetUserHome) (const char *name, Tcl_DString *bufferPtr); /* 42 */
Tcl_ObjCmdProc2 * (*tclGetObjInterpProc2) (void); /* 43 */
void (*reserved44)(void);
int (*tclHideUnsafeCommands) (Tcl_Interp *interp); /* 45 */
int (*tclInExit) (void); /* 46 */
void (*reserved47)(void);
void (*reserved48)(void);
void (*reserved49)(void);
void (*reserved50)(void);
int (*tclInterpInit) (Tcl_Interp *interp); /* 51 */
void (*reserved52)(void);
void (*reserved53)(void);
|
| ︙ | ︙ | |||
651 652 653 654 655 656 657 |
int (*tclObjCommandComplete) (Tcl_Obj *cmdPtr); /* 62 */
void (*reserved63)(void);
int (*tclObjInvoke) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 64 */
void (*reserved65)(void);
void (*reserved66)(void);
void (*reserved67)(void);
void (*reserved68)(void);
| | | | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 |
int (*tclObjCommandComplete) (Tcl_Obj *cmdPtr); /* 62 */
void (*reserved63)(void);
int (*tclObjInvoke) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags); /* 64 */
void (*reserved65)(void);
void (*reserved66)(void);
void (*reserved67)(void);
void (*reserved68)(void);
void * (*tclpAlloc) (TCL_HASH_TYPE size); /* 69 */
void (*reserved70)(void);
void (*reserved71)(void);
void (*reserved72)(void);
void (*reserved73)(void);
void (*tclpFree) (void *ptr); /* 74 */
unsigned long long (*tclpGetClicks) (void); /* 75 */
unsigned long long (*tclpGetSeconds) (void); /* 76 */
void (*reserved77)(void);
void (*reserved78)(void);
void (*reserved79)(void);
void (*reserved80)(void);
void * (*tclpRealloc) (void *ptr, TCL_HASH_TYPE size); /* 81 */
void (*reserved82)(void);
void (*reserved83)(void);
void (*reserved84)(void);
void (*reserved85)(void);
void (*reserved86)(void);
void (*reserved87)(void);
void (*reserved88)(void);
|
| ︙ | ︙ | |||
754 755 756 757 758 759 760 |
void (*tclpSetInitialEncodings) (void); /* 165 */
int (*tclListObjSetElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size index, Tcl_Obj *valuePtr); /* 166 */
void (*reserved167)(void);
void (*reserved168)(void);
int (*tclpUtfNcmp2) (const void *s1, const void *s2, size_t n); /* 169 */
int (*tclCheckInterpTraces) (Tcl_Interp *interp, const char *command, Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags, Tcl_Size objc, Tcl_Obj *const objv[]); /* 170 */
int (*tclCheckExecutionTraces) (Tcl_Interp *interp, const char *command, Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags, Tcl_Size objc, Tcl_Obj *const objv[]); /* 171 */
| | | | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
void (*tclpSetInitialEncodings) (void); /* 165 */
int (*tclListObjSetElement) (Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Size index, Tcl_Obj *valuePtr); /* 166 */
void (*reserved167)(void);
void (*reserved168)(void);
int (*tclpUtfNcmp2) (const void *s1, const void *s2, size_t n); /* 169 */
int (*tclCheckInterpTraces) (Tcl_Interp *interp, const char *command, Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags, Tcl_Size objc, Tcl_Obj *const objv[]); /* 170 */
int (*tclCheckExecutionTraces) (Tcl_Interp *interp, const char *command, Tcl_Size numChars, Command *cmdPtr, int result, int traceFlags, Tcl_Size objc, Tcl_Obj *const objv[]); /* 171 */
int (*tclInThreadExit) (void); /* 172 */
int (*tclUniCharMatch) (const Tcl_UniChar *string, Tcl_Size strLen, const Tcl_UniChar *pattern, Tcl_Size ptnLen, int flags); /* 173 */
void (*reserved174)(void);
int (*tclCallVarTraces) (Interp *iPtr, Var *arrayPtr, Var *varPtr, const char *part1, const char *part2, int flags, int leaveErrMsg); /* 175 */
void (*tclCleanupVar) (Var *varPtr, Var *arrayPtr); /* 176 */
void (*tclVarErrMsg) (Tcl_Interp *interp, const char *part1, const char *part2, const char *operation, const char *reason); /* 177 */
void (*reserved178)(void);
void (*reserved179)(void);
void (*reserved180)(void);
|
| ︙ | ︙ | |||
797 798 799 800 801 802 803 |
Tcl_Channel (*tclpOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions); /* 208 */
void (*reserved209)(void);
void (*reserved210)(void);
void (*reserved211)(void);
void (*tclpFindExecutable) (const char *argv0); /* 212 */
Tcl_Obj * (*tclGetObjNameOfExecutable) (void); /* 213 */
void (*tclSetObjNameOfExecutable) (Tcl_Obj *name, Tcl_Encoding encoding); /* 214 */
| | | | | | | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 |
Tcl_Channel (*tclpOpenFileChannel) (Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions); /* 208 */
void (*reserved209)(void);
void (*reserved210)(void);
void (*reserved211)(void);
void (*tclpFindExecutable) (const char *argv0); /* 212 */
Tcl_Obj * (*tclGetObjNameOfExecutable) (void); /* 213 */
void (*tclSetObjNameOfExecutable) (Tcl_Obj *name, Tcl_Encoding encoding); /* 214 */
void * (*tclStackAlloc) (Tcl_Interp *interp, TCL_HASH_TYPE numBytes); /* 215 */
void (*tclStackFree) (Tcl_Interp *interp, void *freePtr); /* 216 */
int (*tclPushStackFrame) (Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr, Tcl_Namespace *namespacePtr, int isProcCallFrame); /* 217 */
void (*tclPopStackFrame) (Tcl_Interp *interp); /* 218 */
Tcl_Obj * (*tclpCreateTemporaryDirectory) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj); /* 219 */
void (*reserved220)(void);
Tcl_Obj * (*tclListTestObj) (size_t length, size_t leadingSpace, size_t endSpace); /* 221 */
void (*tclListObjValidate) (Tcl_Interp *interp, Tcl_Obj *listObj); /* 222 */
void * (*tclGetCStackPtr) (void); /* 223 */
TclPlatformType * (*tclGetPlatform) (void); /* 224 */
Tcl_Obj * (*tclTraceDictPath) (Tcl_Interp *interp, Tcl_Obj *rootPtr, Tcl_Size keyc, Tcl_Obj *const keyv[], int flags); /* 225 */
int (*tclObjBeingDeleted) (Tcl_Obj *objPtr); /* 226 */
void (*tclSetNsPath) (Namespace *nsPtr, Tcl_Size pathLength, Tcl_Namespace *pathAry[]); /* 227 */
void (*reserved228)(void);
int (*tclPtrMakeUpvar) (Tcl_Interp *interp, Var *otherP1Ptr, const char *myName, int myFlags, int index); /* 229 */
Var * (*tclObjLookupVar) (Tcl_Interp *interp, Tcl_Obj *part1Ptr, const char *part2, int flags, const char *msg, int createPart1, int createPart2, Var **arrayPtrPtr); /* 230 */
int (*tclGetNamespaceFromObj) (Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr); /* 231 */
int (*tclEvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags, const CmdFrame *invoker, int word); /* 232 */
void (*tclGetSrcInfoForPc) (CmdFrame *contextPtr); /* 233 */
Var * (*tclVarHashCreateVar) (TclVarHashTable *tablePtr, const char *key, int *newPtr); /* 234 */
void (*tclInitVarHashTable) (TclVarHashTable *tablePtr, Namespace *nsPtr); /* 235 */
void (*reserved236)(void);
int (*tclResetCancellation) (Tcl_Interp *interp, int force); /* 237 */
int (*tclNRInterpProc) (void *clientData, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); /* 238 */
int (*tclNRInterpProcCore) (Tcl_Interp *interp, Tcl_Obj *procNameObj, Tcl_Size skip, ProcErrorProc *errorProc); /* 239 */
int (*tclNRRunCallbacks) (Tcl_Interp *interp, int result, struct NRE_callback *rootPtr); /* 240 */
int (*tclNREvalObjEx) (Tcl_Interp *interp, Tcl_Obj *objPtr, int flags, const CmdFrame *invoker, int word); /* 241 */
int (*tclNREvalObjv) (Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[], int flags, Command *cmdPtr); /* 242 */
void (*tclDbDumpActiveObjects) (FILE *outFile); /* 243 */
Tcl_HashTable * (*tclGetNamespaceChildTable) (Tcl_Namespace *nsPtr); /* 244 */
Tcl_HashTable * (*tclGetNamespaceCommandTable) (Tcl_Namespace *nsPtr); /* 245 */
int (*tclInitRewriteEnsemble) (Tcl_Interp *interp, Tcl_Size numRemoved, Tcl_Size numInserted, Tcl_Obj *const *objv); /* 246 */
void (*tclResetRewriteEnsemble) (Tcl_Interp *interp, int isRootEnsemble); /* 247 */
int (*tclCopyChannel) (Tcl_Interp *interp, Tcl_Channel inChan, Tcl_Channel outChan, long long toRead, Tcl_Obj *cmdPtr); /* 248 */
|
| ︙ | ︙ | |||
1266 1267 1268 1269 1270 1271 1272 | #define TclUnusedStubEntry \ (tclIntStubsPtr->tclUnusedStubEntry) /* 261 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ | < < < < < > > > > > > > > > > > | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 | #define TclUnusedStubEntry \ (tclIntStubsPtr->tclUnusedStubEntry) /* 261 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #if defined(USE_TCL_STUBS) #undef Tcl_StaticLibrary #define Tcl_StaticLibrary \ (tclIntStubsPtr->tclStaticLibrary) #endif /* defined(USE_TCL_STUBS) */ #if (TCL_MAJOR_VERSION < 9) && defined(USE_TCL_STUBS) #undef TclpGetClicks #define TclpGetClicks() \ ((unsigned long)tclIntStubsPtr->tclpGetClicks()) #undef TclpGetSeconds #define TclpGetSeconds() \ ((unsigned long)tclIntStubsPtr->tclpGetSeconds()) #undef TclGetObjInterpProc2 #define TclGetObjInterpProc2 TclGetObjInterpProc #endif #undef TclUnusedStubEntry #define TclObjInterpProc TclGetObjInterpProc() #define TclObjInterpProc2 TclGetObjInterpProc2() #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #endif /* _TCLINTDECLS */ |
Changes to generic/tclIntPlatDecls.h.
1 2 3 4 5 6 7 8 | /* * tclIntPlatDecls.h -- * * This file contains the declarations for all platform dependent * unsupported functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * tclIntPlatDecls.h -- * * This file contains the declarations for all platform dependent * unsupported functions that are exported by the Tcl library. These * interfaces are not guaranteed to remain the same between * versions. Use at your own risk. * * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. */ #ifndef _TCLINTPLATDECLS #define _TCLINTPLATDECLS #undef TCL_STORAGE_CLASS |
| ︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/*
* WARNING: This file is automatically generated by the tools/genStubs.tcl
* script. Any modifications to the function declarations below should be made
* in the generic/tclInt.decls script.
*/
/* !BEGIN!: Do not edit below this line. */
#ifdef __cplusplus
extern "C" {
#endif
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
/*
* WARNING: This file is automatically generated by the tools/genStubs.tcl
* script. Any modifications to the function declarations below should be made
* in the generic/tclInt.decls script.
*/
#if TCL_MAJOR_VERSION < 9
#ifdef __cplusplus
extern "C" {
#endif
/*
* Exported function declarations:
*/
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */
/* 0 */
EXTERN void TclGetAndDetachPids(Tcl_Interp *interp,
Tcl_Channel chan);
/* 1 */
EXTERN int TclpCloseFile(TclFile file);
/* 2 */
EXTERN Tcl_Channel TclpCreateCommandChannel(TclFile readFile,
TclFile writeFile, TclFile errorFile,
int numPids, Tcl_Pid *pidPtr);
/* 3 */
EXTERN int TclpCreatePipe(TclFile *readPipe, TclFile *writePipe);
/* 4 */
EXTERN int TclpCreateProcess(Tcl_Interp *interp, int argc,
const char **argv, TclFile inputFile,
TclFile outputFile, TclFile errorFile,
Tcl_Pid *pidPtr);
/* Slot 5 is reserved */
/* 6 */
EXTERN TclFile TclpMakeFile(Tcl_Channel channel, int direction);
/* 7 */
EXTERN TclFile TclpOpenFile(const char *fname, int mode);
/* 8 */
EXTERN int TclUnixWaitForFile(int fd, int mask, int timeout);
/* 9 */
EXTERN TclFile TclpCreateTempFile(const char *contents);
/* 10 */
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
/* Slot 11 is reserved */
/* Slot 12 is reserved */
/* Slot 13 is reserved */
/* 14 */
EXTERN int TclUnixCopyFile(const char *src, const char *dst,
const Tcl_StatBuf *statBufPtr,
int dontCopyAtts);
/* 15 */
EXTERN int TclMacOSXGetFileAttribute(Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj **attributePtrPtr);
/* 16 */
EXTERN int TclMacOSXSetFileAttribute(Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj *attributePtr);
/* 17 */
EXTERN int TclMacOSXCopyFileAttributes(const char *src,
const char *dst,
const Tcl_StatBuf *statBufPtr);
/* 18 */
EXTERN int TclMacOSXMatchType(Tcl_Interp *interp,
const char *pathName, const char *fileName,
Tcl_StatBuf *statBufPtr,
Tcl_GlobTypeData *types);
/* 19 */
EXTERN void TclMacOSXNotifierAddRunLoopMode(
const void *runLoopMode);
/* Slot 20 is reserved */
/* Slot 21 is reserved */
/* Slot 22 is reserved */
/* Slot 23 is reserved */
/* Slot 24 is reserved */
/* Slot 25 is reserved */
/* Slot 26 is reserved */
/* Slot 27 is reserved */
/* Slot 28 is reserved */
/* 29 */
EXTERN int TclWinCPUID(int index, int *regs);
/* 30 */
EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj,
Tcl_Obj *basenameObj, Tcl_Obj *extensionObj,
Tcl_Obj *resultingNameObj);
#endif /* UNIX */
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
/* Slot 0 is reserved */
/* Slot 1 is reserved */
/* Slot 2 is reserved */
/* Slot 3 is reserved */
/* 4 */
EXTERN void * TclWinGetTclInstance(void);
/* 5 */
EXTERN int TclUnixWaitForFile(int fd, int mask, int timeout);
/* Slot 6 is reserved */
/* Slot 7 is reserved */
/* 8 */
EXTERN Tcl_Size TclpGetPid(Tcl_Pid pid);
/* Slot 9 is reserved */
/* Slot 10 is reserved */
/* 11 */
EXTERN void TclGetAndDetachPids(Tcl_Interp *interp,
Tcl_Channel chan);
/* 12 */
EXTERN int TclpCloseFile(TclFile file);
/* 13 */
EXTERN Tcl_Channel TclpCreateCommandChannel(TclFile readFile,
TclFile writeFile, TclFile errorFile,
int numPids, Tcl_Pid *pidPtr);
/* 14 */
EXTERN int TclpCreatePipe(TclFile *readPipe, TclFile *writePipe);
/* 15 */
EXTERN int TclpCreateProcess(Tcl_Interp *interp, int argc,
const char **argv, TclFile inputFile,
TclFile outputFile, TclFile errorFile,
Tcl_Pid *pidPtr);
/* 16 */
EXTERN int TclpIsAtty(int fd);
/* 17 */
EXTERN int TclUnixCopyFile(const char *src, const char *dst,
const Tcl_StatBuf *statBufPtr,
int dontCopyAtts);
/* 18 */
EXTERN TclFile TclpMakeFile(Tcl_Channel channel, int direction);
/* 19 */
EXTERN TclFile TclpOpenFile(const char *fname, int mode);
/* 20 */
EXTERN void TclWinAddProcess(void *hProcess, Tcl_Size id);
/* Slot 21 is reserved */
/* 22 */
EXTERN TclFile TclpCreateTempFile(const char *contents);
/* Slot 23 is reserved */
/* 24 */
EXTERN char * TclWinNoBackslash(char *path);
/* Slot 25 is reserved */
/* Slot 26 is reserved */
/* 27 */
EXTERN void TclWinFlushDirtyChannels(void);
/* Slot 28 is reserved */
/* 29 */
EXTERN int TclWinCPUID(int index, int *regs);
/* 30 */
EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj,
Tcl_Obj *basenameObj, Tcl_Obj *extensionObj,
Tcl_Obj *resultingNameObj);
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
/* 0 */
EXTERN void TclGetAndDetachPids(Tcl_Interp *interp,
Tcl_Channel chan);
/* 1 */
EXTERN int TclpCloseFile(TclFile file);
/* 2 */
EXTERN Tcl_Channel TclpCreateCommandChannel(TclFile readFile,
TclFile writeFile, TclFile errorFile,
int numPids, Tcl_Pid *pidPtr);
/* 3 */
EXTERN int TclpCreatePipe(TclFile *readPipe, TclFile *writePipe);
/* 4 */
EXTERN int TclpCreateProcess(Tcl_Interp *interp, int argc,
const char **argv, TclFile inputFile,
TclFile outputFile, TclFile errorFile,
Tcl_Pid *pidPtr);
/* Slot 5 is reserved */
/* 6 */
EXTERN TclFile TclpMakeFile(Tcl_Channel channel, int direction);
/* 7 */
EXTERN TclFile TclpOpenFile(const char *fname, int mode);
/* 8 */
EXTERN int TclUnixWaitForFile(int fd, int mask, int timeout);
/* 9 */
EXTERN TclFile TclpCreateTempFile(const char *contents);
/* 10 */
EXTERN Tcl_DirEntry * TclpReaddir(TclDIR *dir);
/* Slot 13 is reserved */
/* 14 */
EXTERN int TclUnixCopyFile(const char *src, const char *dst,
const Tcl_StatBuf *statBufPtr,
int dontCopyAtts);
/* 15 */
EXTERN int TclMacOSXGetFileAttribute(Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj **attributePtrPtr);
/* 16 */
EXTERN int TclMacOSXSetFileAttribute(Tcl_Interp *interp,
int objIndex, Tcl_Obj *fileName,
Tcl_Obj *attributePtr);
/* 17 */
EXTERN int TclMacOSXCopyFileAttributes(const char *src,
const char *dst,
const Tcl_StatBuf *statBufPtr);
/* 18 */
EXTERN int TclMacOSXMatchType(Tcl_Interp *interp,
const char *pathName, const char *fileName,
Tcl_StatBuf *statBufPtr,
Tcl_GlobTypeData *types);
/* 19 */
EXTERN void TclMacOSXNotifierAddRunLoopMode(
const void *runLoopMode);
/* Slot 20 is reserved */
/* Slot 21 is reserved */
/* Slot 22 is reserved */
/* Slot 23 is reserved */
/* Slot 24 is reserved */
/* Slot 25 is reserved */
/* Slot 26 is reserved */
/* Slot 27 is reserved */
/* Slot 28 is reserved */
/* 29 */
EXTERN int TclWinCPUID(int index, int *regs);
/* 30 */
EXTERN int TclUnixOpenTemporaryFile(Tcl_Obj *dirObj,
Tcl_Obj *basenameObj, Tcl_Obj *extensionObj,
Tcl_Obj *resultingNameObj);
#endif /* MACOSX */
typedef struct TclIntPlatStubs {
int magic;
void *hooks;
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */
void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 0 */
int (*tclpCloseFile) (TclFile file); /* 1 */
Tcl_Channel (*tclpCreateCommandChannel) (TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr); /* 2 */
int (*tclpCreatePipe) (TclFile *readPipe, TclFile *writePipe); /* 3 */
int (*tclpCreateProcess) (Tcl_Interp *interp, int argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 4 */
int (*tclUnixWaitForFile_) (int fd, int mask, int timeout); /* 5 */
TclFile (*tclpMakeFile) (Tcl_Channel channel, int direction); /* 6 */
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) (TclDIR *dir); /* 10 */
void (*reserved11)(void);
void (*reserved12)(void);
void (*reserved13)(void);
int (*tclUnixCopyFile) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr, int dontCopyAtts); /* 14 */
int (*tclMacOSXGetFileAttribute) (Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr); /* 15 */
int (*tclMacOSXSetFileAttribute) (Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr); /* 16 */
int (*tclMacOSXCopyFileAttributes) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr); /* 17 */
int (*tclMacOSXMatchType) (Tcl_Interp *interp, const char *pathName, const char *fileName, Tcl_StatBuf *statBufPtr, Tcl_GlobTypeData *types); /* 18 */
void (*tclMacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 19 */
void (*reserved20)(void);
void (*reserved21)(void);
TclFile (*tclpCreateTempFile_) (const char *contents); /* 22 */
void (*reserved23)(void);
void (*reserved24)(void);
void (*reserved25)(void);
void (*reserved26)(void);
void (*reserved27)(void);
void (*reserved28)(void);
int (*tclWinCPUID) (int index, int *regs); /* 29 */
int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 30 */
#endif /* UNIX */
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
void (*reserved0)(void);
void (*reserved1)(void);
void (*reserved2)(void);
void (*reserved3)(void);
void * (*tclWinGetTclInstance) (void); /* 4 */
int (*tclUnixWaitForFile) (int fd, int mask, int timeout); /* 5 */
void (*reserved6)(void);
void (*reserved7)(void);
Tcl_Size (*tclpGetPid) (Tcl_Pid pid); /* 8 */
void (*reserved9)(void);
void *(*tclpReaddir) (void *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 */
int (*tclpCreatePipe) (TclFile *readPipe, TclFile *writePipe); /* 14 */
int (*tclpCreateProcess) (Tcl_Interp *interp, int argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 15 */
int (*tclpIsAtty) (int fd); /* 16 */
int (*tclUnixCopyFile) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr, int dontCopyAtts); /* 17 */
TclFile (*tclpMakeFile) (Tcl_Channel channel, int direction); /* 18 */
TclFile (*tclpOpenFile) (const char *fname, int mode); /* 19 */
void (*tclWinAddProcess) (void *hProcess, Tcl_Size id); /* 20 */
void (*reserved21)(void);
TclFile (*tclpCreateTempFile) (const char *contents); /* 22 */
void (*reserved23)(void);
char * (*tclWinNoBackslash) (char *path); /* 24 */
void (*reserved25)(void);
void (*reserved26)(void);
void (*tclWinFlushDirtyChannels) (void); /* 27 */
void (*reserved28)(void);
int (*tclWinCPUID) (int index, int *regs); /* 29 */
int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 30 */
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 0 */
int (*tclpCloseFile) (TclFile file); /* 1 */
Tcl_Channel (*tclpCreateCommandChannel) (TclFile readFile, TclFile writeFile, TclFile errorFile, int numPids, Tcl_Pid *pidPtr); /* 2 */
int (*tclpCreatePipe) (TclFile *readPipe, TclFile *writePipe); /* 3 */
int (*tclpCreateProcess) (Tcl_Interp *interp, int argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 4 */
int (*tclUnixWaitForFile_) (int fd, int mask, int timeout); /* 5 */
TclFile (*tclpMakeFile) (Tcl_Channel channel, int direction); /* 6 */
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) (TclDIR *dir); /* 10 */
void (*reserved11)(void);
void (*reserved12)(void);
void (*reserved13)(void);
int (*tclUnixCopyFile) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr, int dontCopyAtts); /* 14 */
int (*tclMacOSXGetFileAttribute) (Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr); /* 15 */
int (*tclMacOSXSetFileAttribute) (Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr); /* 16 */
int (*tclMacOSXCopyFileAttributes) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr); /* 17 */
int (*tclMacOSXMatchType) (Tcl_Interp *interp, const char *pathName, const char *fileName, Tcl_StatBuf *statBufPtr, Tcl_GlobTypeData *types); /* 18 */
void (*tclMacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 19 */
void (*reserved20)(void);
void (*reserved21)(void);
TclFile (*tclpCreateTempFile_) (const char *contents); /* 22 */
void (*reserved23)(void);
void (*reserved24)(void);
void (*reserved25)(void);
void (*reserved26)(void);
void (*reserved27)(void);
void (*reserved28)(void);
int (*tclWinCPUID) (int index, int *regs); /* 29 */
int (*tclUnixOpenTemporaryFile) (Tcl_Obj *dirObj, Tcl_Obj *basenameObj, Tcl_Obj *extensionObj, Tcl_Obj *resultingNameObj); /* 30 */
#endif /* MACOSX */
} TclIntPlatStubs;
extern const TclIntPlatStubs *tclIntPlatStubsPtr;
#ifdef __cplusplus
}
#endif
#if defined(USE_TCL_STUBS)
/*
* Inline function declarations:
*/
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(MAC_OSX_TCL) /* UNIX */
#define TclGetAndDetachPids \
(tclIntPlatStubsPtr->tclGetAndDetachPids) /* 0 */
#define TclpCloseFile \
(tclIntPlatStubsPtr->tclpCloseFile) /* 1 */
#define TclpCreateCommandChannel \
(tclIntPlatStubsPtr->tclpCreateCommandChannel) /* 2 */
#define TclpCreatePipe \
(tclIntPlatStubsPtr->tclpCreatePipe) /* 3 */
#define TclpCreateProcess \
(tclIntPlatStubsPtr->tclpCreateProcess) /* 4 */
/* Slot 5 is reserved */
#define TclpMakeFile \
(tclIntPlatStubsPtr->tclpMakeFile) /* 6 */
#define TclpOpenFile \
(tclIntPlatStubsPtr->tclpOpenFile) /* 7 */
#define TclUnixWaitForFile \
(tclIntPlatStubsPtr->tclUnixWaitForFile) /* 8 */
#define TclpCreateTempFile \
(tclIntPlatStubsPtr->tclpCreateTempFile) /* 9 */
#define TclpReaddir \
(tclIntPlatStubsPtr->tclpReaddir) /* 10 */
/* Slot 11 is reserved */
/* Slot 12 is reserved */
/* Slot 13 is reserved */
#define TclUnixCopyFile \
(tclIntPlatStubsPtr->tclUnixCopyFile) /* 14 */
#define TclMacOSXGetFileAttribute \
(tclIntPlatStubsPtr->tclMacOSXGetFileAttribute) /* 15 */
#define TclMacOSXSetFileAttribute \
(tclIntPlatStubsPtr->tclMacOSXSetFileAttribute) /* 16 */
#define TclMacOSXCopyFileAttributes \
(tclIntPlatStubsPtr->tclMacOSXCopyFileAttributes) /* 17 */
#define TclMacOSXMatchType \
(tclIntPlatStubsPtr->tclMacOSXMatchType) /* 18 */
#define TclMacOSXNotifierAddRunLoopMode \
(tclIntPlatStubsPtr->tclMacOSXNotifierAddRunLoopMode) /* 19 */
/* Slot 20 is reserved */
/* Slot 21 is reserved */
/* Slot 22 is reserved */
/* Slot 23 is reserved */
/* Slot 24 is reserved */
/* Slot 25 is reserved */
/* Slot 26 is reserved */
/* Slot 27 is reserved */
/* Slot 28 is reserved */
#define TclWinCPUID \
(tclIntPlatStubsPtr->tclWinCPUID) /* 29 */
#define TclUnixOpenTemporaryFile \
(tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */
#endif /* UNIX */
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
/* Slot 0 is reserved */
/* Slot 1 is reserved */
/* Slot 2 is reserved */
/* Slot 3 is reserved */
#define TclWinGetTclInstance \
(tclIntPlatStubsPtr->tclWinGetTclInstance) /* 4 */
#define TclUnixWaitForFile \
(tclIntPlatStubsPtr->tclUnixWaitForFile) /* 5 */
/* Slot 6 is reserved */
/* Slot 7 is reserved */
#define TclpGetPid \
(tclIntPlatStubsPtr->tclpGetPid) /* 8 */
/* Slot 9 is reserved */
/* Slot 10 is reserved */
#define TclGetAndDetachPids \
(tclIntPlatStubsPtr->tclGetAndDetachPids) /* 11 */
#define TclpCloseFile \
(tclIntPlatStubsPtr->tclpCloseFile) /* 12 */
#define TclpCreateCommandChannel \
(tclIntPlatStubsPtr->tclpCreateCommandChannel) /* 13 */
#define TclpCreatePipe \
(tclIntPlatStubsPtr->tclpCreatePipe) /* 14 */
#define TclpCreateProcess \
(tclIntPlatStubsPtr->tclpCreateProcess) /* 15 */
#define TclpIsAtty \
(tclIntPlatStubsPtr->tclpIsAtty) /* 16 */
#define TclUnixCopyFile \
(tclIntPlatStubsPtr->tclUnixCopyFile) /* 17 */
#define TclpMakeFile \
(tclIntPlatStubsPtr->tclpMakeFile) /* 18 */
#define TclpOpenFile \
(tclIntPlatStubsPtr->tclpOpenFile) /* 19 */
#define TclWinAddProcess \
(tclIntPlatStubsPtr->tclWinAddProcess) /* 20 */
/* Slot 21 is reserved */
#define TclpCreateTempFile \
(tclIntPlatStubsPtr->tclpCreateTempFile) /* 22 */
/* Slot 23 is reserved */
#define TclWinNoBackslash \
(tclIntPlatStubsPtr->tclWinNoBackslash) /* 24 */
/* Slot 25 is reserved */
/* Slot 26 is reserved */
#define TclWinFlushDirtyChannels \
(tclIntPlatStubsPtr->tclWinFlushDirtyChannels) /* 27 */
/* Slot 28 is reserved */
#define TclWinCPUID \
(tclIntPlatStubsPtr->tclWinCPUID) /* 29 */
#define TclUnixOpenTemporaryFile \
(tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
#define TclGetAndDetachPids \
(tclIntPlatStubsPtr->tclGetAndDetachPids) /* 0 */
#define TclpCloseFile \
(tclIntPlatStubsPtr->tclpCloseFile) /* 1 */
#define TclpCreateCommandChannel \
(tclIntPlatStubsPtr->tclpCreateCommandChannel) /* 2 */
#define TclpCreatePipe \
(tclIntPlatStubsPtr->tclpCreatePipe) /* 3 */
#define TclpCreateProcess \
(tclIntPlatStubsPtr->tclpCreateProcess) /* 4 */
/* Slot 5 is reserved */
#define TclpMakeFile \
(tclIntPlatStubsPtr->tclpMakeFile) /* 6 */
#define TclpOpenFile \
(tclIntPlatStubsPtr->tclpOpenFile) /* 7 */
#define TclUnixWaitForFile \
(tclIntPlatStubsPtr->tclUnixWaitForFile) /* 8 */
#define TclpCreateTempFile \
(tclIntPlatStubsPtr->tclpCreateTempFile) /* 9 */
#define TclpReaddir \
(tclIntPlatStubsPtr->tclpReaddir) /* 10 */
/* Slot 11 is reserved */
/* Slot 12 is reserved */
/* Slot 13 is reserved */
#define TclUnixCopyFile \
(tclIntPlatStubsPtr->tclUnixCopyFile) /* 14 */
#define TclMacOSXGetFileAttribute \
(tclIntPlatStubsPtr->tclMacOSXGetFileAttribute) /* 15 */
#define TclMacOSXSetFileAttribute \
(tclIntPlatStubsPtr->tclMacOSXSetFileAttribute) /* 16 */
#define TclMacOSXCopyFileAttributes \
(tclIntPlatStubsPtr->tclMacOSXCopyFileAttributes) /* 17 */
#define TclMacOSXMatchType \
(tclIntPlatStubsPtr->tclMacOSXMatchType) /* 18 */
#define TclMacOSXNotifierAddRunLoopMode \
(tclIntPlatStubsPtr->tclMacOSXNotifierAddRunLoopMode) /* 19 */
/* Slot 20 is reserved */
/* Slot 21 is reserved */
/* Slot 22 is reserved */
/* Slot 23 is reserved */
/* Slot 24 is reserved */
/* Slot 25 is reserved */
/* Slot 26 is reserved */
/* Slot 27 is reserved */
/* Slot 28 is reserved */
#define TclWinCPUID \
(tclIntPlatStubsPtr->tclWinCPUID) /* 29 */
#define TclUnixOpenTemporaryFile \
(tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */
#endif /* MACOSX */
#endif /* defined(USE_TCL_STUBS) */
#else /* TCL_MAJOR_VERSION > 8 */
/* !BEGIN!: Do not edit below this line. */
#ifdef __cplusplus
extern "C" {
#endif
/*
|
| ︙ | ︙ | |||
70 71 72 73 74 75 76 | /* Slot 14 is reserved */ /* 15 */ EXTERN int TclpCreateProcess(Tcl_Interp *interp, size_t argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 16 */ | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | /* Slot 14 is reserved */ /* 15 */ EXTERN int TclpCreateProcess(Tcl_Interp *interp, size_t argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 16 */ EXTERN int TclpIsAtty(int fd); /* 17 */ EXTERN int TclUnixCopyFile(const char *src, const char *dst, const Tcl_StatBuf *statBufPtr, int dontCopyAtts); /* Slot 18 is reserved */ /* Slot 19 is reserved */ /* 20 */ |
| ︙ | ︙ | |||
116 117 118 119 120 121 122 |
TclFile (*tclpCreateTempFile) (const char *contents); /* 9 */
void (*reserved10)(void);
void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 11 */
void (*reserved12)(void);
void (*reserved13)(void);
void (*reserved14)(void);
int (*tclpCreateProcess) (Tcl_Interp *interp, size_t argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 15 */
| | | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 |
TclFile (*tclpCreateTempFile) (const char *contents); /* 9 */
void (*reserved10)(void);
void (*tclGetAndDetachPids) (Tcl_Interp *interp, Tcl_Channel chan); /* 11 */
void (*reserved12)(void);
void (*reserved13)(void);
void (*reserved14)(void);
int (*tclpCreateProcess) (Tcl_Interp *interp, size_t argc, const char **argv, TclFile inputFile, TclFile outputFile, TclFile errorFile, Tcl_Pid *pidPtr); /* 15 */
int (*tclpIsAtty) (int fd); /* 16 */
int (*tclUnixCopyFile) (const char *src, const char *dst, const Tcl_StatBuf *statBufPtr, int dontCopyAtts); /* 17 */
void (*reserved18)(void);
void (*reserved19)(void);
void (*tclWinAddProcess) (void *hProcess, Tcl_Size id); /* 20 */
void (*reserved21)(void);
void (*reserved22)(void);
void (*reserved23)(void);
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 205 206 207 208 209 210 211 | (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ #define TclUnixOpenTemporaryFile \ (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #ifdef MAC_OSX_TCL /* not accessible on Win32/UNIX */ MODULE_SCOPE int TclMacOSXGetFileAttribute(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, | > | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | (tclIntPlatStubsPtr->tclWinCPUID) /* 29 */ #define TclUnixOpenTemporaryFile \ (tclIntPlatStubsPtr->tclUnixOpenTemporaryFile) /* 30 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* TCL_MAJOR_VERSION */ #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #ifdef MAC_OSX_TCL /* not accessible on Win32/UNIX */ MODULE_SCOPE int TclMacOSXGetFileAttribute(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, |
| ︙ | ︙ |
Changes to generic/tclInterp.c.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 | * Copyright © 2004 Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | * Copyright © 2004 Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* * A pointer to a string that holds an initialization script that if non-NULL * is evaluated in Tcl_Init() prior to the built-in initialization script * above. This variable can be modified by the function below. */ static const char *tclPreInitScript = NULL; /* Forward declaration */ struct Target; /* * Alias: * |
| ︙ | ︙ | |||
113 114 115 116 117 118 119 |
Tcl_Interp *parentInterp; /* Parent interpreter for this child. */
Tcl_HashEntry *childEntryPtr;
/* Hash entry in parents child table for this
* child interpreter. Used to find this
* record, and used when deleting the child
* interpreter to delete it from the parent's
* table. */
| | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
Tcl_Interp *parentInterp; /* Parent interpreter for this child. */
Tcl_HashEntry *childEntryPtr;
/* Hash entry in parents child table for this
* child interpreter. Used to find this
* record, and used when deleting the child
* interpreter to delete it from the parent's
* table. */
Tcl_Interp *childInterp; /* The child interpreter. */
Tcl_Command interpCmd; /* Interpreter object command. */
Tcl_HashTable aliasTable; /* Table which maps from names of commands in
* child interpreter to struct Alias defined
* below. */
} Child;
/*
|
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
* parent interpreter with the parent for each alias which directs to a
* command in the parent. These records are used to remove the source command
* for an from a child if/when the parent is deleted. They are organized in a
* doubly-linked list attached to the parent interpreter.
*/
typedef struct Target {
| | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
* parent interpreter with the parent for each alias which directs to a
* command in the parent. These records are used to remove the source command
* for an from a child if/when the parent is deleted. They are organized in a
* doubly-linked list attached to the parent interpreter.
*/
typedef struct Target {
Tcl_Command childCmd; /* Command for alias in child interp. */
Tcl_Interp *childInterp; /* Child Interpreter. */
struct Target *nextPtr; /* Next in list of target records, or NULL if
* at the end of the list of targets. */
struct Target *prevPtr; /* Previous in list of target records, or NULL
* if at the start of the list of targets. */
} Target;
|
| ︙ | ︙ | |||
264 265 266 267 268 269 270 | */ static int AliasDelete(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Obj *namePtr); static int AliasDescribe(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Obj *objPtr); static int AliasList(Tcl_Interp *interp, Tcl_Interp *childInterp); | | | | | | | | | < < < | | | < < < < < | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | */ static int AliasDelete(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Obj *namePtr); static int AliasDescribe(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Obj *objPtr); static int AliasList(Tcl_Interp *interp, Tcl_Interp *childInterp); static Tcl_ObjCmdProc AliasNRCmd; static Tcl_CmdDeleteProc AliasObjCmdDeleteProc; static Tcl_Interp * GetInterp(Tcl_Interp *interp, Tcl_Obj *pathPtr); static Tcl_Interp * GetInterp2(Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); static Tcl_InterpDeleteProc InterpInfoDeleteProc; static int ChildBgerror(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size objc, Tcl_Obj *const objv[]); static Tcl_Interp * ChildCreate(Tcl_Interp *interp, Tcl_Obj *pathPtr, int safe); static int ChildDebugCmd(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size objc, Tcl_Obj *const objv[]); static int ChildEval(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size objc, Tcl_Obj *const objv[]); static int ChildExpose(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size objc, Tcl_Obj *const objv[]); static int ChildHide(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size objc, Tcl_Obj *const objv[]); static int ChildHidden(Tcl_Interp *interp, Tcl_Interp *childInterp); static int ChildInvokeHidden(Tcl_Interp *interp, Tcl_Interp *childInterp, const char *namespaceName, Tcl_Size objc, Tcl_Obj *const objv[]); static int ChildMarkTrusted(Tcl_Interp *interp, Tcl_Interp *childInterp); static Tcl_CmdDeleteProc ChildObjCmdDeleteProc; static int ChildRecursionLimit(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size objc, Tcl_Obj *const objv[]); static int ChildCommandLimitCmd(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size consumedObjc, Tcl_Size objc, Tcl_Obj *const objv[]); static int ChildTimeLimitCmd(Tcl_Interp *interp, Tcl_Interp *childInterp, Tcl_Size consumedObjc, Tcl_Size objc, Tcl_Obj *const objv[]); static void InheritLimitsFromParent(Tcl_Interp *childInterp, Tcl_Interp *parentInterp); static void SetScriptLimitCallback(Tcl_Interp *interp, int type, Tcl_Interp *targetInterp, Tcl_Obj *scriptObj); static void CallScriptLimitCallback(void *clientData, Tcl_Interp *interp); static void DeleteScriptLimitCallback(void *clientData); static void MakeSafe(Tcl_Interp *interp); static void RunLimitHandlers(LimitHandler *handlerPtr, Tcl_Interp *interp); static void TimeLimitCallback(void *clientData); /* NRE enabling */ static Tcl_NRPostProc NRPostInvokeHidden; static Tcl_ObjCmdProc NRInterpCmd; static Tcl_ObjCmdProc NRChildCmd; /* *---------------------------------------------------------------------- * * Tcl_SetPreInitScript -- * * This routine is used to change the value of the internal variable, |
| ︙ | ︙ | |||
353 354 355 356 357 358 359 |
Tcl_SetPreInitScript(
const char *string) /* Pointer to a script. */
{
const char *prevString = tclPreInitScript;
tclPreInitScript = string;
return prevString;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
Tcl_SetPreInitScript(
const char *string) /* Pointer to a script. */
{
const char *prevString = tclPreInitScript;
tclPreInitScript = string;
return prevString;
}
/*
*----------------------------------------------------------------------
*
* Tcl_Init --
*
* This function is typically invoked by Tcl_AppInit functions to find
|
| ︙ | ︙ | |||
837 838 839 840 841 842 843 |
if (tclPreInitScript != NULL) {
if (Tcl_EvalEx(interp, tclPreInitScript, TCL_INDEX_NONE,
0 /*flags*/) == TCL_ERROR) {
goto end;
}
}
| > > > > > > > > | < | < < > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
if (tclPreInitScript != NULL) {
if (Tcl_EvalEx(interp, tclPreInitScript, TCL_INDEX_NONE,
0 /*flags*/) == TCL_ERROR) {
goto end;
}
}
/*
* In order to find init.tcl during initialization, the following script
* is invoked by Tcl_Init(). It looks in several different directories:
*
* $tcl_library - can specify a primary location, if set, no
* other locations will be checked. This is the
* recommended way for a program that embeds
* Tcl to specifically tell Tcl where to find
* an init.tcl file.
*
* $env(TCL_LIBRARY) - highest priority so user can always override
* the search path unless the application has
* specified an exact directory above
*
* $tclDefaultLibrary - INTERNAL: This variable is set by Tcl on
* those platforms where it can determine at
* runtime the directory where it expects the
* init.tcl file to be. After [tclInit] reads
* and uses this value, it [unset]s it.
* External users of Tcl should not make use of
* the variable to customize [tclInit].
*
* $tcl_libPath - OBSOLETE: This variable is no longer set by
* Tcl itself, but [tclInit] examines it in
* case some program that embeds Tcl is
* customizing [tclInit] by setting this
* variable to a list of directories in which
* to search.
*
* [tcl::pkgconfig get scriptdir,runtime]
* - the directory determined by configure to be
* the place where Tcl's script library is to
* be installed.
*
* The first directory on this path that contains a valid init.tcl script
* will be set as the value of tcl_library.
*
* Note that this entire search mechanism can be bypassed by defining an
* alternate tclInit command before calling Tcl_Init().
*/
result = Tcl_EvalEx(interp,
"if {[namespace which -command tclInit] eq \"\"} {\n"
" proc tclInit {} {\n"
" global tcl_libPath tcl_library env tclDefaultLibrary\n"
" rename tclInit {}\n"
" if {[info exists tcl_library]} {\n"
" set scripts {{set tcl_library}}\n"
" } else {\n"
" set scripts {}\n"
" if {[info exists env(TCL_LIBRARY)] && ($env(TCL_LIBRARY) ne {})} {\n"
" lappend scripts {set env(TCL_LIBRARY)}\n"
" lappend scripts {\n"
"if {[regexp ^tcl(.*)$ [file tail $env(TCL_LIBRARY)] -> tail] == 0} continue\n"
"if {$tail eq [info tclversion]} continue\n"
"file join [file dirname $env(TCL_LIBRARY)] tcl[info tclversion]}\n"
" }\n"
" lappend scripts {::tcl::zipfs::tcl_library_init}\n"
" if {[info exists tclDefaultLibrary]} {\n"
" lappend scripts {set tclDefaultLibrary}\n"
" } else {\n"
" lappend scripts {::tcl::pkgconfig get scriptdir,runtime}\n"
" }\n"
" lappend scripts {\n"
"set parentDir [file dirname [file dirname [info nameofexecutable]]]\n"
"set grandParentDir [file dirname $parentDir]\n"
"file join $parentDir lib tcl[info tclversion]} \\\n"
" {file join $grandParentDir lib tcl[info tclversion]} \\\n"
" {file join $parentDir library} \\\n"
" {file join $grandParentDir library} \\\n"
" {file join $grandParentDir tcl[info tclversion] library} \\\n"
" {file join $grandParentDir tcl[info patchlevel] library} \\\n"
" {\n"
"file join [file dirname $grandParentDir] tcl[info patchlevel] library}\n"
" if {[info exists tcl_libPath]\n"
" && [catch {llength $tcl_libPath} len] == 0} {\n"
" for {set i 0} {$i < $len} {incr i} {\n"
" lappend scripts [list lindex \\$tcl_libPath $i]\n"
" }\n"
" }\n"
" }\n"
" set dirs {}\n"
" set errors {}\n"
" foreach script $scripts {\n"
" if {[set tcl_library [eval $script]] eq \"\"} continue\n"
" set tclfile [file join $tcl_library init.tcl]\n"
" if {[file exists $tclfile]} {\n"
" if {[catch {uplevel #0 [list source $tclfile]} msg opts]} {\n"
" append errors \"$tclfile: $msg\n\"\n"
" append errors \"[dict get $opts -errorinfo]\n\"\n"
" continue\n"
" }\n"
" unset -nocomplain tclDefaultLibrary\n"
#if defined(_WIN32) && defined(STATIC_BUILD)
" package ifneeded registry 1.3.7 {\n"
" load {} Registry; package provide registry 1.3.7\n"
" }\n"
" package ifneeded dde 1.4.6 {\n"
" load {} Dde; package provide dde 1.4.6\n"
" }\n"
#endif
" return\n"
" }\n"
" lappend dirs $tcl_library\n"
" }\n"
" unset -nocomplain tclDefaultLibrary\n"
" set msg \"Cannot find a usable init.tcl in the following directories: \n\"\n"
" append msg \" $dirs\n\n\"\n"
" append msg \"$errors\n\n\"\n"
" append msg \"This probably means that Tcl wasn't installed properly.\n\"\n"
" error $msg\n"
" }\n"
"}\n"
"tclInit", TCL_INDEX_NONE, 0);
TclpSetInitialEncodings();
end:
*names = (*names)->nextPtr;
return result;
}
/*
*---------------------------------------------------------------------------
|
| ︙ | ︙ | |||
891 892 893 894 895 896 897 |
childPtr = &interpInfoPtr->child;
childPtr->parentInterp = NULL;
childPtr->childEntryPtr = NULL;
childPtr->childInterp = interp;
childPtr->interpCmd = NULL;
Tcl_InitHashTable(&childPtr->aliasTable, TCL_STRING_KEYS);
| | | < | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
childPtr = &interpInfoPtr->child;
childPtr->parentInterp = NULL;
childPtr->childEntryPtr = NULL;
childPtr->childInterp = interp;
childPtr->interpCmd = NULL;
Tcl_InitHashTable(&childPtr->aliasTable, TCL_STRING_KEYS);
Tcl_NRCreateCommand(interp, "interp", Tcl_InterpObjCmd, NRInterpCmd,
NULL, NULL);
Tcl_CallWhenDeleted(interp, InterpInfoDeleteProc, NULL);
return TCL_OK;
}
/*
*---------------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 |
*----------------------------------------------------------------------
*/
int
Tcl_InterpObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | < | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
*----------------------------------------------------------------------
*/
int
Tcl_InterpObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, NRInterpCmd, clientData, objc, objv);
}
static int
NRInterpCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Interp *childInterp;
static const char *const options[] = {
"alias", "aliases", "bgerror", "cancel",
"children", "create", "debug", "delete",
"eval", "exists", "expose", "hide",
"hidden", "issafe", "invokehidden",
"limit", "marktrusted", "recursionlimit",
"share",
#ifndef TCL_NO_DEPRECATED
"slaves",
#endif
"target", "transfer", NULL
};
static const char *const optionsNoSlaves[] = {
"alias", "aliases", "bgerror", "cancel",
"children", "create", "debug", "delete",
"eval", "exists", "expose",
"hide", "hidden", "issafe",
"invokehidden", "limit", "marktrusted", "recursionlimit",
"share", "target", "transfer",
NULL
};
enum interpOptionEnum {
OPT_ALIAS, OPT_ALIASES, OPT_BGERROR, OPT_CANCEL,
OPT_CHILDREN, OPT_CREATE, OPT_DEBUG, OPT_DELETE,
OPT_EVAL, OPT_EXISTS, OPT_EXPOSE, OPT_HIDE,
OPT_HIDDEN, OPT_ISSAFE, OPT_INVOKEHID,
OPT_LIMIT, OPT_MARKTRUSTED, OPT_RECLIMIT, OPT_SHARE,
#ifndef TCL_NO_DEPRECATED
OPT_SLAVES,
#endif
OPT_TARGET, OPT_TRANSFER
} index;
Tcl_Size i;
|
| ︙ | ︙ | |||
1072 1073 1074 1075 1076 1077 1078 |
childInterp = GetInterp(interp, objv[2]);
if (childInterp == NULL) {
return TCL_ERROR;
}
if (objc == 4) {
return AliasDescribe(interp, childInterp, objv[3]);
}
| | | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
childInterp = GetInterp(interp, objv[2]);
if (childInterp == NULL) {
return TCL_ERROR;
}
if (objc == 4) {
return AliasDescribe(interp, childInterp, objv[3]);
}
if ((objc == 5) && (TclGetString(objv[4])[0] == '\0')) {
return AliasDelete(interp, childInterp, objv[3]);
}
if (objc > 5) {
parentInterp = GetInterp(interp, objv[4]);
if (parentInterp == NULL) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
1287 1288 1289 1290 1291 1292 1293 |
return TCL_ERROR;
}
childInterp = GetInterp(interp, objv[2]);
if (childInterp == NULL) {
return TCL_ERROR;
}
return ChildEval(interp, childInterp, objc - 3, objv + 3);
| < < < < < < < < < < < | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 |
return TCL_ERROR;
}
childInterp = GetInterp(interp, objv[2]);
if (childInterp == NULL) {
return TCL_ERROR;
}
return ChildEval(interp, childInterp, objc - 3, objv + 3);
case OPT_EXISTS: {
int exists = 1;
childInterp = GetInterp2(interp, objc, objv);
if (childInterp == NULL) {
if (objc > 3) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
1569 1570 1571 1572 1573 1574 1575 |
*/
static Tcl_Interp *
GetInterp2(
Tcl_Interp *interp, /* Default interp if no interp was specified
* on the command line. */
Tcl_Size objc, /* Number of arguments. */
| | | 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 |
*/
static Tcl_Interp *
GetInterp2(
Tcl_Interp *interp, /* Default interp if no interp was specified
* on the command line. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc == 2) {
return interp;
} else if (objc == 3) {
return GetInterp(interp, objv[2]);
} else {
Tcl_WrongNumArgs(interp, 2, objv, "?path?");
|
| ︙ | ︙ | |||
1659 1660 1661 1662 1663 1664 1665 |
int
Tcl_CreateAliasObj(
Tcl_Interp *childInterp, /* Interpreter for source command. */
const char *childCmd, /* Command to install in child. */
Tcl_Interp *targetInterp, /* Interpreter for target command. */
const char *targetCmd, /* Name of target command. */
Tcl_Size objc, /* How many additional arguments? */
| | | 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 |
int
Tcl_CreateAliasObj(
Tcl_Interp *childInterp, /* Interpreter for source command. */
const char *childCmd, /* Command to install in child. */
Tcl_Interp *targetInterp, /* Interpreter for target command. */
const char *targetCmd, /* Name of target command. */
Tcl_Size objc, /* How many additional arguments? */
Tcl_Obj *const objv[]) /* Argument vector. */
{
Tcl_Obj *childObjPtr, *targetObjPtr;
int result;
childObjPtr = Tcl_NewStringObj(childCmd, -1);
Tcl_IncrRefCount(childObjPtr);
|
| ︙ | ︙ | |||
1776 1777 1778 1779 1780 1781 1782 |
Command *aliasCmdPtr;
/*
* If we are not creating or renaming an alias, then it is always OK to
* create or rename the command.
*/
| | | | | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 |
Command *aliasCmdPtr;
/*
* If we are not creating or renaming an alias, then it is always OK to
* create or rename the command.
*/
if (cmdPtr->objProc != TclAliasObjCmd
&& cmdPtr->objProc != TclLocalAliasObjCmd) {
return TCL_OK;
}
/*
* OK, we are dealing with an alias, so traverse the chain of aliases. If
* we encounter the alias we are defining (or renaming to) any in the
* chain then we have a loop.
*/
aliasPtr = (Alias *) cmdPtr->objClientData;
nextAliasPtr = aliasPtr;
while (1) {
Tcl_Obj *cmdNamePtr;
/*
* If the target of the next alias in the chain is the same as the
* source alias, we have a loop.
|
| ︙ | ︙ | |||
1832 1833 1834 1835 1836 1837 1838 | /* * Otherwise, follow the chain one step further. See if the target * command is an alias - if so, follow the loop to its target command. * Otherwise we do not have a loop. */ | | | | | 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 |
/*
* Otherwise, follow the chain one step further. See if the target
* command is an alias - if so, follow the loop to its target command.
* Otherwise we do not have a loop.
*/
if (aliasCmdPtr->objProc != TclAliasObjCmd
&& aliasCmdPtr->objProc != TclLocalAliasObjCmd) {
return TCL_OK;
}
nextAliasPtr = (Alias *) aliasCmdPtr->objClientData;
}
}
/*
*----------------------------------------------------------------------
*
* TclAliasCreate --
|
| ︙ | ︙ | |||
1867 1868 1869 1870 1871 1872 1873 |
Tcl_Interp *childInterp, /* Interp where alias cmd will live or from
* which alias will be deleted. */
Tcl_Interp *parentInterp, /* Interp in which target command will be
* invoked. */
Tcl_Obj *namePtr, /* Name of alias cmd. */
Tcl_Obj *targetCmdPtr, /* Name of target cmd. */
Tcl_Size objc, /* Additional arguments to store */
| | | 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 |
Tcl_Interp *childInterp, /* Interp where alias cmd will live or from
* which alias will be deleted. */
Tcl_Interp *parentInterp, /* Interp in which target command will be
* invoked. */
Tcl_Obj *namePtr, /* Name of alias cmd. */
Tcl_Obj *targetCmdPtr, /* Name of target cmd. */
Tcl_Size objc, /* Additional arguments to store */
Tcl_Obj *const objv[]) /* with alias. */
{
Alias *aliasPtr;
Tcl_HashEntry *hPtr;
Target *targetPtr;
Child *childPtr;
Parent *parentPtr;
Tcl_Obj **prefv;
|
| ︙ | ︙ | |||
1897 1898 1899 1900 1901 1902 1903 |
Tcl_IncrRefCount(objv[i]);
}
Tcl_Preserve(childInterp);
Tcl_Preserve(parentInterp);
if (childInterp == parentInterp) {
| | | | 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 |
Tcl_IncrRefCount(objv[i]);
}
Tcl_Preserve(childInterp);
Tcl_Preserve(parentInterp);
if (childInterp == parentInterp) {
aliasPtr->childCmd = Tcl_NRCreateCommand(childInterp,
TclGetString(namePtr), TclLocalAliasObjCmd, AliasNRCmd,
aliasPtr, AliasObjCmdDeleteProc);
} else {
aliasPtr->childCmd = Tcl_CreateObjCommand(childInterp,
TclGetString(namePtr), TclAliasObjCmd, aliasPtr,
AliasObjCmdDeleteProc);
}
if (TclPreventAliasLoop(interp, childInterp,
aliasPtr->childCmd) != TCL_OK) {
/*
|
| ︙ | ︙ | |||
2168 2169 2170 2171 2172 2173 2174 |
*----------------------------------------------------------------------
*/
static int
AliasNRCmd(
void *clientData, /* Alias record. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 |
*----------------------------------------------------------------------
*/
static int
AliasNRCmd(
void *clientData, /* Alias record. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument vector. */
{
Alias *aliasPtr = (Alias *) clientData;
Tcl_Size prefc, cmdc, i;
Tcl_Obj **prefv, **cmdv;
Tcl_Obj *listPtr;
ListRep listRep;
int flags = TCL_EVAL_INVOKE;
|
| ︙ | ︙ | |||
2221 2222 2223 2224 2225 2226 2227 |
return Tcl_NREvalObj(interp, listPtr, flags);
}
int
TclAliasObjCmd(
void *clientData, /* Alias record. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 |
return Tcl_NREvalObj(interp, listPtr, flags);
}
int
TclAliasObjCmd(
void *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 = (Alias *) clientData;
Tcl_Interp *targetInterp = aliasPtr->targetInterp;
int result;
Tcl_Size prefc, cmdc, i;
Tcl_Obj **prefv, **cmdv;
|
| ︙ | ︙ | |||
2312 2313 2314 2315 2316 2317 2318 |
#undef ALIAS_CMDV_PREALLOC
}
int
TclLocalAliasObjCmd(
void *clientData, /* Alias record. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
#undef ALIAS_CMDV_PREALLOC
}
int
TclLocalAliasObjCmd(
void *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 = (Alias *) clientData;
int result;
Tcl_Size prefc, cmdc, i;
Tcl_Obj **prefv, **cmdv;
Tcl_Obj *cmdArr[ALIAS_CMDV_PREALLOC];
|
| ︙ | ︙ | |||
2724 2725 2726 2727 2728 2729 2730 |
*/
static int
ChildBgerror(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which limit is set/queried. */
Tcl_Size objc, /* Set or Query. */
| | | 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 |
*/
static int
ChildBgerror(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which limit is set/queried. */
Tcl_Size objc, /* Set or Query. */
Tcl_Obj *const objv[]) /* Argument strings. */
{
if (objc) {
Tcl_Size length;
if (TCL_ERROR == TclListObjLength(NULL, objv[0], &length)
|| (length < 1)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
| ︙ | ︙ | |||
2813 2814 2815 2816 2817 2818 2819 |
}
childInterp = Tcl_CreateInterp();
childPtr = &INTERP_INFO(childInterp)->child;
childPtr->parentInterp = parentInterp;
childPtr->childEntryPtr = hPtr;
childPtr->childInterp = childInterp;
| | | 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 |
}
childInterp = Tcl_CreateInterp();
childPtr = &INTERP_INFO(childInterp)->child;
childPtr->parentInterp = parentInterp;
childPtr->childEntryPtr = hPtr;
childPtr->childInterp = childInterp;
childPtr->interpCmd = Tcl_NRCreateCommand(parentInterp, path,
TclChildObjCmd, NRChildCmd, childInterp, ChildObjCmdDeleteProc);
Tcl_InitHashTable(&childPtr->aliasTable, TCL_STRING_KEYS);
Tcl_SetHashValue(hPtr, childPtr);
Tcl_SetVar2(childInterp, "tcl_interactive", NULL, "0", TCL_GLOBAL_ONLY);
/*
* Inherit the recursion limit.
|
| ︙ | ︙ | |||
2898 2899 2900 2901 2902 2903 2904 |
*----------------------------------------------------------------------
*/
int
TclChildObjCmd(
void *clientData, /* Child interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 |
*----------------------------------------------------------------------
*/
int
TclChildObjCmd(
void *clientData, /* Child interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, NRChildCmd, clientData, objc, objv);
}
static int
NRChildCmd(
void *clientData, /* Child interpreter. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Interp *childInterp = (Tcl_Interp *) clientData;
static const char *const options[] = {
"alias", "aliases", "bgerror", "debug",
"eval", "expose", "hide", "hidden",
"issafe", "invokehidden", "limit", "marktrusted",
"recursionlimit", NULL
};
enum childCmdOptionsEnum {
OPT_ALIAS, OPT_ALIASES, OPT_BGERROR, OPT_DEBUG,
OPT_EVAL, OPT_EXPOSE, OPT_HIDE, OPT_HIDDEN,
OPT_ISSAFE, OPT_INVOKEHIDDEN, OPT_LIMIT, OPT_MARKTRUSTED,
OPT_RECLIMIT
} index;
if (childInterp == NULL) {
Tcl_Panic("TclChildObjCmd: interpreter has been deleted");
}
if (objc < 2) {
|
| ︙ | ︙ | |||
2944 2945 2946 2947 2948 2949 2950 |
switch (index) {
case OPT_ALIAS:
if (objc > 2) {
if (objc == 3) {
return AliasDescribe(interp, childInterp, objv[2]);
}
| | | 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 |
switch (index) {
case OPT_ALIAS:
if (objc > 2) {
if (objc == 3) {
return AliasDescribe(interp, childInterp, objv[2]);
}
if (TclGetString(objv[3])[0] == '\0') {
if (objc == 4) {
return AliasDelete(interp, childInterp, objv[2]);
}
} else {
return TclAliasCreate(interp, childInterp, interp, objv[2],
objv[3], objc - 4, objv + 4);
}
|
| ︙ | ︙ | |||
3084 3085 3086 3087 3088 3089 3090 |
return ChildMarkTrusted(interp, childInterp);
case OPT_RECLIMIT:
if (objc != 2 && objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?newlimit?");
return TCL_ERROR;
}
return ChildRecursionLimit(interp, childInterp, objc - 2, objv + 2);
| < < < < < < | 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 |
return ChildMarkTrusted(interp, childInterp);
case OPT_RECLIMIT:
if (objc != 2 && objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?newlimit?");
return TCL_ERROR;
}
return ChildRecursionLimit(interp, childInterp, objc - 2, objv + 2);
default:
TCL_UNREACHABLE();
}
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3167 3168 3169 3170 3171 3172 3173 |
static int
ChildDebugCmd(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* The child interpreter in which command
* will be evaluated. */
Tcl_Size objc, /* Number of arguments. */
| | | 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 |
static int
ChildDebugCmd(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* The child interpreter in which command
* will be evaluated. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const debugTypes[] = {
"-frame", NULL
};
enum DebugTypes {
DEBUG_TYPE_FRAME
};
|
| ︙ | ︙ | |||
3238 3239 3240 3241 3242 3243 3244 |
static int
ChildEval(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* The child interpreter in which command
* will be evaluated. */
Tcl_Size objc, /* Number of arguments. */
| | | 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 |
static int
ChildEval(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* The child interpreter in which command
* will be evaluated. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result;
/*
* TIP #285: If necessary, reset the cancellation flags for the child
* interpreter now; otherwise, canceling a script in a parent interpreter
* can result in a situation where a child interpreter can no longer
|
| ︙ | ︙ | |||
3262 3263 3264 3265 3266 3267 3268 |
if (objc == 1) {
/*
* TIP #280: Make actual argument location available to eval'd script.
*/
Interp *iPtr = (Interp *) interp;
CmdFrame *invoker = iPtr->cmdFramePtr;
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 |
if (objc == 1) {
/*
* TIP #280: Make actual argument location available to eval'd script.
*/
Interp *iPtr = (Interp *) interp;
CmdFrame *invoker = iPtr->cmdFramePtr;
int word = 0;
TclArgumentGet(interp, objv[0], &invoker, &word);
result = TclEvalObjEx(childInterp, objv[0], 0, invoker, word);
} else {
Tcl_Obj *objPtr = Tcl_ConcatObj(objc, objv);
Tcl_IncrRefCount(objPtr);
result = Tcl_EvalObjEx(childInterp, objPtr, 0);
Tcl_DecrRefCount(objPtr);
}
Tcl_TransferResult(childInterp, result, interp);
Tcl_Release(childInterp);
return result;
}
/*
*----------------------------------------------------------------------
*
* ChildExpose --
*
* Helper function to expose a command in a child interpreter.
|
| ︙ | ︙ | |||
3346 3347 3348 3349 3350 3351 3352 |
*/
static int
ChildExpose(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which command will be exposed. */
Tcl_Size objc, /* Number of arguments. */
| | | 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 |
*/
static int
ChildExpose(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which command will be exposed. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument strings. */
{
const char *name;
if (Tcl_IsSafe(interp)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"permission denied: safe interpreter cannot expose commands",
-1));
|
| ︙ | ︙ | |||
3390 3391 3392 3393 3394 3395 3396 |
*/
static int
ChildRecursionLimit(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which limit is set/queried. */
Tcl_Size objc, /* Set or Query. */
| | | 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 |
*/
static int
ChildRecursionLimit(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which limit is set/queried. */
Tcl_Size objc, /* Set or Query. */
Tcl_Obj *const objv[]) /* Argument strings. */
{
Interp *iPtr;
Tcl_WideInt limit;
if (objc) {
if (Tcl_IsSafe(interp)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("permission denied: "
|
| ︙ | ︙ | |||
3452 3453 3454 3455 3456 3457 3458 |
*/
static int
ChildHide(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which command will be exposed. */
Tcl_Size objc, /* Number of arguments. */
| | | 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 |
*/
static int
ChildHide(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* Interp in which command will be exposed. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument strings. */
{
const char *name;
if (Tcl_IsSafe(interp)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"permission denied: safe interpreter cannot hide commands",
-1));
|
| ︙ | ︙ | |||
3538 3539 3540 3541 3542 3543 3544 |
static int
ChildInvokeHidden(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* The child interpreter in which command will
* be invoked. */
const char *namespaceName, /* The namespace to use, if any. */
Tcl_Size objc, /* Number of arguments. */
| | > > < < | > > > > > > | | | | < | < < | > < | | < < < < | 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 |
static int
ChildInvokeHidden(
Tcl_Interp *interp, /* Interp for error return. */
Tcl_Interp *childInterp, /* The child interpreter in which command will
* be invoked. */
const char *namespaceName, /* The namespace to use, if any. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result = TCL_OK;
if (Tcl_IsSafe(interp)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"not allowed to invoke hidden commands from safe interpreter",
-1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP", "UNSAFE",
(char *)NULL);
return TCL_ERROR;
}
if (objc < 1) {
Tcl_Panic("need at least one word: hidden command name");
}
Tcl_Preserve(childInterp);
Tcl_AllowExceptions(childInterp);
if (namespaceName == NULL) {
NRE_callback *rootPtr = TOP_CB(childInterp);
Tcl_NRAddCallback(interp, NRPostInvokeHidden, childInterp,
rootPtr, NULL, NULL);
return TclNRInvoke(NULL, childInterp, objc, objv);
} else {
Namespace *nsPtr, *dummy1, *dummy2;
const char *tail;
result = TclGetNamespaceForQualName(childInterp, namespaceName, NULL,
TCL_FIND_ONLY_NS | TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG
| TCL_CREATE_NS_IF_UNKNOWN, &nsPtr, &dummy1, &dummy2, &tail);
if (result == TCL_OK) {
result = TclObjInvokeNamespace(childInterp, objc, objv,
(Tcl_Namespace *) nsPtr, TCL_INVOKE_HIDDEN);
}
}
Tcl_TransferResult(childInterp, result, interp);
Tcl_Release(childInterp);
return result;
}
static int
NRPostInvokeHidden(
void *data[],
Tcl_Interp *interp,
int result)
{
Tcl_Interp *childInterp = (Tcl_Interp *) data[0];
NRE_callback *rootPtr = (NRE_callback *) data[1];
if (interp != childInterp) {
result = TclNRRunCallbacks(childInterp, result, rootPtr);
Tcl_TransferResult(childInterp, result, interp);
}
Tcl_Release(childInterp);
return result;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
3660 3661 3662 3663 3664 3665 3666 |
Tcl_Interp *interp) /* Is this interpreter "safe" ? */
{
Interp *iPtr = (Interp *) interp;
if (iPtr == NULL) {
return 0;
}
| | | 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 |
Tcl_Interp *interp) /* Is this interpreter "safe" ? */
{
Interp *iPtr = (Interp *) interp;
if (iPtr == NULL) {
return 0;
}
return (iPtr->flags & SAFE_INTERP) ? 1 : 0;
}
/*
*----------------------------------------------------------------------
*
* MakeSafe --
*
|
| ︙ | ︙ | |||
3891 3892 3893 3894 3895 3896 3897 |
}
Tcl_Release(interp);
}
if ((iPtr->limit.active & TCL_LIMIT_TIME) &&
((iPtr->limit.timeGranularity == 1) ||
(ticker % iPtr->limit.timeGranularity == 0))) {
| | | | > > | > > | 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 |
}
Tcl_Release(interp);
}
if ((iPtr->limit.active & TCL_LIMIT_TIME) &&
((iPtr->limit.timeGranularity == 1) ||
(ticker % iPtr->limit.timeGranularity == 0))) {
Tcl_Time now;
Tcl_GetTime(&now);
if (iPtr->limit.time.sec < now.sec ||
(iPtr->limit.time.sec == now.sec &&
iPtr->limit.time.usec < now.usec)) {
iPtr->limit.exceeded |= TCL_LIMIT_TIME;
Tcl_Preserve(interp);
RunLimitHandlers(iPtr->limit.timeHandlers, interp);
if (iPtr->limit.time.sec > now.sec ||
(iPtr->limit.time.sec == now.sec &&
iPtr->limit.time.usec >= now.usec)) {
iPtr->limit.exceeded &= ~TCL_LIMIT_TIME;
} else if (iPtr->limit.exceeded & TCL_LIMIT_TIME) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"time limit exceeded", -1));
Tcl_SetErrorCode(interp, "TCL", "LIMIT", "TIME", (char *)NULL);
Tcl_Release(interp);
return TCL_ERROR;
|
| ︙ | ︙ | |||
4435 4436 4437 4438 4439 4440 4441 | * Also resets whether the time limit was exceeded. This might permit a * small amount of further execution in the interpreter even if the limit * itself is theoretically exceeded. * *---------------------------------------------------------------------- */ | < < < < < < < < < < < < < < < < < < < < | > | | | < | < < | < | | 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 |
* Also resets whether the time limit was exceeded. This might permit a
* small amount of further execution in the interpreter even if the limit
* itself is theoretically exceeded.
*
*----------------------------------------------------------------------
*/
void
Tcl_LimitSetTime(
Tcl_Interp *interp,
Tcl_Time *timeLimitPtr)
{
Interp *iPtr = (Interp *) interp;
Tcl_Time nextMoment;
iPtr->limit.time = *timeLimitPtr;
if (iPtr->limit.timeEvent != NULL) {
Tcl_DeleteTimerHandler(iPtr->limit.timeEvent);
}
nextMoment.sec = timeLimitPtr->sec;
nextMoment.usec = timeLimitPtr->usec+10;
if (nextMoment.usec >= 1000000) {
nextMoment.sec++;
nextMoment.usec -= 1000000;
}
iPtr->limit.timeEvent = TclCreateAbsoluteTimerHandler(&nextMoment,
TimeLimitCallback, interp);
iPtr->limit.exceeded &= ~TCL_LIMIT_TIME;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4543 4544 4545 4546 4547 4548 4549 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | < < < < < < < < < | < | 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Tcl_LimitGetTime(
Tcl_Interp *interp,
Tcl_Time *timeLimitPtr)
{
Interp *iPtr = (Interp *) interp;
*timeLimitPtr = iPtr->limit.time;
}
/*
*----------------------------------------------------------------------
*
* Tcl_LimitSetGranularity --
*
|
| ︙ | ︙ | |||
4844 4845 4846 4847 4848 4849 4850 |
iPtr->limit.active = 0;
iPtr->limit.granularityTicker = 0;
iPtr->limit.exceeded = 0;
iPtr->limit.cmdCount = 0;
iPtr->limit.cmdHandlers = NULL;
iPtr->limit.cmdGranularity = 1;
| | | 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 |
iPtr->limit.active = 0;
iPtr->limit.granularityTicker = 0;
iPtr->limit.exceeded = 0;
iPtr->limit.cmdCount = 0;
iPtr->limit.cmdHandlers = NULL;
iPtr->limit.cmdGranularity = 1;
memset(&iPtr->limit.time, 0, sizeof(Tcl_Time));
iPtr->limit.timeHandlers = NULL;
iPtr->limit.timeEvent = NULL;
iPtr->limit.timeGranularity = 10;
Tcl_InitHashTable(&iPtr->limit.callbacks,
sizeof(ScriptLimitCallbackKey) / sizeof(int));
}
|
| ︙ | ︙ | |||
4916 4917 4918 4919 4920 4921 4922 |
static int
ChildCommandLimitCmd(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Interp *childInterp, /* Interpreter being adjusted. */
Tcl_Size consumedObjc, /* Number of args already parsed. */
Tcl_Size objc, /* Total number of arguments. */
| | | 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 |
static int
ChildCommandLimitCmd(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Interp *childInterp, /* Interpreter being adjusted. */
Tcl_Size consumedObjc, /* Number of args already parsed. */
Tcl_Size objc, /* Total number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const options[] = {
"-command", "-granularity", "-value", NULL
};
enum Options {
OPT_CMD, OPT_GRAN, OPT_VAL
} index;
|
| ︙ | ︙ | |||
5105 5106 5107 5108 5109 5110 5111 |
static int
ChildTimeLimitCmd(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Interp *childInterp, /* Interpreter being adjusted. */
Tcl_Size consumedObjc, /* Number of args already parsed. */
Tcl_Size objc, /* Total number of arguments. */
| | | 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 |
static int
ChildTimeLimitCmd(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Interp *childInterp, /* Interpreter being adjusted. */
Tcl_Size consumedObjc, /* Number of args already parsed. */
Tcl_Size objc, /* Total number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const options[] = {
"-command", "-granularity", "-milliseconds", "-seconds", NULL
};
enum Options {
OPT_CMD, OPT_GRAN, OPT_MILLI, OPT_SEC
} index;
|
| ︙ | ︙ | |||
5157 5158 5159 5160 5161 5162 5163 |
TclNewObj(empty);
TclDictPut(NULL, dictPtr, options[0], empty);
}
TclDictPut(NULL, dictPtr, options[1], Tcl_NewWideIntObj(
Tcl_LimitGetGranularity(childInterp, TCL_LIMIT_TIME)));
if (Tcl_LimitTypeEnabled(childInterp, TCL_LIMIT_TIME)) {
| | | | | | 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 |
TclNewObj(empty);
TclDictPut(NULL, dictPtr, options[0], empty);
}
TclDictPut(NULL, dictPtr, options[1], Tcl_NewWideIntObj(
Tcl_LimitGetGranularity(childInterp, TCL_LIMIT_TIME)));
if (Tcl_LimitTypeEnabled(childInterp, TCL_LIMIT_TIME)) {
Tcl_Time limitMoment;
Tcl_LimitGetTime(childInterp, &limitMoment);
TclDictPut(NULL, dictPtr, options[2],
Tcl_NewWideIntObj(limitMoment.usec / 1000));
TclDictPut(NULL, dictPtr, options[3],
Tcl_NewWideIntObj(limitMoment.sec));
} else {
Tcl_Obj *empty;
TclNewObj(empty);
TclDictPut(NULL, dictPtr, options[2], empty);
TclDictPut(NULL, dictPtr, options[3], empty);
}
|
| ︙ | ︙ | |||
5196 5197 5198 5199 5200 5201 5202 |
break;
case OPT_GRAN:
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(
Tcl_LimitGetGranularity(childInterp, TCL_LIMIT_TIME)));
break;
case OPT_MILLI:
if (Tcl_LimitTypeEnabled(childInterp, TCL_LIMIT_TIME)) {
| | | | | | | | | | 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 |
break;
case OPT_GRAN:
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(
Tcl_LimitGetGranularity(childInterp, TCL_LIMIT_TIME)));
break;
case OPT_MILLI:
if (Tcl_LimitTypeEnabled(childInterp, TCL_LIMIT_TIME)) {
Tcl_Time limitMoment;
Tcl_LimitGetTime(childInterp, &limitMoment);
Tcl_SetObjResult(interp,
Tcl_NewWideIntObj(limitMoment.usec/1000));
}
break;
case OPT_SEC:
if (Tcl_LimitTypeEnabled(childInterp, TCL_LIMIT_TIME)) {
Tcl_Time limitMoment;
Tcl_LimitGetTime(childInterp, &limitMoment);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(limitMoment.sec));
}
break;
default:
TCL_UNREACHABLE();
}
return TCL_OK;
} else if ((objc-consumedObjc) & 1 /* isOdd(objc-consumedObjc) */) {
Tcl_WrongNumArgs(interp, consumedObjc, objv, "?-option value ...?");
return TCL_ERROR;
} else {
Tcl_Size i, scriptLen = 0, milliLen = 0, secLen = 0;
Tcl_Obj *scriptObj = NULL, *granObj = NULL;
Tcl_Obj *milliObj = NULL, *secObj = NULL;
int gran = 0;
Tcl_Time limitMoment;
Tcl_WideInt tmp;
Tcl_LimitGetTime(childInterp, &limitMoment);
for (i=consumedObjc ; i<objc ; i+=2) {
if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0,
&index) != TCL_OK) {
return TCL_ERROR;
}
switch (index) {
case OPT_CMD:
|
| ︙ | ︙ | |||
5266 5267 5268 5269 5270 5271 5272 |
if (tmp < 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"milliseconds must be non-negative", -1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP",
"BADVALUE", (char *)NULL);
return TCL_ERROR;
}
| | | | 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 |
if (tmp < 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"milliseconds must be non-negative", -1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP",
"BADVALUE", (char *)NULL);
return TCL_ERROR;
}
limitMoment.usec = tmp*1000;
break;
case OPT_SEC:
secObj = objv[i+1];
(void) TclGetStringFromObj(objv[i+1], &secLen);
if (secLen == 0) {
break;
}
if (TclGetWideIntFromObj(interp, objv[i+1], &tmp) != TCL_OK) {
return TCL_ERROR;
}
if (tmp < 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"seconds must be non-negative", -1));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP",
"BADVALUE", (char *)NULL);
return TCL_ERROR;
}
limitMoment.sec = (long long) tmp;
break;
default:
TCL_UNREACHABLE();
}
}
if (milliObj != NULL || secObj != NULL) {
if (milliObj != NULL) {
|
| ︙ | ︙ | |||
5316 5317 5318 5319 5320 5321 5322 |
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP",
"BADUSAGE", (char *)NULL);
return TCL_ERROR;
}
}
if (milliLen > 0 || secLen > 0) {
| > > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 |
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "INTERP",
"BADUSAGE", (char *)NULL);
return TCL_ERROR;
}
}
if (milliLen > 0 || secLen > 0) {
/*
* Force usec to be in range [0..1000000), possibly
* incrementing sec in the process. This makes it much easier
* for people to write scripts that do small time increments.
*/
limitMoment.sec += limitMoment.usec / 1000000;
limitMoment.usec %= 1000000;
Tcl_LimitSetTime(childInterp, &limitMoment);
Tcl_LimitTypeSet(childInterp, TCL_LIMIT_TIME);
} else {
Tcl_LimitTypeReset(childInterp, TCL_LIMIT_TIME);
}
}
if (scriptObj != NULL) {
SetScriptLimitCallback(interp, TCL_LIMIT_TIME, childInterp,
(scriptLen > 0 ? scriptObj : NULL));
}
if (granObj != NULL) {
Tcl_LimitSetGranularity(childInterp, TCL_LIMIT_TIME, gran);
}
return TCL_OK;
}
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclLink.c.
| ︙ | ︙ | |||
32 33 34 35 36 37 38 |
* needed during trace callbacks, since the
* actual variable may be aliased at that time
* via upvar. */
void *addr; /* Location of C variable. */
Tcl_Size bytes; /* Size of C variable array. This is 0 when
* single variables, and >0 used for array
* variables. */
| | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
* needed during trace callbacks, since the
* actual variable may be aliased at that time
* via upvar. */
void *addr; /* Location of C variable. */
Tcl_Size bytes; /* Size of C variable array. This is 0 when
* single variables, and >0 used for array
* variables. */
Tcl_Size numElems; /* Number of elements in C variable array.
* Zero for single variables. */
int type; /* Type of link (TCL_LINK_INT, etc.). */
union {
char c;
unsigned char uc;
int i;
unsigned int ui;
|
| ︙ | ︙ | |||
71 72 73 74 75 76 77 |
* avoid string conversions. */
int flags; /* Miscellaneous one-bit values; see below for
* definitions. */
} Link;
/*
* Definitions for flag bits:
| < < | | | | | < | > | | > | > > > > | | | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
* avoid string conversions. */
int flags; /* Miscellaneous one-bit values; see below for
* definitions. */
} Link;
/*
* Definitions for flag bits:
* LINK_READ_ONLY - 1 means errors should be generated if Tcl
* script attempts to write variable.
* LINK_BEING_UPDATED - 1 means that a call to Tcl_UpdateLinkedVar is
* in progress for this variable, so trace
* callbacks on the variable should be ignored.
* LINK_ALLOC_ADDR - 1 means linkPtr->addr was allocated on the
* heap.
* LINK_ALLOC_LAST - 1 means linkPtr->valueLast.p was allocated on
* the heap.
*/
#define LINK_READ_ONLY 1
#define LINK_BEING_UPDATED 2
#define LINK_ALLOC_ADDR 4
#define LINK_ALLOC_LAST 8
/*
* Forward references to functions defined later in this file:
*/
static char * LinkTraceProc(void *clientData,Tcl_Interp *interp,
const char *name1, const char *name2, int flags);
static Tcl_Obj * ObjValue(Link *linkPtr);
static void LinkFree(Link *linkPtr);
static int GetInvalidIntFromObj(Tcl_Obj *objPtr, int *intPtr);
static int GetInvalidDoubleFromObj(Tcl_Obj *objPtr,
double *doublePtr);
static int SetInvalidRealFromAny(Tcl_Interp *interp,
Tcl_Obj *objPtr);
/*
* A marker type used to flag weirdnesses so we can pass them around right.
*/
static const Tcl_ObjType invalidRealType = {
"invalidReal", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V1(TclLengthOne)
};
/*
* Convenience macro for accessing the value of the C variable pointed to by a
* link. Note that this macro produces something that may be regarded as an
* lvalue or rvalue; it may be assigned to as well as read. Also note that
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 |
{
return isinf(a)
#ifdef ACCEPT_NAN
|| isnan(a)
#endif /* ACCEPT_NAN */
;
}
| | < < < < | | | < | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
{
return isinf(a)
#ifdef ACCEPT_NAN
|| isnan(a)
#endif /* ACCEPT_NAN */
;
}
/*
* Mark an object as holding a weird double.
*/
static int
SetInvalidRealFromAny(
TCL_UNUSED(Tcl_Interp *),
Tcl_Obj *objPtr)
{
const char *str;
const char *endPtr;
|
| ︙ | ︙ | |||
599 600 601 602 603 604 605 |
objPtr->internalRep.doubleValue = doubleValue;
return TCL_OK;
}
}
}
return TCL_ERROR;
}
| | < < < < | | | | | | < | < < < < | | | | | | < | 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
objPtr->internalRep.doubleValue = doubleValue;
return TCL_OK;
}
}
}
return TCL_ERROR;
}
/*
* This function checks for integer representations, which are valid
* when linking with C variables, but which are invalid in other
* contexts in Tcl. Handled are "+", "-", "", "0x", "0b", "0d" and "0o"
* (upperand lowercase). See bug [39f6304c2e].
*/
static int
GetInvalidIntFromObj(
Tcl_Obj *objPtr,
int *intPtr)
{
Tcl_Size length;
const char *str = TclGetStringFromObj(objPtr, &length);
if ((length == 0) || ((length == 2) && (str[0] == '0')
&& strchr("xXbBoOdD", str[1]))) {
*intPtr = 0;
return TCL_OK;
} else if ((length == 1) && strchr("+-", str[0])) {
*intPtr = (str[0] == '+');
return TCL_OK;
}
return TCL_ERROR;
}
/*
* This function checks for double representations, which are valid
* when linking with C variables, but which are invalid in other
* contexts in Tcl. Handled are "+", "-", "", ".", "0x", "0b" and "0o"
* (upper- and lowercase) and sequences like "1e-". See bug [39f6304c2e].
*/
static int
GetInvalidDoubleFromObj(
Tcl_Obj *objPtr,
double *doublePtr)
{
int intValue;
|
| ︙ | ︙ | |||
685 686 687 688 689 690 691 692 693 | * Side effects: * The C variable may be updated to make it consistent with the Tcl * variable, or the Tcl variable may be overwritten to reject a * modification. * *---------------------------------------------------------------------- */ static char * LinkTraceProc( | > | | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
* Side effects:
* The C variable may be updated to make it consistent with the Tcl
* variable, or the Tcl variable may be overwritten to reject a
* modification.
*
*----------------------------------------------------------------------
*/
static char *
LinkTraceProc(
void *clientData, /* Contains information about the link. */
Tcl_Interp *interp, /* Interpreter containing Tcl variable. */
TCL_UNUSED(const char *) /*name1*/,
TCL_UNUSED(const char *) /*name2*/,
/* Links can only be made to global variables,
* so we can find them with need to resolve
* caller-supplied name in caller context. */
int flags) /* Miscellaneous additional information. */
|
| ︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 | } /* *---------------------------------------------------------------------- * * ObjValue -- * | | > | 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 |
}
/*
*----------------------------------------------------------------------
*
* ObjValue --
*
* Converts the value of a C variable to a Tcl_Obj* for use in a Tcl
* variable to which it is linked.
*
* Results:
* The return value is a pointer to a Tcl_Obj that represents the value
* of the C variable given by linkPtr.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static Tcl_Obj *
ObjValue(
Link *linkPtr) /* Structure describing linked variable. */
{
char *p;
Tcl_Obj *resultObj, **objv;
Tcl_Size i;
|
| ︙ | ︙ | |||
1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 |
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
LinkFree(
Link *linkPtr) /* Structure describing linked variable. */
{
if (linkPtr->nsPtr) {
TclNsDecrRefCount(linkPtr->nsPtr);
}
| > | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 |
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
LinkFree(
Link *linkPtr) /* Structure describing linked variable. */
{
if (linkPtr->nsPtr) {
TclNsDecrRefCount(linkPtr->nsPtr);
}
|
| ︙ | ︙ |
Changes to generic/tclListObj.c.
| ︙ | ︙ | |||
114 115 116 117 118 119 120 |
#define LISTREP_SPACE_FLAGS \
(LISTREP_SPACE_FAVOR_FRONT | LISTREP_SPACE_FAVOR_BACK \
| LISTREP_SPACE_ONLY_BACK)
/*
* Prototypes for non-inline static functions defined later in this file:
*/
| | | < | < | | > > | < | | < | | > > | | < | | | | | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
#define LISTREP_SPACE_FLAGS \
(LISTREP_SPACE_FAVOR_FRONT | LISTREP_SPACE_FAVOR_BACK \
| LISTREP_SPACE_ONLY_BACK)
/*
* Prototypes for non-inline static functions defined later in this file:
*/
static int MemoryAllocationError(Tcl_Interp *, size_t size);
static ListStore *ListStoreNew(Tcl_Size objc, Tcl_Obj *const objv[], int flags);
static int ListRepInit(Tcl_Size objc, Tcl_Obj *const objv[], int flags, ListRep *);
static int ListRepInitAttempt(Tcl_Interp *,
Tcl_Size objc,
Tcl_Obj *const objv[],
ListRep *);
static void ListRepClone(ListRep *fromRepPtr, ListRep *toRepPtr, int flags);
static void ListRepUnsharedFreeUnreferenced(const ListRep *repPtr);
static int TclListObjGetRep(Tcl_Interp *, Tcl_Obj *listPtr, ListRep *repPtr);
static void ListRepRange(ListRep *srcRepPtr,
Tcl_Size rangeStart,
Tcl_Size rangeEnd,
int preserveSrcRep,
ListRep *rangeRepPtr);
static ListStore *ListStoreReallocate(ListStore *storePtr, Tcl_Size numSlots);
static void ListRepValidate(const ListRep *repPtr, const char *file,
int lineNum);
static void DupListInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void FreeListInternalRep(Tcl_Obj *listPtr);
static int SetListFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void UpdateStringOfList(Tcl_Obj *listPtr);
static Tcl_Size ListLength(Tcl_Obj *listPtr);
/*
* The structure below defines the list Tcl object type by means of functions
* that can be invoked by generic object code.
*
* The internal representation of a list object is ListRep defined in tcl.h.
*/
|
| ︙ | ︙ | |||
167 168 169 170 171 172 173 |
(repPtr_)->spanPtr->refCount++; \
} \
} while (0)
/* Returns number of free unused slots at the back of the ListRep's ListStore */
#define ListRepNumFreeTail(repPtr_) \
((repPtr_)->storePtr->numAllocated \
| | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
(repPtr_)->spanPtr->refCount++; \
} \
} while (0)
/* Returns number of free unused slots at the back of the ListRep's ListStore */
#define ListRepNumFreeTail(repPtr_) \
((repPtr_)->storePtr->numAllocated \
- ((repPtr_)->storePtr->firstUsed + (repPtr_)->storePtr->numUsed))
/* Returns number of free unused slots at the front of the ListRep's ListStore */
#define ListRepNumFreeHead(repPtr_) ((repPtr_)->storePtr->firstUsed)
/* Returns a pointer to the slot corresponding to list index listIdx_ */
#define ListRepSlotPtr(repPtr_, listIdx_) \
(&(repPtr_)->storePtr->slots[ListRepStart(repPtr_) + (listIdx_)])
|
| ︙ | ︙ | |||
561 562 563 564 565 566 567 |
LIST_ASSERT(storePtr->firstUsed == 0);
LIST_ASSERT(shiftCount == 0);
}
LISTREP_CHECK(repPtr);
}
| | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 |
LIST_ASSERT(storePtr->firstUsed == 0);
LIST_ASSERT(shiftCount == 0);
}
LISTREP_CHECK(repPtr);
}
/*
*------------------------------------------------------------------------
*
* ListRepUnsharedShiftUp --
*
* Shifts the "in-use" contents in the ListStore for a ListRep up
* by the given number of slots. The ListStore must be unshared and
|
| ︙ | ︙ | |||
597 598 599 600 601 602 603 |
LISTREP_CHECK(repPtr);
LIST_ASSERT(!ListRepIsShared(repPtr));
LIST_COUNT_ASSERT(shiftCount);
storePtr = repPtr->storePtr;
LIST_ASSERT((storePtr->firstUsed + storePtr->numUsed + shiftCount)
| | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 |
LISTREP_CHECK(repPtr);
LIST_ASSERT(!ListRepIsShared(repPtr));
LIST_COUNT_ASSERT(shiftCount);
storePtr = repPtr->storePtr;
LIST_ASSERT((storePtr->firstUsed + storePtr->numUsed + shiftCount)
<= storePtr->numAllocated);
memmove(&storePtr->slots[storePtr->firstUsed + shiftCount],
&storePtr->slots[storePtr->firstUsed],
storePtr->numUsed * sizeof(Tcl_Obj *));
storePtr->firstUsed += shiftCount;
if (repPtr->spanPtr) {
repPtr->spanPtr->spanStart += shiftCount;
|
| ︙ | ︙ | |||
738 739 740 741 742 743 744 |
* since the returned ListStore references them.
*
*----------------------------------------------------------------------
*/
static ListStore *
ListStoreNew(
Tcl_Size objc,
| | | | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 |
* since the returned ListStore references them.
*
*----------------------------------------------------------------------
*/
static ListStore *
ListStoreNew(
Tcl_Size objc,
Tcl_Obj *const objv[],
int flags)
{
ListStore *storePtr;
Tcl_Size capacity;
/*
* First check to see if we'd overflow and try to allocate an object
* larger than our memory allocator allows.
*/
if (objc > LIST_MAX) {
if (flags & LISTREP_PANIC_ON_FAIL) {
Tcl_Panic("max length of a Tcl list exceeded");
}
return NULL;
}
storePtr = NULL;
if (flags & LISTREP_SPACE_FLAGS) {
/* Caller requests extra space front, back or both */
storePtr = (ListStore *)TclAttemptAllocElemsEx(
objc, sizeof(Tcl_Obj *), offsetof(ListStore, slots), &capacity);
} else {
/* Exact allocation */
capacity = objc;
storePtr = (ListStore *)Tcl_AttemptAlloc(LIST_SIZE(capacity));
}
if (storePtr == NULL) {
if (flags & LISTREP_PANIC_ON_FAIL) {
|
| ︙ | ︙ | |||
879 880 881 882 883 884 885 |
* resulting list now refers to them.
*
*----------------------------------------------------------------------
*/
static int
ListRepInit(
Tcl_Size objc,
| | | 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 |
* resulting list now refers to them.
*
*----------------------------------------------------------------------
*/
static int
ListRepInit(
Tcl_Size objc,
Tcl_Obj *const objv[],
int flags,
ListRep *repPtr)
{
ListStore *storePtr;
storePtr = ListStoreNew(objc, objv, flags);
if (storePtr) {
|
| ︙ | ︙ | |||
934 935 936 937 938 939 940 |
*
*----------------------------------------------------------------------
*/
static int
ListRepInitAttempt(
Tcl_Interp *interp,
Tcl_Size objc,
| | | 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 |
*
*----------------------------------------------------------------------
*/
static int
ListRepInitAttempt(
Tcl_Interp *interp,
Tcl_Size objc,
Tcl_Obj *const objv[],
ListRep *repPtr)
{
int result = ListRepInit(objc, objv, 0, repPtr);
if (result != TCL_OK && interp != NULL) {
if (objc > LIST_MAX) {
TclListLimitExceededError(interp);
|
| ︙ | ︙ | |||
1039 1040 1041 1042 1043 1044 1045 |
/* Collect garbage at back */
count = (storePtr->firstUsed + storePtr->numUsed)
- (spanPtr->spanStart + spanPtr->spanLength);
LIST_COUNT_ASSERT(count);
if (count > 0) {
/* T:listrep-6.{1:8} */
ObjArrayDecrRefs(
| | | 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 |
/* Collect garbage at back */
count = (storePtr->firstUsed + storePtr->numUsed)
- (spanPtr->spanStart + spanPtr->spanLength);
LIST_COUNT_ASSERT(count);
if (count > 0) {
/* T:listrep-6.{1:8} */
ObjArrayDecrRefs(
storePtr->slots, spanPtr->spanStart + spanPtr->spanLength, count);
LIST_ASSERT(storePtr->numUsed >= count);
storePtr->numUsed -= count;
}
LIST_ASSERT(ListRepStart(repPtr) == storePtr->firstUsed);
LIST_ASSERT(ListRepLength(repPtr) == storePtr->numUsed);
LISTREP_CHECK(repPtr);
|
| ︙ | ︙ | |||
1081 1082 1083 1084 1085 1086 1087 |
#ifdef TCL_MEM_DEBUG
#undef Tcl_NewListObj
Tcl_Obj *
Tcl_NewListObj(
Tcl_Size objc, /* Count of objects referenced by objv. */
| | | | 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 |
#ifdef TCL_MEM_DEBUG
#undef Tcl_NewListObj
Tcl_Obj *
Tcl_NewListObj(
Tcl_Size objc, /* Count of objects referenced by objv. */
Tcl_Obj *const objv[]) /* An array of pointers to Tcl objects. */
{
return Tcl_DbNewListObj(objc, objv, "unknown", 0);
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_NewListObj(
Tcl_Size objc, /* Count of objects referenced by objv. */
Tcl_Obj *const objv[]) /* An array of pointers to Tcl objects. */
{
ListRep listRep;
Tcl_Obj *listObj;
TclNewObj(listObj);
if (objc <= 0) {
|
| ︙ | ︙ | |||
1143 1144 1145 1146 1147 1148 1149 |
*/
#ifdef TCL_MEM_DEBUG
Tcl_Obj *
Tcl_DbNewListObj(
Tcl_Size objc, /* Count of objects referenced by objv. */
| | | 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 |
*/
#ifdef TCL_MEM_DEBUG
Tcl_Obj *
Tcl_DbNewListObj(
Tcl_Size objc, /* Count of objects referenced by objv. */
Tcl_Obj *const objv[], /* An array of pointers to Tcl objects. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
{
Tcl_Obj *listObj;
ListRep listRep;
|
| ︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 |
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_DbNewListObj(
Tcl_Size objc, /* Count of objects referenced by objv. */
| | | 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 |
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_DbNewListObj(
Tcl_Size objc, /* Count of objects referenced by objv. */
Tcl_Obj *const objv[], /* An array of pointers to Tcl objects. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
{
return Tcl_NewListObj(objc, objv);
}
#endif /* TCL_MEM_DEBUG */
|
| ︙ | ︙ | |||
1305 1306 1307 1308 1309 1310 1311 |
*
*----------------------------------------------------------------------
*/
void
Tcl_SetListObj(
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
Tcl_Size objc, /* Count of objects referenced by objv. */
| | | 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 |
*
*----------------------------------------------------------------------
*/
void
Tcl_SetListObj(
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
Tcl_Size objc, /* Count of objects referenced by objv. */
Tcl_Obj *const objv[]) /* An array of pointers to Tcl objects. */
{
if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetListObj");
}
/*
* Set the object's type to "list" and initialize the internal rep.
|
| ︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 |
*------------------------------------------------------------------------
*/
static void
ListRepRange(
ListRep *srcRepPtr, /* Contains source of the range */
Tcl_Size rangeStart, /* Index of first element to include */
Tcl_Size rangeEnd, /* Index of last element to include */
| | | 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 |
*------------------------------------------------------------------------
*/
static void
ListRepRange(
ListRep *srcRepPtr, /* Contains source of the range */
Tcl_Size rangeStart, /* Index of first element to include */
Tcl_Size rangeEnd, /* Index of last element to include */
int preserveSrcRep, /* If true, srcRepPtr contents must not be
* modified (generally because a shared Tcl_Obj
* references it) */
ListRep *rangeRepPtr) /* Output. Must NOT be == srcRepPtr */
{
Tcl_Obj **srcElems;
Tcl_Size numSrcElems = ListRepLength(srcRepPtr);
Tcl_Size rangeLen;
|
| ︙ | ︙ | |||
1544 1545 1546 1547 1548 1549 1550 |
/* Assert: Because numSrcElems > rangeEnd earlier */
if (numAfterRangeEnd != 0) {
/* T:listrep-3.17 */
ObjArrayDecrRefs(srcElems, rangeEnd + 1, numAfterRangeEnd);
}
memmove(&srcRepPtr->storePtr->slots[0],
&srcRepPtr->storePtr
| | | 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 |
/* Assert: Because numSrcElems > rangeEnd earlier */
if (numAfterRangeEnd != 0) {
/* T:listrep-3.17 */
ObjArrayDecrRefs(srcElems, rangeEnd + 1, numAfterRangeEnd);
}
memmove(&srcRepPtr->storePtr->slots[0],
&srcRepPtr->storePtr
->slots[srcRepPtr->storePtr->firstUsed + rangeStart],
rangeLen * sizeof(Tcl_Obj *));
srcRepPtr->storePtr->firstUsed = 0;
srcRepPtr->storePtr->numUsed = rangeLen;
srcRepPtr->storePtr->flags = 0;
if (srcRepPtr->spanPtr) {
/* In case the source has a span, update it for consistency */
/* T:listrep-3.{15,17} */
|
| ︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 |
Tcl_Obj *listObj, /* List object to take a range from. */
Tcl_Size rangeStart, /* Index of first element to include. */
Tcl_Size rangeEnd) /* Index of last element to include. */
{
ListRep listRep;
ListRep resultRep;
| | | | 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 |
Tcl_Obj *listObj, /* List object to take a range from. */
Tcl_Size rangeStart, /* Index of first element to include. */
Tcl_Size rangeEnd) /* Index of last element to include. */
{
ListRep listRep;
ListRep resultRep;
int isShared;
if (TclListObjGetRep(interp, listObj, &listRep) != TCL_OK) {
return NULL;
}
isShared = Tcl_IsShared(listObj);
ListRepRange(&listRep, rangeStart, rangeEnd, isShared, &resultRep);
if (isShared) {
/* T:listrep-1.10.1,2.{4.2,4.3,5.2,5.3,6.2,7.2,8.1} */
TclNewObj(listObj);
} /* T:listrep-1.{4.3,5.1,5.2} */
|
| ︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 |
*/
ListObjStompRep(toObj, &listRep);
} /* else T:listrep-3.{4,5} */
LIST_ASSERT(listRep.storePtr->numAllocated >= finalLen);
/* Current store big enough */
numTailFree = ListRepNumFreeTail(&listRep);
LIST_ASSERT((numTailFree + listRep.storePtr->firstUsed)
| | | 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 |
*/
ListObjStompRep(toObj, &listRep);
} /* else T:listrep-3.{4,5} */
LIST_ASSERT(listRep.storePtr->numAllocated >= finalLen);
/* Current store big enough */
numTailFree = ListRepNumFreeTail(&listRep);
LIST_ASSERT((numTailFree + listRep.storePtr->firstUsed)
>= elemCount); /* Total free */
if (numTailFree < elemCount) {
/* Not enough room at back. Move some to front */
/* T:listrep-3.5 */
Tcl_Size shiftCount = elemCount - numTailFree;
/* Divide remaining space between front and back */
shiftCount += (listRep.storePtr->numAllocated - finalLen) / 2;
LIST_ASSERT(shiftCount <= listRep.storePtr->firstUsed);
|
| ︙ | ︙ | |||
2043 2044 2045 2046 2047 2048 2049 |
/* Empty string => empty list. Avoid unnecessary shimmering */
if (listObj->bytes == &tclEmptyString) {
*objPtrPtr = NULL;
return TCL_OK;
}
| | | 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 |
/* Empty string => empty list. Avoid unnecessary shimmering */
if (listObj->bytes == &tclEmptyString) {
*objPtrPtr = NULL;
return TCL_OK;
}
int hasAbstractList = TclObjTypeHasProc(listObj,indexProc) != 0;
if (hasAbstractList) {
return TclObjTypeIndex(interp, listObj, index, objPtrPtr);
}
if (TclListObjGetElements(interp, listObj, &numElems, &elemObjs) != TCL_OK) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2254 2255 2256 2257 2258 2259 2260 |
TclInvalidateStringRep(listObj);
return TCL_OK;
}
if (first == 0) {
/* Delete from front, so return tail. */
/* T:listrep-1.{4,5},2.{4,5},3.{15,16},4.7 */
ListRep tailRep;
| | | | 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 |
TclInvalidateStringRep(listObj);
return TCL_OK;
}
if (first == 0) {
/* Delete from front, so return tail. */
/* T:listrep-1.{4,5},2.{4,5},3.{15,16},4.7 */
ListRep tailRep;
ListRepRange(&listRep, numToDelete, origListLen-1, 0, &tailRep);
ListObjReplaceRepAndInvalidate(listObj, &tailRep);
return TCL_OK;
} else if ((first+numToDelete) >= origListLen) {
/* Delete from tail, so return head */
/* T:listrep-1.{8,9},2.{6,7},3.{17,18},4.8 */
ListRep headRep;
ListRepRange(&listRep, 0, first-1, 0, &headRep);
ListObjReplaceRepAndInvalidate(listObj, &headRep);
return TCL_OK;
}
/* Deletion from middle. Fall through to general case */
}
/* Garbage collect before checking the pure insert optimization */
|
| ︙ | ︙ | |||
2901 2902 2903 2904 2905 2906 2907 |
* indexArgPtr designates something that is neither an index nor a
* well formed list. Report the error via TclLsetFlat.
*/
retValueObj = TclLsetFlat(interp,
listObj, 1, &indexArgObj, valueObj);
} else if (TCL_OK != TclListObjGetElements(interp,
indexListCopy, &indexCount, &indices)) {
| | | | | | | | | | | | | 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 |
* indexArgPtr designates something that is neither an index nor a
* well formed list. Report the error via TclLsetFlat.
*/
retValueObj = TclLsetFlat(interp,
listObj, 1, &indexArgObj, valueObj);
} else if (TCL_OK != TclListObjGetElements(interp,
indexListCopy, &indexCount, &indices)) {
Tcl_DecrRefCount(indexListCopy);
/*
* indexArgPtr designates something that is neither an index nor a
* well formed list. Report the error via TclLsetFlat.
*/
retValueObj = TclLsetFlat(interp,
listObj, 1, &indexArgObj, valueObj);
} else {
/*
* Let TclLsetFlat perform the actual lset operation.
*/
retValueObj = TclLsetFlat(interp,
listObj, indexCount, indices, valueObj);
if (indexListCopy) {
Tcl_DecrRefCount(indexListCopy);
}
}
}
assert (retValueObj==NULL || retValueObj->typePtr || retValueObj->bytes);
return retValueObj;
}
|
| ︙ | ︙ | |||
3253 3254 3255 3256 3257 3258 3259 |
}
elemCount = ListRepLength(&listRep);
/* Ensure that the index is in bounds. */
if ((index < 0) || (index >= elemCount)) {
if (interp != NULL) {
| | | | 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 |
}
elemCount = ListRepLength(&listRep);
/* Ensure that the index is in bounds. */
if ((index < 0) || (index >= elemCount)) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"index \"%" TCL_SIZE_MODIFIER "d\" out of range", index));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX", "OUTOFRANGE", (char *)NULL);
}
return TCL_ERROR;
}
/*
* Note - garbage collect this only AFTER checking indices above.
|
| ︙ | ︙ | |||
3318 3319 3320 3321 3322 3323 3324 |
Tcl_Obj *listObj) /* List object with internal rep to free. */
{
ListRep listRep;
ListObjGetRep(listObj, &listRep);
if (listRep.storePtr->refCount-- <= 1) {
ObjArrayDecrRefs(
| | | | 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 |
Tcl_Obj *listObj) /* List object with internal rep to free. */
{
ListRep listRep;
ListObjGetRep(listObj, &listRep);
if (listRep.storePtr->refCount-- <= 1) {
ObjArrayDecrRefs(
listRep.storePtr->slots,
listRep.storePtr->firstUsed, listRep.storePtr->numUsed);
Tcl_Free(listRep.storePtr);
}
if (listRep.spanPtr) {
ListSpanDecrRefs(listRep.spanPtr);
}
}
|
| ︙ | ︙ | |||
3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 |
}
Tcl_IncrRefCount(*elemPtrs++);/* Since list now holds ref to it. */
}
LIST_ASSERT((Tcl_Size)(elemPtrs - listRep.storePtr->slots) == elemCount);
listRep.storePtr->numUsed = elemCount;
} else {
Tcl_Size estCount, length;
const char *limit, *nextElem = TclGetStringFromObj(objPtr, &length);
/*
* Allocate enough space to hold a (Tcl_Obj *) for each
* (possible) list element.
| > | 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 |
}
Tcl_IncrRefCount(*elemPtrs++);/* Since list now holds ref to it. */
}
LIST_ASSERT((Tcl_Size)(elemPtrs - listRep.storePtr->slots) == elemCount);
listRep.storePtr->numUsed = elemCount;
} else {
Tcl_Size estCount, length;
const char *limit, *nextElem = TclGetStringFromObj(objPtr, &length);
/*
* Allocate enough space to hold a (Tcl_Obj *) for each
* (possible) list element.
|
| ︙ | ︙ |
Deleted generic/tclListTypes.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to generic/tclLiteral.c.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 | #define REBUILD_MULTIPLIER 3 /* * Function prototypes for static functions in this file: */ static size_t AddLocalLiteralEntry(CompileEnv *envPtr, | | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #define REBUILD_MULTIPLIER 3 /* * Function prototypes for static functions in this file: */ static size_t AddLocalLiteralEntry(CompileEnv *envPtr, Tcl_Obj *objPtr, int localHash); static void ExpandLocalLiteralArray(CompileEnv *envPtr); static size_t HashString(const char *string, size_t length); #ifdef TCL_COMPILE_DEBUG static LiteralEntry * LookupLiteralEntry(Tcl_Interp *interp, Tcl_Obj *objPtr); #endif static void RebuildLiteralTable(LiteralTable *tablePtr); /* |
| ︙ | ︙ | |||
54 55 56 57 58 59 60 | * The literal table is made ready for use. * *---------------------------------------------------------------------- */ void TclInitLiteralTable( | | > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
* The literal table is made ready for use.
*
*----------------------------------------------------------------------
*/
void
TclInitLiteralTable(
LiteralTable *tablePtr)
/* Pointer to table structure, which is
* supplied by the caller. */
{
#if (TCL_SMALL_HASH_TABLE != 4)
Tcl_Panic("%s: TCL_SMALL_HASH_TABLE is %d, not 4", "TclInitLiteralTable",
TCL_SMALL_HASH_TABLE);
#endif
|
| ︙ | ︙ | |||
171 172 173 174 175 176 177 |
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclCreateLiteral(
Interp *iPtr,
| | | | | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclCreateLiteral(
Interp *iPtr,
const char *bytes, /* The start of the string. Note that this is
* not a NUL-terminated string. */
Tcl_Size length, /* Number of bytes in the string. */
size_t hash, /* The string's hash. If the value is
* TCL_INDEX_NONE, it will be computed here. */
int *newPtr,
Namespace *nsPtr,
int flags,
LiteralEntry **globalPtrPtr)
{
LiteralTable *globalTablePtr = &iPtr->literalTable;
LiteralEntry *globalPtr;
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
* The literal is new to the interpreter.
*/
TclNewObj(objPtr);
if ((flags & LITERAL_ON_HEAP)) {
objPtr->bytes = (char *) bytes;
objPtr->length = length;
| > | < < | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
* The literal is new to the interpreter.
*/
TclNewObj(objPtr);
if ((flags & LITERAL_ON_HEAP)) {
objPtr->bytes = (char *) bytes;
objPtr->length = length;
} else {
TclInitStringRep(objPtr, bytes, length);
}
/* Should the new literal be shared globally? */
if ((flags & LITERAL_UNSHARED)) {
/*
* No, do *not* add it the global literal table
|
| ︙ | ︙ | |||
385 386 387 388 389 390 391 | * buffer holding the result of backslash substitutions. * *---------------------------------------------------------------------- */ int /* Do NOT change this type. Should not be wider than TclEmitPush operand*/ TclRegisterLiteral( | | | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
* buffer holding the result of backslash substitutions.
*
*----------------------------------------------------------------------
*/
int /* Do NOT change this type. Should not be wider than TclEmitPush operand*/
TclRegisterLiteral(
void *ePtr, /* Points to the CompileEnv in whose object
* array an object is found or created. */
const char *bytes, /* Points to string for which to find or
* create an object in CompileEnv's object
* array. */
Tcl_Size length, /* Number of bytes in the string. If -1, the
* string consists of all bytes up to the
* first null character. */
int flags) /* If LITERAL_ON_HEAP then the caller already
* malloc'd bytes and ownership is passed to
* this function. If LITERAL_CMD_NAME then
* the literal should not be shared across
* namespaces. */
|
| ︙ | ︙ | |||
436 437 438 439 440 441 442 |
#ifdef TCL_COMPILE_DEBUG
TclVerifyLocalLiteralTable(envPtr);
#endif /*TCL_COMPILE_DEBUG*/
if (objIndex > INT_MAX) {
Tcl_Panic("Literal table index too large. Cannot be handled by TclEmitPush");
}
| | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
#ifdef TCL_COMPILE_DEBUG
TclVerifyLocalLiteralTable(envPtr);
#endif /*TCL_COMPILE_DEBUG*/
if (objIndex > INT_MAX) {
Tcl_Panic("Literal table index too large. Cannot be handled by TclEmitPush");
}
return objIndex;
}
}
/*
* The literal is new to this CompileEnv. If it is a command name, avoid
* sharing it across namespaces, and try not to share it with non-cmd
* literals. Note that FQ command names can be shared, so that we register
|
| ︙ | ︙ | |||
475 476 477 478 479 480 481 |
Tcl_Panic("%s: global literal \"%.*s\" had bad refCount %" TCL_Z_MODIFIER "u",
"TclRegisterLiteral", (length>60? 60 : (int)length), bytes,
globalPtr->refCount);
}
TclVerifyLocalLiteralTable(envPtr);
#endif /*TCL_COMPILE_DEBUG*/
if (objIndex > INT_MAX) {
| | | | | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
Tcl_Panic("%s: global literal \"%.*s\" had bad refCount %" TCL_Z_MODIFIER "u",
"TclRegisterLiteral", (length>60? 60 : (int)length), bytes,
globalPtr->refCount);
}
TclVerifyLocalLiteralTable(envPtr);
#endif /*TCL_COMPILE_DEBUG*/
if (objIndex > INT_MAX) {
Tcl_Panic(
"Literal table index too large. Cannot be handled by TclEmitPush");
}
return objIndex;
}
#ifdef TCL_COMPILE_DEBUG
/*
*----------------------------------------------------------------------
*
* LookupLiteralEntry --
|
| ︙ | ︙ | |||
503 504 505 506 507 508 509 |
*----------------------------------------------------------------------
*/
static LiteralEntry *
LookupLiteralEntry(
Tcl_Interp *interp, /* Interpreter for which objPtr was created to
* hold a literal. */
| | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
*----------------------------------------------------------------------
*/
static LiteralEntry *
LookupLiteralEntry(
Tcl_Interp *interp, /* Interpreter for which objPtr was created to
* hold a literal. */
Tcl_Obj *objPtr) /* Points to a Tcl object holding a literal
* that was previously created by a call to
* TclRegisterLiteral. */
{
Interp *iPtr = (Interp *) interp;
LiteralTable *globalTablePtr = &iPtr->literalTable;
LiteralEntry *entryPtr;
const char *bytes;
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 |
*----------------------------------------------------------------------
*/
void
TclHideLiteral(
Tcl_Interp *interp, /* Interpreter for which objPtr was created to
* hold a literal. */
| | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
*----------------------------------------------------------------------
*/
void
TclHideLiteral(
Tcl_Interp *interp, /* Interpreter for which objPtr was created to
* hold a literal. */
CompileEnv *envPtr,/* Points to CompileEnv whose literal array
* contains the entry being hidden. */
int index) /* The index of the entry in the literal
* array. */
{
LiteralEntry **nextPtrPtr, *entryPtr, *lPtr;
LiteralTable *localTablePtr = &envPtr->localLitTable;
size_t localHash;
|
| ︙ | ︙ | |||
613 614 615 616 617 618 619 | * literal object. * *---------------------------------------------------------------------- */ int TclAddLiteralObj( | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
* literal object.
*
*----------------------------------------------------------------------
*/
int
TclAddLiteralObj(
CompileEnv *envPtr,/* Points to CompileEnv in whose literal array
* the object is to be inserted. */
Tcl_Obj *objPtr, /* The object to insert into the array. */
LiteralEntry **litPtrPtr) /* The location where the pointer to the new
* literal entry should be stored. May be
* NULL. */
{
LiteralEntry *lPtr;
size_t objIndex;
if (envPtr->literalArrayNext >= envPtr->literalArrayEnd) {
ExpandLocalLiteralArray(envPtr);
}
objIndex = envPtr->literalArrayNext;
envPtr->literalArrayNext++;
if (objIndex > INT_MAX) {
Tcl_Panic(
"Literal table index too large. Cannot be handled by TclEmitPush");
}
lPtr = &envPtr->literalArrayPtr[objIndex];
lPtr->objPtr = objPtr;
Tcl_IncrRefCount(objPtr);
lPtr->refCount = TCL_INDEX_NONE; /* i.e., unused */
lPtr->nextPtr = NULL;
if (litPtrPtr) {
*litPtrPtr = lPtr;
}
return objIndex;
}
/*
*----------------------------------------------------------------------
*
* AddLocalLiteralEntry --
*
|
| ︙ | ︙ | |||
708 709 710 711 712 713 714 | * array of the CompileEnv's literal array if it becomes too large. * *---------------------------------------------------------------------- */ static size_t AddLocalLiteralEntry( | | | | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
* array of the CompileEnv's literal array if it becomes too large.
*
*----------------------------------------------------------------------
*/
static size_t
AddLocalLiteralEntry(
CompileEnv *envPtr,/* Points to CompileEnv in whose literal array
* the object is to be inserted. */
Tcl_Obj *objPtr, /* The literal to add to the CompileEnv. */
int localHash) /* Hash value for the literal's string. */
{
LiteralTable *localTablePtr = &envPtr->localLitTable;
LiteralEntry *localPtr;
size_t objIndex;
objIndex = TclAddLiteralObj(envPtr, objPtr, &localPtr);
|
| ︙ | ︙ | |||
787 788 789 790 791 792 793 | * The local literal table is updated to refer to the new entries. * *---------------------------------------------------------------------- */ static void ExpandLocalLiteralArray( | | | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 |
* The local literal table is updated to refer to the new entries.
*
*----------------------------------------------------------------------
*/
static void
ExpandLocalLiteralArray(
CompileEnv *envPtr)/* Points to the CompileEnv whose object array
* must be enlarged. */
{
/*
* The current allocated local literal entries are stored between elements
* 0 and (envPtr->literalArrayNext - 1) [inclusive].
*/
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 |
*----------------------------------------------------------------------
*/
void
TclReleaseLiteral(
Tcl_Interp *interp, /* Interpreter for which objPtr was created to
* hold a literal. */
| | | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 |
*----------------------------------------------------------------------
*/
void
TclReleaseLiteral(
Tcl_Interp *interp, /* Interpreter for which objPtr was created to
* hold a literal. */
Tcl_Obj *objPtr) /* Points to a literal object that was
* previously created by a call to
* TclRegisterLiteral. */
{
Interp *iPtr = (Interp *) interp;
LiteralTable *globalTablePtr;
LiteralEntry *entryPtr, *prevPtr;
const char *bytes;
|
| ︙ | ︙ | |||
949 950 951 952 953 954 955 | * None. * *---------------------------------------------------------------------- */ static size_t HashString( | | | | 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 |
* None.
*
*----------------------------------------------------------------------
*/
static size_t
HashString(
const char *string, /* String for which to compute hash value. */
size_t length) /* Number of bytes in the string. */
{
size_t result = 0;
/*
* I tried a zillion different hash functions and asked many other people
* for advice. Many people had their own favorite functions, all
* different, but no-one had much idea why they were good ones. I chose
|
| ︙ | ︙ | |||
1013 1014 1015 1016 1017 1018 1019 | * Memory gets reallocated and entries get rehashed into new buckets. * *---------------------------------------------------------------------- */ static void RebuildLiteralTable( | | > | 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 |
* Memory gets reallocated and entries get rehashed into new buckets.
*
*----------------------------------------------------------------------
*/
static void
RebuildLiteralTable(
LiteralTable *tablePtr)
/* Local or global table to enlarge. */
{
LiteralEntry **oldBuckets;
LiteralEntry **oldChainPtr, **newChainPtr;
LiteralEntry *entryPtr;
LiteralEntry **bucketPtr;
const char *bytes;
size_t oldSize, count, index;
|
| ︙ | ︙ |
Changes to generic/tclLoad.c.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 |
LoadedLibrary *libraryPtr; /* Points to detailed information about
* library. */
struct InterpLibrary *nextPtr;
/* Next library in this interpreter, or NULL
* for end of list. */
} InterpLibrary;
| < < < < < < | | | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
LoadedLibrary *libraryPtr; /* Points to detailed information about
* library. */
struct InterpLibrary *nextPtr;
/* Next library in this interpreter, or NULL
* for end of list. */
} InterpLibrary;
/*
* Prototypes for functions that are private to this file:
*/
static void LoadCleanupProc(void *clientData,
Tcl_Interp *interp);
static int IsStatic(LoadedLibrary *libraryPtr);
static int UnloadLibrary(Tcl_Interp *interp, Tcl_Interp *target,
LoadedLibrary *library, int keepLibrary,
const char *fullFileName, int interpExiting);
static int
IsStatic(
LoadedLibrary *libraryPtr)
{
return (libraryPtr->fileName[0] == '\0');
}
/*
|
| ︙ | ︙ | |||
126 127 128 129 130 131 132 |
*----------------------------------------------------------------------
*/
int
Tcl_LoadObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < | < | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
*----------------------------------------------------------------------
*/
int
Tcl_LoadObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Interp *target;
LoadedLibrary *libraryPtr, *defaultPtr;
Tcl_DString pfx, tmp, initName, safeInitName;
Tcl_DString unloadName, safeUnloadName;
InterpLibrary *ipFirstPtr, *ipPtr;
int code, namesMatch, filesMatch, offset;
const char *symbols[2];
Tcl_LibraryInitProc *initProc;
const char *p, *fullFileName, *prefix;
Tcl_LoadHandle loadHandle;
Tcl_UniChar ch = 0;
size_t len;
int flags = 0;
|
| ︙ | ︙ | |||
233 234 235 236 237 238 239 |
*/
Tcl_MutexLock(&libraryMutex);
defaultPtr = NULL;
for (libraryPtr = firstLibraryPtr; libraryPtr != NULL; libraryPtr = libraryPtr->nextPtr) {
if (prefix == NULL) {
| | | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
*/
Tcl_MutexLock(&libraryMutex);
defaultPtr = NULL;
for (libraryPtr = firstLibraryPtr; libraryPtr != NULL; libraryPtr = libraryPtr->nextPtr) {
if (prefix == NULL) {
namesMatch = 0;
} else {
TclDStringClear(&pfx);
Tcl_DStringAppend(&pfx, prefix, -1);
TclDStringClear(&tmp);
Tcl_DStringAppend(&tmp, libraryPtr->prefix, -1);
if (strcmp(Tcl_DStringValue(&tmp),
Tcl_DStringValue(&pfx)) == 0) {
namesMatch = 1;
} else {
namesMatch = 0;
}
}
TclDStringClear(&pfx);
filesMatch = (strcmp(libraryPtr->fileName, fullFileName) == 0);
if (filesMatch && (namesMatch || (prefix == NULL))) {
break;
|
| ︙ | ︙ | |||
282 283 284 285 286 287 288 |
/*
* Scan through the list of libraries already loaded in the target
* interpreter. If the library we want is already loaded there, then
* there's nothing for us to do.
*/
if (libraryPtr != NULL) {
| | | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
/*
* Scan through the list of libraries already loaded in the target
* interpreter. If the library we want is already loaded there, then
* there's nothing for us to do.
*/
if (libraryPtr != NULL) {
ipFirstPtr = (InterpLibrary *)Tcl_GetAssocData(target, "tclLoad", NULL);
for (ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
if (ipPtr->libraryPtr == libraryPtr) {
code = TCL_OK;
goto done;
}
}
}
|
| ︙ | ︙ | |||
518 519 520 521 522 523 524 |
Tcl_MutexUnlock(&libraryMutex);
/*
* Refetch ipFirstPtr: loading the library may have introduced additional
* static libraries at the head of the linked list!
*/
| | | | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
Tcl_MutexUnlock(&libraryMutex);
/*
* Refetch ipFirstPtr: loading the library may have introduced additional
* static libraries at the head of the linked list!
*/
ipFirstPtr = (InterpLibrary *)Tcl_GetAssocData(target, "tclLoad", NULL);
ipPtr = (InterpLibrary *)Tcl_Alloc(sizeof(InterpLibrary));
ipPtr->libraryPtr = libraryPtr;
ipPtr->nextPtr = ipFirstPtr;
Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc, ipPtr);
done:
Tcl_DStringFree(&pfx);
Tcl_DStringFree(&initName);
Tcl_DStringFree(&safeInitName);
Tcl_DStringFree(&unloadName);
Tcl_DStringFree(&safeUnloadName);
|
| ︙ | ︙ | |||
555 556 557 558 559 560 561 |
*----------------------------------------------------------------------
*/
int
Tcl_UnloadObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < < | | 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
*----------------------------------------------------------------------
*/
int
Tcl_UnloadObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Interp *target; /* Which interpreter to unload from. */
LoadedLibrary *libraryPtr;
Tcl_DString pfx, tmp;
InterpLibrary *ipFirstPtr, *ipPtr;
int i, code, complain = 1, keepLibrary = 0;
const char *fullFileName = "";
const char *prefix;
static const char *const options[] = {
"-nocomplain", "-keeplibrary", "--", NULL
};
enum unloadOptionsEnum {
UNLOAD_NOCOMPLAIN, UNLOAD_KEEPLIB, UNLOAD_LAST
|
| ︙ | ︙ | |||
597 598 599 600 601 602 603 |
Tcl_ResetResult(interp);
break;
}
}
switch (index) {
case UNLOAD_NOCOMPLAIN: /* -nocomplain */
| | | | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 |
Tcl_ResetResult(interp);
break;
}
}
switch (index) {
case UNLOAD_NOCOMPLAIN: /* -nocomplain */
complain = 0;
break;
case UNLOAD_KEEPLIB: /* -keeplibrary */
keepLibrary = 1;
break;
case UNLOAD_LAST: /* -- */
i++;
goto endOfForLoop;
default:
TCL_UNREACHABLE();
}
|
| ︙ | ︙ | |||
666 667 668 669 670 671 672 |
* - Its prefix matches, the file name was specified as empty, and there is
* no statically loaded library with the same prefix.
*/
Tcl_MutexLock(&libraryMutex);
for (libraryPtr = firstLibraryPtr; libraryPtr != NULL; libraryPtr = libraryPtr->nextPtr) {
| | | | | | 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
* - Its prefix matches, the file name was specified as empty, and there is
* no statically loaded library with the same prefix.
*/
Tcl_MutexLock(&libraryMutex);
for (libraryPtr = firstLibraryPtr; libraryPtr != NULL; libraryPtr = libraryPtr->nextPtr) {
int namesMatch, filesMatch;
if (prefix == NULL) {
namesMatch = 0;
} else {
TclDStringClear(&pfx);
Tcl_DStringAppend(&pfx, prefix, -1);
TclDStringClear(&tmp);
Tcl_DStringAppend(&tmp, libraryPtr->prefix, -1);
if (strcmp(Tcl_DStringValue(&tmp),
Tcl_DStringValue(&pfx)) == 0) {
namesMatch = 1;
} else {
namesMatch = 0;
}
}
TclDStringClear(&pfx);
filesMatch = (strcmp(libraryPtr->fileName, fullFileName) == 0);
if (filesMatch && (namesMatch || (prefix == NULL))) {
break;
|
| ︙ | ︙ | |||
727 728 729 730 731 732 733 |
* Scan through the list of libraries already loaded in the target
* interpreter. If the library we want is already loaded there, then we
* should proceed with unloading.
*/
code = TCL_ERROR;
if (libraryPtr != NULL) {
| | | 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 |
* Scan through the list of libraries already loaded in the target
* interpreter. If the library we want is already loaded there, then we
* should proceed with unloading.
*/
code = TCL_ERROR;
if (libraryPtr != NULL) {
ipFirstPtr = (InterpLibrary *)Tcl_GetAssocData(target, "tclLoad", NULL);
for (ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
if (ipPtr->libraryPtr == libraryPtr) {
code = TCL_OK;
break;
}
}
}
|
| ︙ | ︙ | |||
749 750 751 752 753 754 755 |
fullFileName));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "NEVERLOADED",
(char *)NULL);
code = TCL_ERROR;
goto done;
}
| | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 |
fullFileName));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "UNLOAD", "NEVERLOADED",
(char *)NULL);
code = TCL_ERROR;
goto done;
}
code = UnloadLibrary(interp, target, libraryPtr, keepLibrary, fullFileName, 0);
done:
Tcl_DStringFree(&pfx);
Tcl_DStringFree(&tmp);
if (!complain && (code != TCL_OK)) {
code = TCL_OK;
Tcl_ResetResult(interp);
|
| ︙ | ︙ | |||
782 783 784 785 786 787 788 789 |
*----------------------------------------------------------------------
*/
static int
UnloadLibrary(
Tcl_Interp *interp,
Tcl_Interp *target,
LoadedLibrary *libraryPtr,
const char *fullFileName,
| > < | | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 |
*----------------------------------------------------------------------
*/
static int
UnloadLibrary(
Tcl_Interp *interp,
Tcl_Interp *target,
LoadedLibrary *libraryPtr,
int keepLibrary,
const char *fullFileName,
int interpExiting)
{
int code;
InterpLibrary *ipFirstPtr, *ipPtr;
LoadedLibrary *iterLibraryPtr;
int trustedRefCount = -1, safeRefCount = -1;
Tcl_LibraryUnloadProc *unloadProc = NULL;
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 |
}
/*
* Remove this library from the interpreter's library cache.
*/
if (!interpExiting) {
| | | | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 |
}
/*
* Remove this library from the interpreter's library cache.
*/
if (!interpExiting) {
ipFirstPtr = (InterpLibrary *)Tcl_GetAssocData(target, "tclLoad", NULL);
if (ipFirstPtr) {
ipPtr = ipFirstPtr;
if (ipPtr->libraryPtr == libraryPtr) {
ipFirstPtr = ipFirstPtr->nextPtr;
} else {
InterpLibrary *ipPrevPtr;
for (ipPrevPtr = ipPtr; ipPtr != NULL;
ipPrevPtr = ipPtr, ipPtr = ipPtr->nextPtr) {
if (ipPtr->libraryPtr == libraryPtr) {
ipPrevPtr->nextPtr = ipPtr->nextPtr;
break;
}
}
}
Tcl_Free(ipPtr);
Tcl_SetAssocData(target, "tclLoad", LoadCleanupProc, ipFirstPtr);
}
}
if (IsStatic(libraryPtr)) {
goto done;
}
|
| ︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 |
void
Tcl_StaticLibrary(
Tcl_Interp *interp, /* If not NULL, it means that the library has
* already been loaded into the given
* interpreter by calling the appropriate init
* proc. */
| | | 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
void
Tcl_StaticLibrary(
Tcl_Interp *interp, /* If not NULL, it means that the library has
* already been loaded into the given
* interpreter by calling the appropriate init
* proc. */
const char *prefix, /* Prefix. */
Tcl_LibraryInitProc *initProc,
/* Function to call to incorporate this
* library into a trusted interpreter. */
Tcl_LibraryInitProc *safeInitProc)
/* Function to call to incorporate this
* library into a safe interpreter (one that
* will execute untrusted scripts). NULL means
|
| ︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 | libraryPtr = (LoadedLibrary *)Tcl_Alloc(sizeof(LoadedLibrary)); libraryPtr->fileName = (char *)Tcl_Alloc(1); libraryPtr->fileName[0] = 0; libraryPtr->prefix = (char *)Tcl_Alloc(strlen(prefix) + 1); strcpy(libraryPtr->prefix, prefix); libraryPtr->loadHandle = NULL; libraryPtr->initProc = initProc; | | | | | | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 |
libraryPtr = (LoadedLibrary *)Tcl_Alloc(sizeof(LoadedLibrary));
libraryPtr->fileName = (char *)Tcl_Alloc(1);
libraryPtr->fileName[0] = 0;
libraryPtr->prefix = (char *)Tcl_Alloc(strlen(prefix) + 1);
strcpy(libraryPtr->prefix, prefix);
libraryPtr->loadHandle = NULL;
libraryPtr->initProc = initProc;
libraryPtr->safeInitProc = safeInitProc;
libraryPtr->unloadProc = NULL;
libraryPtr->safeUnloadProc = NULL;
Tcl_MutexLock(&libraryMutex);
libraryPtr->nextPtr = firstLibraryPtr;
firstLibraryPtr = libraryPtr;
Tcl_MutexUnlock(&libraryMutex);
}
if (interp != NULL) {
/*
* If we're loading the library into an interpreter, determine whether
* it's already loaded.
*/
ipFirstPtr = (InterpLibrary *)Tcl_GetAssocData(interp, "tclLoad", NULL);
for (ipPtr = ipFirstPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
if (ipPtr->libraryPtr == libraryPtr) {
return;
}
}
/*
* Library isn't loaded in the current interp yet. Mark it as now being
* loaded.
*/
ipPtr = (InterpLibrary *)Tcl_Alloc(sizeof(InterpLibrary));
ipPtr->libraryPtr = libraryPtr;
ipPtr->nextPtr = ipFirstPtr;
Tcl_SetAssocData(interp, "tclLoad", LoadCleanupProc, ipPtr);
}
}
/*
*----------------------------------------------------------------------
*
* TclGetLoadedLibraries --
|
| ︙ | ︙ | |||
1138 1139 1140 1141 1142 1143 1144 |
return TCL_OK;
}
target = Tcl_GetChild(interp, targetName);
if (target == NULL) {
return TCL_ERROR;
}
| | | 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 |
return TCL_OK;
}
target = Tcl_GetChild(interp, targetName);
if (target == NULL) {
return TCL_ERROR;
}
ipPtr = (InterpLibrary *)Tcl_GetAssocData(target, "tclLoad", NULL);
/*
* Return information about all of the available libraries.
*/
if (prefix) {
resultObj = NULL;
|
| ︙ | ︙ | |||
1206 1207 1208 1209 1210 1211 1212 |
Tcl_Interp *interp)
{
InterpLibrary *ipPtr = (InterpLibrary *)clientData, *nextPtr;
LoadedLibrary *libraryPtr;
while (ipPtr) {
libraryPtr = ipPtr->libraryPtr;
| | | 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
Tcl_Interp *interp)
{
InterpLibrary *ipPtr = (InterpLibrary *)clientData, *nextPtr;
LoadedLibrary *libraryPtr;
while (ipPtr) {
libraryPtr = ipPtr->libraryPtr;
UnloadLibrary(interp, interp, libraryPtr, 0, "", 1);
/* UnloadLibrary doesn't free it by interp delete, so do it here and
* repeat for next. */
nextPtr = ipPtr->nextPtr;
Tcl_Free(ipPtr);
ipPtr = nextPtr;
}
}
|
| ︙ | ︙ |
Changes to generic/tclMain.c.
| ︙ | ︙ | |||
276 277 278 279 280 281 282 | * interpreted. * *---------------------------------------------------------------------- */ TCL_NORETURN void Tcl_MainEx( | | > > > | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
* interpreted.
*
*----------------------------------------------------------------------
*/
TCL_NORETURN void
Tcl_MainEx(
Tcl_Size argc, /* Number of arguments. */
TCHAR **argv, /* Array of argument strings. */
Tcl_AppInitProc *appInitProc,
/* Application-specific initialization
* function to call after most initialization
* but before starting to execute commands. */
Tcl_Interp *interp)
{
Tcl_Size i=0; /* argv[i] index */
Tcl_Obj *path, *resultPtr, *argvPtr, *appName;
const char *encodingName = NULL;
int code, exitCode = 0;
Tcl_MainLoopProc *mainLoopProc;
Tcl_Channel chan;
InteractiveState is;
TclpSetInitialEncodings();
if (argc > 0) {
--argc; /* consume argv[0] */
++i;
}
TclpFindExecutable((const char *)argv[0]); /* nb: this could be NULL
* w/ (eg) an empty argv supplied to execve() */
Tcl_InitMemory(interp);
is.interp = interp;
is.prompt = PROMPT_START;
TclNewObj(is.commandPtr);
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 |
is.input = Tcl_GetStdChannel(TCL_STDIN);
Tcl_DecrRefCount(is.commandPtr);
TclNewObj(is.commandPtr);
Tcl_IncrRefCount(is.commandPtr);
if (code != TCL_OK) {
chan = Tcl_GetStdChannel(TCL_STDERR);
if (chan) {
| | | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
is.input = Tcl_GetStdChannel(TCL_STDIN);
Tcl_DecrRefCount(is.commandPtr);
TclNewObj(is.commandPtr);
Tcl_IncrRefCount(is.commandPtr);
if (code != TCL_OK) {
chan = Tcl_GetStdChannel(TCL_STDERR);
if (chan) {
if (Tcl_WriteObj(chan, Tcl_GetObjResult(interp)) < 0) {
Tcl_WriteChars(chan, ENCODING_ERROR, -1);
}
Tcl_WriteChars(chan, "\n", 1);
}
} else if (is.tty) {
resultPtr = Tcl_GetObjResult(interp);
Tcl_IncrRefCount(resultPtr);
(void)Tcl_GetStringFromObj(resultPtr, &length);
chan = Tcl_GetStdChannel(TCL_STDOUT);
|
| ︙ | ︙ | |||
732 733 734 735 736 737 738 | * Could be almost arbitrary, depending on the command that's typed. * *---------------------------------------------------------------------- */ static void StdinProc( | | | 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 |
* Could be almost arbitrary, depending on the command that's typed.
*
*----------------------------------------------------------------------
*/
static void
StdinProc(
void *clientData, /* The state of interactive cmd line */
TCL_UNUSED(int) /*mask*/)
{
int code;
Tcl_Size length;
InteractiveState *isPtr = (InteractiveState *)clientData;
Tcl_Channel chan = isPtr->input;
Tcl_Obj *commandPtr = isPtr->commandPtr;
|
| ︙ | ︙ |
Changes to generic/tclMutexTest.c.
1 2 3 4 5 | /* * tclMutexTest.c -- * * This file implements the testmutex command. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * tclMutexTest.c -- * * This file implements the testmutex command. * * Copyright (c) 2025 Ashok P. Nadkarni. All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef BUILD_tcl #undef STATIC_BUILD |
| ︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
#ifdef __cplusplus
extern "C" {
#endif
extern int Tcltest_Init(Tcl_Interp *interp);
#ifdef __cplusplus
}
#endif
/*
*----------------------------------------------------------------------
*
* TestMutexCmd --
*
* This procedure is invoked to process the "testmutex" Tcl command.
| > > > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
#ifdef __cplusplus
extern "C" {
#endif
extern int Tcltest_Init(Tcl_Interp *interp);
#ifdef __cplusplus
}
#endif
// Get the difference (in microseconds) between two Tcl_GetTime() timestamps.
#define USEC_DIFF(before, after) \
(1000000 * ((after).sec - (before).sec) + ((after).usec - (before).usec))
/*
*----------------------------------------------------------------------
*
* TestMutexCmd --
*
* This procedure is invoked to process the "testmutex" Tcl command.
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
*----------------------------------------------------------------------
*/
static int
TestMutexObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
*----------------------------------------------------------------------
*/
static int
TestMutexObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const mutexOptions[] = {
"lock", "condition", NULL
};
enum options {
LOCK, CONDITION
} option;
|
| ︙ | ︙ | |||
422 423 424 425 426 427 428 | * * Side effects: * None. * *------------------------------------------------------------------------ */ | | | | | | | | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static const Tcl_Time CONDITION_TIMEOUT = {5, 0};
static Tcl_ThreadCreateType
ProducerThreadProc(
void *clientData)
{
MutexThreadContext *threadContextPtr = (MutexThreadContext *)clientData;
MutexSharedContext *contextPtr = threadContextPtr->sharedContextPtr;
/* Limit on total number of operations across all threads */
unsigned long long limit;
limit = contextPtr->numThreads * (unsigned long long) contextPtr->numIterations;
/* Spin wait until given the run signal */
while (mutexThreadCount < contextPtr->numThreads) {
YieldToOtherThreads();
}
LockTestContext(contextPtr->numRecursions);
while (contextPtr->u.queue.totalEnqueued < limit) {
if (contextPtr->u.queue.available == contextPtr->u.queue.capacity) {
Tcl_Time before, after;
Tcl_GetTime(&before);
Tcl_ConditionWait(&contextPtr->u.queue.canEnqueue,
&testContextMutex, &CONDITION_TIMEOUT);
Tcl_GetTime(&after);
if (USEC_DIFF(before, after) >= 1000000 * CONDITION_TIMEOUT.sec) {
threadContextPtr->timeouts += 1;
}
} else {
contextPtr->u.queue.available += 1; /* Enqueue operation */
contextPtr->u.queue.totalEnqueued += 1;
threadContextPtr->numOperations += 1;
Tcl_ConditionNotify(&contextPtr->u.queue.canDequeue);
|
| ︙ | ︙ | |||
504 505 506 507 508 509 510 |
while (mutexThreadCount < contextPtr->numThreads) {
YieldToOtherThreads();
}
LockTestContext(contextPtr->numRecursions);
while (contextPtr->u.queue.totalDequeued < limit) {
if (contextPtr->u.queue.available == 0) {
| | | | | | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 |
while (mutexThreadCount < contextPtr->numThreads) {
YieldToOtherThreads();
}
LockTestContext(contextPtr->numRecursions);
while (contextPtr->u.queue.totalDequeued < limit) {
if (contextPtr->u.queue.available == 0) {
Tcl_Time before, after;
Tcl_GetTime(&before);
Tcl_ConditionWait(&contextPtr->u.queue.canDequeue,
&testContextMutex, &CONDITION_TIMEOUT);
Tcl_GetTime(&after);
if (USEC_DIFF(before, after) >= 1000000 * CONDITION_TIMEOUT.sec) {
threadContextPtr->timeouts += 1;
}
} else {
contextPtr->u.queue.totalDequeued += 1;
threadContextPtr->numOperations += 1;
contextPtr->u.queue.available -= 1;
Tcl_ConditionNotify(&contextPtr->u.queue.canEnqueue);
|
| ︙ | ︙ | |||
551 552 553 554 555 556 557 |
*----------------------------------------------------------------------
*/
int
TclMutex_Init(
Tcl_Interp *interp) /* The current Tcl interpreter */
{
| | | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
*----------------------------------------------------------------------
*/
int
TclMutex_Init(
Tcl_Interp *interp) /* The current Tcl interpreter */
{
Tcl_CreateObjCommand(interp, "testmutex", TestMutexObjCmd, NULL, NULL);
return TCL_OK;
}
#endif /* TCL_THREADS */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclNamesp.c.
| ︙ | ︙ | |||
70 71 72 73 74 75 76 | * Declarations for functions local to this file: */ static void DeleteImportedCmd(void *clientData); static int DoImport(Tcl_Interp *interp, Namespace *nsPtr, Tcl_HashEntry *hPtr, const char *cmdName, const char *pattern, | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
* Declarations for functions local to this file:
*/
static void DeleteImportedCmd(void *clientData);
static int DoImport(Tcl_Interp *interp,
Namespace *nsPtr, Tcl_HashEntry *hPtr,
const char *cmdName, const char *pattern,
Namespace *importNsPtr, int allowOverwrite);
static void DupNsNameInternalRep(Tcl_Obj *objPtr,
Tcl_Obj *copyPtr);
static char * ErrorCodeRead(void *clientData, Tcl_Interp *interp,
const char *name1, const char *name2, int flags);
static char * ErrorInfoRead(void *clientData, Tcl_Interp *interp,
const char *name1, const char *name2, int flags);
static char * EstablishErrorCodeTraces(void *clientData,
Tcl_Interp *interp, const char *name1,
const char *name2, int flags);
static char * EstablishErrorInfoTraces(void *clientData,
Tcl_Interp *interp, const char *name1,
const char *name2, int flags);
static void FreeNsNameInternalRep(Tcl_Obj *objPtr);
static int GetNamespaceFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, Tcl_Namespace **nsPtrPtr);
static int InvokeImportedNRCmd(void *clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
static Tcl_ObjCmdProc NamespaceChildrenCmd;
static Tcl_ObjCmdProc NamespaceCodeCmd;
static Tcl_ObjCmdProc NamespaceCurrentCmd;
static Tcl_ObjCmdProc NamespaceDeleteCmd;
static Tcl_ObjCmdProc NamespaceEvalCmd;
static Tcl_ObjCmdProc NRNamespaceEvalCmd;
static Tcl_ObjCmdProc NamespaceExistsCmd;
static Tcl_ObjCmdProc NamespaceExportCmd;
static Tcl_ObjCmdProc NamespaceForgetCmd;
static void NamespaceFree(Namespace *nsPtr);
static Tcl_ObjCmdProc NamespaceImportCmd;
static Tcl_ObjCmdProc NamespaceInscopeCmd;
static Tcl_ObjCmdProc NRNamespaceInscopeCmd;
static Tcl_ObjCmdProc NamespaceOriginCmd;
static Tcl_ObjCmdProc NamespaceParentCmd;
static Tcl_ObjCmdProc NamespacePathCmd;
static Tcl_ObjCmdProc NamespaceQualifiersCmd;
static Tcl_ObjCmdProc NamespaceTailCmd;
static Tcl_ObjCmdProc NamespaceUpvarCmd;
static Tcl_ObjCmdProc NamespaceUnknownCmd;
static Tcl_ObjCmdProc NamespaceWhichCmd;
static int SetNsNameFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void UnlinkNsPath(Namespace *nsPtr);
static Tcl_NRPostProc NsEval_Callback;
/*
* This structure defines a Tcl object type that contains a namespace
* reference. It is used in commands that take the name of a namespace as an
* argument. The namespace reference is resolved, and the result in cached in
* the object.
*/
static const Tcl_ObjType nsNameType = {
"nsName", /* the type's name */
FreeNsNameInternalRep, /* freeIntRepProc */
DupNsNameInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
SetNsNameFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define NsNameSetInternalRep(objPtr, nnPtr) \
do { \
Tcl_ObjInternalRep ir; \
(nnPtr)->refCount++; \
ir.twoPtrValue.ptr1 = (nnPtr); \
ir.twoPtrValue.ptr2 = NULL; \
Tcl_StoreInternalRep((objPtr), &nsNameType, &ir); \
} while (0)
#define NsNameGetInternalRep(objPtr, nnPtr) \
do { \
const Tcl_ObjInternalRep *irPtr; \
irPtr = TclFetchInternalRep((objPtr), &nsNameType); \
(nnPtr) = irPtr ? (ResolvedNsName *) irPtr->twoPtrValue.ptr1 : NULL; \
} while (0)
/*
* Array of values describing how to implement each standard subcommand of the
* "namespace" command.
*/
static const EnsembleImplMap defaultNamespaceMap[] = {
{"children", NamespaceChildrenCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 0},
{"code", NamespaceCodeCmd, TclCompileNamespaceCodeCmd, NULL, NULL, 0},
{"current", NamespaceCurrentCmd, TclCompileNamespaceCurrentCmd, NULL, NULL, 0},
{"delete", NamespaceDeleteCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
{"ensemble", TclNamespaceEnsembleCmd, NULL, NULL, NULL, 0},
{"eval", NamespaceEvalCmd, NULL, NRNamespaceEvalCmd, NULL, 0},
{"exists", NamespaceExistsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"export", NamespaceExportCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
{"forget", NamespaceForgetCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
{"import", NamespaceImportCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 0},
{"inscope", NamespaceInscopeCmd, NULL, NRNamespaceInscopeCmd, NULL, 0},
{"origin", NamespaceOriginCmd, TclCompileNamespaceOriginCmd, NULL, NULL, 0},
{"parent", NamespaceParentCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"path", NamespacePathCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"qualifiers", NamespaceQualifiersCmd, TclCompileNamespaceQualifiersCmd, NULL, NULL, 0},
{"tail", NamespaceTailCmd, TclCompileNamespaceTailCmd, NULL, NULL, 0},
{"unknown", NamespaceUnknownCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0},
{"upvar", NamespaceUpvarCmd, TclCompileNamespaceUpvarCmd, NULL, NULL, 0},
{"which", NamespaceWhichCmd, TclCompileNamespaceWhichCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
|
| ︙ | ︙ | |||
196 197 198 199 200 201 202 203 |
*----------------------------------------------------------------------
*/
static inline Tcl_HashEntry *
CreateChildEntry(
Namespace *nsPtr, /* Parent namespace. */
const char *name) /* Simple name to look for. */
{
#ifndef BREAK_NAMESPACE_COMPAT
| > | | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
*----------------------------------------------------------------------
*/
static inline Tcl_HashEntry *
CreateChildEntry(
Namespace *nsPtr, /* Parent namespace. */
const char *name) /* Simple name to look for. */
{
int newEntry;
#ifndef BREAK_NAMESPACE_COMPAT
return Tcl_CreateHashEntry(&nsPtr->childTable, name, &newEntry);
#else
if (nsPtr->childTablePtr == NULL) {
nsPtr->childTablePtr = (Tcl_HashTable *)
Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(nsPtr->childTablePtr, TCL_STRING_KEYS);
}
return Tcl_CreateHashEntry(nsPtr->childTablePtr, name, &newEntry);
#endif
}
/*
*----------------------------------------------------------------------
*
* FindChildEntry --
|
| ︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 |
* NOTE: we could avoid traversing the ns's command list by keeping a
* separate list of coros.
*/
for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
entryPtr != NULL;) {
cmdPtr = (Command *) Tcl_GetHashValue(entryPtr);
| | | 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 |
* NOTE: we could avoid traversing the ns's command list by keeping a
* separate list of coros.
*/
for (entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
entryPtr != NULL;) {
cmdPtr = (Command *) Tcl_GetHashValue(entryPtr);
if (cmdPtr->nreProc == TclNRInterpCoroutine) {
Tcl_DeleteCommandFromToken(interp, (Tcl_Command) cmdPtr);
entryPtr = Tcl_FirstHashEntry(&nsPtr->cmdTable, &search);
} else {
entryPtr = Tcl_NextHashEntry(&search);
}
}
|
| ︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 |
nsPtr->flags &= ~(NS_DYING|NS_TEARDOWN);
}
}
TclNsDecrRefCount(nsPtr);
}
| < > | | | 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 |
nsPtr->flags &= ~(NS_DYING|NS_TEARDOWN);
}
}
TclNsDecrRefCount(nsPtr);
}
int
TclNamespaceDeleted(
Namespace *nsPtr)
{
return (nsPtr->flags & NS_DYING) ? 1 : 0;
}
void
TclDeleteNamespaceChildren(
Namespace *nsPtr) /* Namespace whose children to delete */
{
Tcl_Interp *interp = nsPtr->interp;
Tcl_HashEntry *entryPtr;
size_t i;
int unchecked;
Tcl_HashSearch search;
/*
* Delete all the child namespaces.
*
* BE CAREFUL: When each child is deleted, it divorces itself from its
* parent. The hash table can't be properly traversed if its elements are
|
| ︙ | ︙ | |||
1213 1214 1215 1216 1217 1218 1219 |
for (entryPtr = FirstChildEntry(nsPtr, &search);
entryPtr != NULL;
entryPtr = Tcl_NextHashEntry(&search)) {
children[i] = (Namespace *) Tcl_GetHashValue(entryPtr);
children[i]->refCount++;
i++;
}
| | | | 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 |
for (entryPtr = FirstChildEntry(nsPtr, &search);
entryPtr != NULL;
entryPtr = Tcl_NextHashEntry(&search)) {
children[i] = (Namespace *) Tcl_GetHashValue(entryPtr);
children[i]->refCount++;
i++;
}
unchecked = 0;
for (i = 0 ; i < length ; i++) {
if (!(children[i]->flags & NS_DYING)) {
unchecked = 1;
Tcl_DeleteNamespace((Tcl_Namespace *) children[i]);
TclNsDecrRefCount(children[i]);
}
}
TclStackFree(interp, children);
}
}
|
| ︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 |
if ((simplePattern != NULL) && TclMatchIsTrivial(simplePattern)) {
hPtr = Tcl_FindHashEntry(&importNsPtr->cmdTable, simplePattern);
if (hPtr == NULL) {
return TCL_OK;
}
return DoImport(interp, nsPtr, hPtr, simplePattern, pattern,
| | | | 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 |
if ((simplePattern != NULL) && TclMatchIsTrivial(simplePattern)) {
hPtr = Tcl_FindHashEntry(&importNsPtr->cmdTable, simplePattern);
if (hPtr == NULL) {
return TCL_OK;
}
return DoImport(interp, nsPtr, hPtr, simplePattern, pattern,
importNsPtr, allowOverwrite);
}
for (hPtr = Tcl_FirstHashEntry(&importNsPtr->cmdTable, &search);
(hPtr != NULL); hPtr = Tcl_NextHashEntry(&search)) {
char *cmdName = (char *) Tcl_GetHashKey(&importNsPtr->cmdTable, hPtr);
if (Tcl_StringMatch(cmdName, simplePattern) &&
DoImport(interp, nsPtr, hPtr, cmdName, pattern, importNsPtr,
allowOverwrite) == TCL_ERROR) {
return TCL_ERROR;
}
}
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
1792 1793 1794 1795 1796 1797 1798 |
DoImport(
Tcl_Interp *interp,
Namespace *nsPtr,
Tcl_HashEntry *hPtr,
const char *cmdName,
const char *pattern,
Namespace *importNsPtr,
| | | 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 |
DoImport(
Tcl_Interp *interp,
Namespace *nsPtr,
Tcl_HashEntry *hPtr,
const char *cmdName,
const char *pattern,
Namespace *importNsPtr,
int allowOverwrite)
{
Tcl_Size i = 0, exported = 0;
Tcl_HashEntry *found;
/*
* The command cmdName in the source namespace matches the pattern. Check
* whether it was exported. If it wasn't, we ignore it.
|
| ︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 |
cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
if (found != NULL && cmdPtr->deleteProc == DeleteImportedCmd) {
Command *overwrite = (Command *) Tcl_GetHashValue(found);
Command *linkCmd = cmdPtr;
while (linkCmd->deleteProc == DeleteImportedCmd) {
| | | | 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 |
cmdPtr = (Command *) Tcl_GetHashValue(hPtr);
if (found != NULL && cmdPtr->deleteProc == DeleteImportedCmd) {
Command *overwrite = (Command *) Tcl_GetHashValue(found);
Command *linkCmd = cmdPtr;
while (linkCmd->deleteProc == DeleteImportedCmd) {
dataPtr = (ImportedCmdData *) linkCmd->objClientData;
linkCmd = dataPtr->realCmdPtr;
if (overwrite == linkCmd) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"import pattern \"%s\" would create a loop"
" containing command \"%s\"",
pattern, Tcl_DStringValue(&ds)));
Tcl_DStringFree(&ds);
Tcl_SetErrorCode(interp, "TCL", "IMPORT", "LOOP", (char *)NULL);
return TCL_ERROR;
}
}
}
dataPtr = (ImportedCmdData *) Tcl_Alloc(sizeof(ImportedCmdData));
importedCmd = Tcl_NRCreateCommand(interp, Tcl_DStringValue(&ds),
TclInvokeImportedCmd, InvokeImportedNRCmd, dataPtr,
DeleteImportedCmd);
dataPtr->realCmdPtr = cmdPtr;
/* corresponding decrement is in DeleteImportedCmd */
cmdPtr->refCount++;
dataPtr->selfPtr = (Command *) importedCmd;
dataPtr->selfPtr->compileProc = cmdPtr->compileProc;
|
| ︙ | ︙ | |||
1884 1885 1886 1887 1888 1889 1890 |
refPtr->importedCmdPtr = (Command *) importedCmd;
refPtr->nextPtr = cmdPtr->importRefPtr;
cmdPtr->importRefPtr = refPtr;
} else {
Command *overwrite = (Command *) Tcl_GetHashValue(found);
if (overwrite->deleteProc == DeleteImportedCmd) {
| | > | 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 |
refPtr->importedCmdPtr = (Command *) importedCmd;
refPtr->nextPtr = cmdPtr->importRefPtr;
cmdPtr->importRefPtr = refPtr;
} else {
Command *overwrite = (Command *) Tcl_GetHashValue(found);
if (overwrite->deleteProc == DeleteImportedCmd) {
ImportedCmdData *dataPtr = (ImportedCmdData *)
overwrite->objClientData;
if (dataPtr->realCmdPtr == Tcl_GetHashValue(hPtr)) {
/*
* Repeated import of same command is acceptable.
*/
return TCL_OK;
|
| ︙ | ︙ | |||
2021 2022 2023 2024 2025 2026 2027 |
if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) {
/*
* Original not in namespace we're matching. Check the first link
* in the import chain.
*/
Command *cmdPtr = (Command *) token;
| | > | 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 |
if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) {
/*
* Original not in namespace we're matching. Check the first link
* in the import chain.
*/
Command *cmdPtr = (Command *) token;
ImportedCmdData *dataPtr = (ImportedCmdData *)
cmdPtr->objClientData;
Tcl_Command firstToken = (Tcl_Command) dataPtr->realCmdPtr;
if (firstToken == origin) {
continue;
}
Tcl_GetCommandInfoFromToken(firstToken, &info);
if (info.namespacePtr != (Tcl_Namespace *) sourceNsPtr) {
|
| ︙ | ︙ | |||
2075 2076 2077 2078 2079 2080 2081 |
Command *cmdPtr = (Command *) command;
if (cmdPtr->deleteProc != DeleteImportedCmd) {
return NULL;
}
while (cmdPtr->deleteProc == DeleteImportedCmd) {
| | | 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 |
Command *cmdPtr = (Command *) command;
if (cmdPtr->deleteProc != DeleteImportedCmd) {
return NULL;
}
while (cmdPtr->deleteProc == DeleteImportedCmd) {
ImportedCmdData *dataPtr = (ImportedCmdData *) cmdPtr->objClientData;
cmdPtr = dataPtr->realCmdPtr;
}
return (Tcl_Command) cmdPtr;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
2105 2106 2107 2108 2109 2110 2111 |
*/
static int
InvokeImportedNRCmd(
void *clientData, /* Points to the imported command's
* ImportedCmdData structure. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 |
*/
static int
InvokeImportedNRCmd(
void *clientData, /* Points to the imported command's
* ImportedCmdData structure. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
ImportedCmdData *dataPtr = (ImportedCmdData *) clientData;
Command *realCmdPtr = dataPtr->realCmdPtr;
TclSkipTailcall(interp);
return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR, realCmdPtr);
}
int
TclInvokeImportedCmd(
void *clientData, /* Points to the imported command's
* ImportedCmdData structure. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
return Tcl_NRCallObjProc(interp, InvokeImportedNRCmd, clientData,
objc, objv);
}
/*
*----------------------------------------------------------------------
*
* DeleteImportedCmd --
|
| ︙ | ︙ | |||
2294 2295 2296 2297 2298 2299 2300 |
* TCL_CREATE_NS_IF_UNKNOWN flag is set. */
Namespace **actualCxtPtrPtr,/* Address where function stores a pointer to
* the actual namespace from which the search
* started. This is either cxtNsPtr, the ::
* namespace if TCL_GLOBAL_ONLY was specified,
* or the current namespace if cxtNsPtr was
* NULL. */
| | | 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 |
* TCL_CREATE_NS_IF_UNKNOWN flag is set. */
Namespace **actualCxtPtrPtr,/* Address where function stores a pointer to
* the actual namespace from which the search
* started. This is either cxtNsPtr, the ::
* namespace if TCL_GLOBAL_ONLY was specified,
* or the current namespace if cxtNsPtr was
* NULL. */
const char **simpleNamePtr) /* Address where function stores the simple
* name at end of the qualName, or NULL if
* qualName is "::" or the flag
* TCL_FIND_ONLY_NS was specified. */
{
Interp *iPtr = (Interp *) interp;
Namespace *nsPtr = cxtNsPtr, *lastNsPtr = NULL, *lastAltNsPtr = NULL;
Namespace *altNsPtr;
|
| ︙ | ︙ | |||
2332 2333 2334 2335 2336 2337 2338 |
* namespace. */
if ((qualName[0] == ':') && (qualName[1] == ':')) {
start = qualName + 2; /* Skip over the initial :: */
while (start[0] == ':') {
start++; /* Skip over a subsequent : */
}
nsPtr = globalNsPtr;
| | > | 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 |
* namespace. */
if ((qualName[0] == ':') && (qualName[1] == ':')) {
start = qualName + 2; /* Skip over the initial :: */
while (start[0] == ':') {
start++; /* Skip over a subsequent : */
}
nsPtr = globalNsPtr;
if (start[0] == '\0') { /* qualName is just two or more
* ":"s. */
*nsPtrPtr = globalNsPtr;
*altNsPtrPtr = NULL;
*actualCxtPtrPtr = globalNsPtr;
*simpleNamePtr = start; /* Points to empty string. */
return TCL_OK;
}
}
|
| ︙ | ︙ | |||
2536 2537 2538 2539 2540 2541 2542 |
TclEnsureNamespace(
Tcl_Interp *interp,
Tcl_Namespace *namespacePtr)
{
Namespace *nsPtr = (Namespace *) namespacePtr;
if (!(nsPtr->flags & NS_DYING)) {
| | | 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 |
TclEnsureNamespace(
Tcl_Interp *interp,
Tcl_Namespace *namespacePtr)
{
Namespace *nsPtr = (Namespace *) namespacePtr;
if (!(nsPtr->flags & NS_DYING)) {
return namespacePtr;
}
/*
* If a new namespace with the same name has been created already,
* return that. Otherwise, create a new one. Bug 24d7f1a695.
*/
namespacePtr = Tcl_FindNamespace(interp, nsPtr->fullName, NULL, 0);
if (namespacePtr != NULL) {
|
| ︙ | ︙ | |||
2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 |
}
resPtr = resPtr->nextPtr;
}
if (result == TCL_OK) {
((Command *) cmd)->flags |= CMD_VIA_RESOLVER;
return cmd;
} else if (result != TCL_CONTINUE) {
return NULL;
}
}
/*
* Find the namespace(s) that contain the command.
| > | 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 |
}
resPtr = resPtr->nextPtr;
}
if (result == TCL_OK) {
((Command *) cmd)->flags |= CMD_VIA_RESOLVER;
return cmd;
} else if (result != TCL_CONTINUE) {
return NULL;
}
}
/*
* Find the namespace(s) that contain the command.
|
| ︙ | ︙ | |||
2840 2841 2842 2843 2844 2845 2846 |
Command *newCmdPtr) /* Points to the new command. */
{
char *cmdName;
Tcl_HashEntry *hPtr;
Namespace *nsPtr;
Namespace *trailNsPtr, *shadowNsPtr;
Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
| < | | 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 |
Command *newCmdPtr) /* Points to the new command. */
{
char *cmdName;
Tcl_HashEntry *hPtr;
Namespace *nsPtr;
Namespace *trailNsPtr, *shadowNsPtr;
Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
int found, i;
int trailFront = -1;
int trailSize = 5; /* Formerly NUM_TRAIL_ELEMS. */
Namespace **trailPtr = (Namespace **) TclStackAlloc(interp,
trailSize * sizeof(Namespace *));
/*
* Start at the namespace containing the new command, and work up through
|
| ︙ | ︙ | |||
2877 2878 2879 2880 2881 2882 2883 | * such that there is a identically-named sequence of child namespaces * starting from ::. shadowNsPtr will be the tail of this sequence, or * the deepest namespace under :: that might contain a command now * shadowed by cmdName. We check below if shadowNsPtr actually * contains a command cmdName. */ | | | | 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 |
* such that there is a identically-named sequence of child namespaces
* starting from ::. shadowNsPtr will be the tail of this sequence, or
* the deepest namespace under :: that might contain a command now
* shadowed by cmdName. We check below if shadowNsPtr actually
* contains a command cmdName.
*/
found = 1;
shadowNsPtr = globalNsPtr;
for (i = trailFront; i >= 0; i--) {
trailNsPtr = trailPtr[i];
hPtr = FindChildEntry(shadowNsPtr, trailNsPtr->name);
if (hPtr != NULL) {
shadowNsPtr = (Namespace *) Tcl_GetHashValue(hPtr);
} else {
found = 0;
break;
}
}
/*
* If shadowNsPtr contains a command named cmdName, we invalidate all
* of the command refs cached in nsPtr. As a boundary case,
|
| ︙ | ︙ | |||
3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 |
}
return objPtr;
}
/*
*----------------------------------------------------------------------
*
* NamespaceChildrenCmd --
*
* Invoked to implement the "namespace children" command that returns a
* list containing the fully-qualified names of the child namespaces of a
* given namespace. Handles the following syntax:
*
* namespace children ?name? ?pattern?
| > > > > > > > > > > > > > > > > > > > > > > > > | 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 |
}
return objPtr;
}
/*
*----------------------------------------------------------------------
*
* TclInitNamespaceCmd --
*
* This function is called to create the "namespace" Tcl command. See the
* user documentation for details on what it does.
*
* Results:
* Handle for the namespace command, or NULL on failure.
*
* Side effects:
* none
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitNamespaceCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
return TclMakeEnsemble(interp, "namespace", defaultNamespaceMap);
}
/*
*----------------------------------------------------------------------
*
* NamespaceChildrenCmd --
*
* Invoked to implement the "namespace children" command that returns a
* list containing the fully-qualified names of the child namespaces of a
* given namespace. Handles the following syntax:
*
* namespace children ?name? ?pattern?
|
| ︙ | ︙ | |||
3107 3108 3109 3110 3111 3112 3113 |
*----------------------------------------------------------------------
*/
static int
NamespaceChildrenCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 |
*----------------------------------------------------------------------
*/
static int
NamespaceChildrenCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Namespace *namespacePtr;
Namespace *nsPtr, *childNsPtr;
Namespace *globalNsPtr = (Namespace *) TclGetGlobalNamespace(interp);
const char *pattern = NULL;
Tcl_DString buffer;
Tcl_HashEntry *entryPtr;
|
| ︙ | ︙ | |||
3225 3226 3227 3228 3229 3230 3231 |
*----------------------------------------------------------------------
*/
static int
NamespaceCodeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 |
*----------------------------------------------------------------------
*/
static int
NamespaceCodeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *listPtr, *objPtr;
const char *arg;
Tcl_Size length;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "arg");
return TCL_ERROR;
}
/*
* If "arg" is already a scoped value, then return it directly.
* Take care to only check for scoping in precisely the style that
* [::namespace code] generates it. Anything more forgiving can have
* the effect of failing in namespaces that contain their own custom
" "namespace" command. [Bug 3202171].
*/
arg = TclGetStringFromObj(objv[1], &length);
if (*arg==':' && length > 20
&& strncmp(arg, "::namespace inscope ", 20) == 0) {
Tcl_SetObjResult(interp, objv[1]);
return TCL_OK;
|
| ︙ | ︙ | |||
3300 3301 3302 3303 3304 3305 3306 |
*----------------------------------------------------------------------
*/
static int
NamespaceCurrentCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 |
*----------------------------------------------------------------------
*/
static int
NamespaceCurrentCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
}
/*
|
| ︙ | ︙ | |||
3359 3360 3361 3362 3363 3364 3365 |
*----------------------------------------------------------------------
*/
static int
NamespaceDeleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 |
*----------------------------------------------------------------------
*/
static int
NamespaceDeleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Namespace *namespacePtr;
const char *name;
int i;
if (objc < 1) {
Tcl_WrongNumArgs(interp, 1, objv, "?name name...?");
return TCL_ERROR;
}
/*
|
| ︙ | ︙ | |||
3436 3437 3438 3439 3440 3441 3442 |
*----------------------------------------------------------------------
*/
static int
NamespaceEvalCmd(
void *clientData, /* Arbitrary value passed to cmd. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 |
*----------------------------------------------------------------------
*/
static int
NamespaceEvalCmd(
void *clientData, /* Arbitrary value passed to cmd. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, NRNamespaceEvalCmd, clientData, objc,
objv);
}
static int
NRNamespaceEvalCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
CmdFrame *invoker;
int word;
Tcl_Namespace *namespacePtr;
CallFrame *framePtr, **framePtrPtr;
Tcl_Obj *objPtr;
int result;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name arg ?arg...?");
|
| ︙ | ︙ | |||
3579 3580 3581 3582 3583 3584 3585 |
*----------------------------------------------------------------------
*/
static int
NamespaceExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 |
*----------------------------------------------------------------------
*/
static int
NamespaceExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Namespace *namespacePtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3634 3635 3636 3637 3638 3639 3640 |
*----------------------------------------------------------------------
*/
static int
NamespaceExportCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 |
*----------------------------------------------------------------------
*/
static int
NamespaceExportCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int firstArg, i;
if (objc < 1) {
Tcl_WrongNumArgs(interp, 1, objv, "?-clear? ?pattern pattern...?");
return TCL_ERROR;
}
/*
|
| ︙ | ︙ | |||
3716 3717 3718 3719 3720 3721 3722 |
*----------------------------------------------------------------------
*/
static int
NamespaceForgetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < | | 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 |
*----------------------------------------------------------------------
*/
static int
NamespaceForgetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *pattern;
int i, result;
if (objc < 1) {
Tcl_WrongNumArgs(interp, 1, objv, "?pattern pattern...?");
return TCL_ERROR;
}
for (i = 1; i < objc; i++) {
|
| ︙ | ︙ | |||
3782 3783 3784 3785 3786 3787 3788 |
*----------------------------------------------------------------------
*/
static int
NamespaceImportCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | < | > | | 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 |
*----------------------------------------------------------------------
*/
static int
NamespaceImportCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int allowOverwrite = 0;
const char *string, *pattern;
int i, result;
int firstArg;
if (objc < 1) {
Tcl_WrongNumArgs(interp, 1, objv, "?-force? ?pattern pattern...?");
return TCL_ERROR;
}
/*
* Skip over the optional "-force" as the first argument.
*/
firstArg = 1;
if (firstArg < objc) {
string = TclGetString(objv[firstArg]);
if ((*string == '-') && (strcmp(string, "-force") == 0)) {
allowOverwrite = 1;
firstArg++;
}
} else {
/*
* When objc == 1, command is just [namespace import]. Introspection
* form to return list of imported commands.
*/
|
| ︙ | ︙ | |||
3886 3887 3888 3889 3890 3891 3892 |
*----------------------------------------------------------------------
*/
static int
NamespaceInscopeCmd(
void *clientData, /* Arbitrary value passed to cmd. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 |
*----------------------------------------------------------------------
*/
static int
NamespaceInscopeCmd(
void *clientData, /* Arbitrary value passed to cmd. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, NRNamespaceInscopeCmd, clientData, objc,
objv);
}
static int
NRNamespaceInscopeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Namespace *namespacePtr;
CallFrame *framePtr, **framePtrPtr;
Tcl_Obj *cmdObjPtr;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name arg ?arg...?");
|
| ︙ | ︙ | |||
3984 3985 3986 3987 3988 3989 3990 |
*----------------------------------------------------------------------
*/
static int
NamespaceOriginCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 |
*----------------------------------------------------------------------
*/
static int
NamespaceOriginCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Command cmd, origCmd;
Tcl_Obj *resultPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name");
return TCL_ERROR;
|
| ︙ | ︙ | |||
4045 4046 4047 4048 4049 4050 4051 |
*----------------------------------------------------------------------
*/
static int
NamespaceParentCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 |
*----------------------------------------------------------------------
*/
static int
NamespaceParentCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Namespace *nsPtr;
if (objc == 1) {
nsPtr = TclGetCurrentNamespace(interp);
} else if (objc == 2) {
if (TclGetNamespaceFromObj(interp, objv[1], &nsPtr) != TCL_OK) {
|
| ︙ | ︙ | |||
4102 4103 4104 4105 4106 4107 4108 |
*----------------------------------------------------------------------
*/
static int
NamespacePathCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 |
*----------------------------------------------------------------------
*/
static int
NamespacePathCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Namespace *nsPtr = (Namespace *) TclGetCurrentNamespace(interp);
Tcl_Size nsObjc, i;
int result = TCL_ERROR;
Tcl_Obj **nsObjv;
Tcl_Namespace **namespaceList = NULL;
|
| ︙ | ︙ | |||
4329 4330 4331 4332 4333 4334 4335 |
*----------------------------------------------------------------------
*/
static int
NamespaceQualifiersCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 |
*----------------------------------------------------------------------
*/
static int
NamespaceQualifiersCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *name, *p;
size_t length;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "string");
return TCL_ERROR;
|
| ︙ | ︙ | |||
4397 4398 4399 4400 4401 4402 4403 |
*----------------------------------------------------------------------
*/
static int
NamespaceUnknownCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 |
*----------------------------------------------------------------------
*/
static int
NamespaceUnknownCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Namespace *currNsPtr;
Tcl_Obj *resultPtr;
int rc;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?script?");
|
| ︙ | ︙ | |||
4584 4585 4586 4587 4588 4589 4590 |
*----------------------------------------------------------------------
*/
static int
NamespaceTailCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 |
*----------------------------------------------------------------------
*/
static int
NamespaceTailCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *name, *p;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "string");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
4642 4643 4644 4645 4646 4647 4648 |
*----------------------------------------------------------------------
*/
static int
NamespaceUpvarCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 |
*----------------------------------------------------------------------
*/
static int
NamespaceUpvarCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
Tcl_Namespace *nsPtr, *savedNsPtr;
Var *otherPtr, *arrayPtr;
const char *myName;
if (objc < 2 || (objc & 1)) {
|
| ︙ | ︙ | |||
4716 4717 4718 4719 4720 4721 4722 |
*----------------------------------------------------------------------
*/
static int
NamespaceWhichCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 |
*----------------------------------------------------------------------
*/
static int
NamespaceWhichCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const opts[] = {
"-command", "-variable", NULL
};
enum { OPT_COMMAND, OPT_VARIABLE } lookupType = OPT_COMMAND;
Tcl_Obj *resultPtr;
|
| ︙ | ︙ | |||
4886 4887 4888 4889 4890 4891 4892 |
if (interp == NULL) {
return TCL_ERROR;
}
name = TclGetString(objPtr);
TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS,
| | | 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 |
if (interp == NULL) {
return TCL_ERROR;
}
name = TclGetString(objPtr);
TclGetNamespaceForQualName(interp, name, NULL, TCL_FIND_ONLY_NS,
&nsPtr, &dummy1Ptr, &dummy2Ptr, &dummy);
if ((nsPtr == NULL) || (nsPtr->flags & NS_DYING)) {
return TCL_ERROR;
}
/*
* If we found a namespace, then create a new ResolvedNsName structure
|
| ︙ | ︙ | |||
4997 4998 4999 5000 5001 5002 5003 |
Tcl_Interp *interp, /* Interpreter in which to log information. */
const char *script, /* First character in script containing
* command (must be <= command). */
const char *command, /* First character in command that generated
* the error. */
Tcl_Size length, /* Number of bytes in command (< 0 means use
* all bytes up to first null byte). */
| | > < < | 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 |
Tcl_Interp *interp, /* Interpreter in which to log information. */
const char *script, /* First character in script containing
* command (must be <= command). */
const char *command, /* First character in command that generated
* the error. */
Tcl_Size length, /* Number of bytes in command (< 0 means use
* all bytes up to first null byte). */
const unsigned char *pc, /* Current pc of bytecode execution context */
Tcl_Obj **tosPtr) /* Current stack of bytecode execution
* context */
{
const char *p;
Interp *iPtr = (Interp *) interp;
int overflow, limit = 150;
Var *varPtr, *arrayPtr;
if (iPtr->flags & ERR_ALREADY_LOGGED) {
/*
* Someone else has already logged error information for this command.
* Don't add anything more.
*/
|
| ︙ | ︙ |
Changes to generic/tclNotify.c.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 |
Tcl_Event *lastEventPtr; /* Last pending event, or NULL if none. */
Tcl_Event *markerEventPtr; /* Last high-priority event in queue, or NULL
* if none. */
Tcl_Size eventCount; /* Number of entries, but refer to comments in
* Tcl_ServiceEvent(). */
Tcl_Mutex queueMutex; /* Mutex to protect access to the previous
* four fields. */
| < < | > > | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
Tcl_Event *lastEventPtr; /* Last pending event, or NULL if none. */
Tcl_Event *markerEventPtr; /* Last high-priority event in queue, or NULL
* if none. */
Tcl_Size eventCount; /* Number of entries, but refer to comments in
* Tcl_ServiceEvent(). */
Tcl_Mutex queueMutex; /* Mutex to protect access to the previous
* four fields. */
int serviceMode; /* One of TCL_SERVICE_NONE or
* TCL_SERVICE_ALL. */
int blockTimeSet; /* 0 means there is no maximum block time:
* block forever. */
Tcl_Time blockTime; /* If blockTimeSet is 1, gives the maximum
* elapsed time for the next block. */
int inTraversal; /* 1 if Tcl_SetMaxBlockTime is being called
* during an event source traversal. */
int initialized; /* 1 if notifier has been initialized. */
EventSource *firstEventSourcePtr;
/* Pointer to first event source in list of
* event sources for this thread. */
Tcl_ThreadId threadId; /* Thread that owns this notifier instance. */
void *clientData; /* Opaque handle for platform specific
* notifier. */
struct ThreadSpecificData *nextPtr;
/* Next notifier in global list of notifiers.
* Access is controlled by the listLock global
* mutex. */
} ThreadSpecificData;
|
| ︙ | ︙ | |||
133 134 135 136 137 138 139 | /* * Notifier not yet initialized in this thread. */ tsdPtr = TCL_TSD_INIT(&dataKey); tsdPtr->threadId = threadId; tsdPtr->clientData = Tcl_InitNotifier(); | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
/*
* Notifier not yet initialized in this thread.
*/
tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->threadId = threadId;
tsdPtr->clientData = Tcl_InitNotifier();
tsdPtr->initialized = 1;
tsdPtr->nextPtr = firstNotifierPtr;
firstNotifierPtr = tsdPtr;
}
Tcl_MutexUnlock(&listLock);
}
/*
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;
prevPtrPtr = &((*prevPtrPtr)->nextPtr)) {
if (*prevPtrPtr == tsdPtr) {
*prevPtrPtr = tsdPtr->nextPtr;
break;
}
}
| | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
for (prevPtrPtr = &firstNotifierPtr; *prevPtrPtr != NULL;
prevPtrPtr = &((*prevPtrPtr)->nextPtr)) {
if (*prevPtrPtr == tsdPtr) {
*prevPtrPtr = tsdPtr->nextPtr;
break;
}
}
tsdPtr->initialized = 0;
Tcl_MutexUnlock(&listLock);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
304 305 306 307 308 309 310 |
Tcl_CreateEventSource(
Tcl_EventSetupProc *setupProc,
/* Function to invoke to figure out what to
* wait for. */
Tcl_EventCheckProc *checkProc,
/* Function to call after waiting to see what
* happened. */
| | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
Tcl_CreateEventSource(
Tcl_EventSetupProc *setupProc,
/* Function to invoke to figure out what to
* wait for. */
Tcl_EventCheckProc *checkProc,
/* Function to call after waiting to see what
* happened. */
void *clientData) /* One-word argument to pass to setupProc and
* checkProc. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
EventSource *sourcePtr = (EventSource *)Tcl_Alloc(sizeof(EventSource));
sourcePtr->setupProc = setupProc;
sourcePtr->checkProc = checkProc;
|
| ︙ | ︙ | |||
343 344 345 346 347 348 349 |
Tcl_DeleteEventSource(
Tcl_EventSetupProc *setupProc,
/* Function to invoke to figure out what to
* wait for. */
Tcl_EventCheckProc *checkProc,
/* Function to call after waiting to see what
* happened. */
| | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
Tcl_DeleteEventSource(
Tcl_EventSetupProc *setupProc,
/* Function to invoke to figure out what to
* wait for. */
Tcl_EventCheckProc *checkProc,
/* Function to call after waiting to see what
* happened. */
void *clientData) /* One-word argument to pass to setupProc and
* checkProc. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
EventSource *sourcePtr, *prevPtr;
for (sourcePtr = tsdPtr->firstEventSourcePtr, prevPtr = NULL;
sourcePtr != NULL;
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
*
*----------------------------------------------------------------------
*/
void
Tcl_QueueEvent(
Tcl_Event *evPtr, /* Event to add to queue. The storage space
| | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
*
*----------------------------------------------------------------------
*/
void
Tcl_QueueEvent(
Tcl_Event *evPtr, /* Event to add to queue. The storage space
* must have been allocated the caller with
* malloc (Tcl_Alloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
* possibly combined with TCL_QUEUE_ALERT_IF_EMPTY. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
QueueEvent(tsdPtr, evPtr, position);
}
|
| ︙ | ︙ | |||
422 423 424 425 426 427 428 |
Tcl_ThreadQueueEvent(
Tcl_ThreadId threadId, /* Identifier for thread to use. */
Tcl_Event *evPtr, /* Event to add to queue. The storage space
* must have been allocated the caller with
* malloc (Tcl_Alloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
| | | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
Tcl_ThreadQueueEvent(
Tcl_ThreadId threadId, /* Identifier for thread to use. */
Tcl_Event *evPtr, /* Event to add to queue. The storage space
* must have been allocated the caller with
* malloc (Tcl_Alloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
* possibly combined with TCL_QUEUE_ALERT_IF_EMPTY. */
{
ThreadSpecificData *tsdPtr;
/*
* Find the notifier associated with the specified thread.
*/
|
| ︙ | ︙ | |||
482 483 484 485 486 487 488 |
ThreadSpecificData *tsdPtr, /* Handle to thread local data that indicates
* which event queue to use. */
Tcl_Event *evPtr, /* Event to add to queue. The storage space
* must have been allocated the caller with
* malloc (Tcl_Alloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
| | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
ThreadSpecificData *tsdPtr, /* Handle to thread local data that indicates
* which event queue to use. */
Tcl_Event *evPtr, /* Event to add to queue. The storage space
* must have been allocated the caller with
* malloc (Tcl_Alloc), and it becomes the
* property of the event queue. It will be
* freed after the event has been handled. */
int position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK,
* possibly combined with TCL_QUEUE_ALERT_IF_EMPTY */
{
int wasEmpty = 0;
Tcl_MutexLock(&(tsdPtr->queueMutex));
if ((position & 3) == TCL_QUEUE_TAIL) {
/*
|
| ︙ | ︙ | |||
558 559 560 561 562 563 564 |
*
*----------------------------------------------------------------------
*/
void
Tcl_DeleteEvents(
Tcl_EventDeleteProc *proc, /* The function to call. */
| | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
*
*----------------------------------------------------------------------
*/
void
Tcl_DeleteEvents(
Tcl_EventDeleteProc *proc, /* The function to call. */
void *clientData) /* The type-specific data. */
{
Tcl_Event *evPtr; /* Pointer to the event being examined */
Tcl_Event *prevPtr; /* Pointer to evPtr's predecessor, or NULL if
* evPtr designates the first event in the
* queue for the thread. */
Tcl_Event *hold;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
| ︙ | ︙ | |||
845 846 847 848 849 850 851 | * * Side effects: * May reduce the length of the next sleep in the tsdPtr-> * *---------------------------------------------------------------------- */ | < < < < < | > > | | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 |
*
* Side effects:
* May reduce the length of the next sleep in the tsdPtr->
*
*----------------------------------------------------------------------
*/
void
Tcl_SetMaxBlockTime(
const Tcl_Time *timePtr) /* Specifies a maximum elapsed time for the
* next blocking operation in the event
* tsdPtr-> */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->blockTimeSet || (timePtr->sec < tsdPtr->blockTime.sec)
|| ((timePtr->sec == tsdPtr->blockTime.sec)
&& (timePtr->usec < tsdPtr->blockTime.usec))) {
tsdPtr->blockTime = *timePtr;
tsdPtr->blockTimeSet = 1;
}
/*
* If we are called outside an event source traversal, set the timeout
* immediately.
*/
if (!tsdPtr->inTraversal) {
Tcl_SetTimer(&tsdPtr->blockTime);
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_DoOneEvent --
|
| ︙ | ︙ | |||
944 945 946 947 948 949 950 |
* combination of TCL_DONT_WAIT,
* TCL_WINDOW_EVENTS, TCL_FILE_EVENTS,
* TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
* others defined by event sources. */
{
int result = 0, oldMode;
EventSource *sourcePtr;
| | | 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 |
* combination of TCL_DONT_WAIT,
* TCL_WINDOW_EVENTS, TCL_FILE_EVENTS,
* TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
* others defined by event sources. */
{
int result = 0, oldMode;
EventSource *sourcePtr;
Tcl_Time *timePtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* The first thing we do is to service any asynchronous event handlers.
*/
if (Tcl_AsyncReady()) {
|
| ︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 |
/*
* If TCL_DONT_WAIT is set, be sure to poll rather than blocking,
* otherwise reset the block time to infinity.
*/
if (flags & TCL_DONT_WAIT) {
| | | > | | | | | | | 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 |
/*
* If TCL_DONT_WAIT is set, be sure to poll rather than blocking,
* otherwise reset the block time to infinity.
*/
if (flags & TCL_DONT_WAIT) {
tsdPtr->blockTime.sec = 0;
tsdPtr->blockTime.usec = 0;
tsdPtr->blockTimeSet = 1;
} else {
tsdPtr->blockTimeSet = 0;
}
/*
* Set up all the event sources for new events. This will cause the
* block time to be updated if necessary.
*/
tsdPtr->inTraversal = 1;
for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->setupProc) {
sourcePtr->setupProc(sourcePtr->clientData, flags);
}
}
tsdPtr->inTraversal = 0;
if ((flags & TCL_DONT_WAIT) || tsdPtr->blockTimeSet) {
timePtr = &tsdPtr->blockTime;
} else {
timePtr = NULL;
}
/*
* Wait for a new event or a timeout. If Tcl_WaitForEvent returns -1,
* we should abort Tcl_DoOneEvent.
*/
result = Tcl_WaitForEvent(timePtr);
if (result < 0) {
result = 0;
break;
}
/*
* Check all the event sources for new events.
|
| ︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 |
/*
* Make a single pass through all event sources, queued events, and idle
* handlers. Note that we wait to update the notifier timer until the end
* so we can avoid multiple changes.
*/
| | | | 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 |
/*
* Make a single pass through all event sources, queued events, and idle
* handlers. Note that we wait to update the notifier timer until the end
* so we can avoid multiple changes.
*/
tsdPtr->inTraversal = 1;
tsdPtr->blockTimeSet = 0;
for (sourcePtr = tsdPtr->firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->setupProc) {
sourcePtr->setupProc(sourcePtr->clientData, TCL_ALL_EVENTS);
}
}
|
| ︙ | ︙ | |||
1177 1178 1179 1180 1181 1182 1183 |
result = 1;
}
if (TclServiceIdle()) {
result = 1;
}
if (!tsdPtr->blockTimeSet) {
| | | | | 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 |
result = 1;
}
if (TclServiceIdle()) {
result = 1;
}
if (!tsdPtr->blockTimeSet) {
Tcl_SetTimer(NULL);
} else {
Tcl_SetTimer(&tsdPtr->blockTime);
}
tsdPtr->inTraversal = 0;
tsdPtr->serviceMode = TCL_SERVICE_ALL;
return result;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1306 1307 1308 1309 1310 1311 1312 | * See the platform-specific implementations. * *---------------------------------------------------------------------- */ void Tcl_AlertNotifier( | | | 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 |
* See the platform-specific implementations.
*
*----------------------------------------------------------------------
*/
void
Tcl_AlertNotifier(
void *clientData) /* Pointer to thread data. */
{
if (tclNotifierHooks.alertNotifierProc) {
tclNotifierHooks.alertNotifierProc(clientData);
} else {
TclpAlertNotifier(clientData);
}
}
|
| ︙ | ︙ | |||
1363 1364 1365 1366 1367 1368 1369 | * See the platform-specific implementations. * *---------------------------------------------------------------------- */ void Tcl_SetTimer( | | < < < < < < < < < < < < < < < < < < < < < < | | 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 |
* See the platform-specific implementations.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetTimer(
const Tcl_Time *timePtr) /* Timeout value, may be NULL. */
{
if (tclNotifierHooks.setTimerProc) {
tclNotifierHooks.setTimerProc(timePtr);
} else {
TclpSetTimer(timePtr);
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_WaitForEvent --
|
| ︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 | * Queues file events that are detected by the notifier. * *---------------------------------------------------------------------- */ int Tcl_WaitForEvent( | | < < < < | < < < < < < < < < < < < < < < < | 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 |
* Queues file events that are detected by the notifier.
*
*----------------------------------------------------------------------
*/
int
Tcl_WaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
if (tclNotifierHooks.waitForEventProc) {
return tclNotifierHooks.waitForEventProc(timePtr);
} else {
return TclpWaitForEvent(timePtr);
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_CreateFileHandler --
*
|
| ︙ | ︙ | |||
1475 1476 1477 1478 1479 1480 1481 |
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
* conditions under which proc should be
* called. */
Tcl_FileProc *proc, /* Function to call for each selected
* event. */
| | | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 |
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
* conditions under which proc should be
* called. */
Tcl_FileProc *proc, /* Function to call for each selected
* event. */
void *clientData) /* Arbitrary data to pass to proc. */
{
if (tclNotifierHooks.createFileHandlerProc) {
tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
} else {
TclpCreateFileHandler(fd, mask, proc, clientData);
}
}
|
| ︙ | ︙ |
Changes to generic/tclOO.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
/*
* Commands in oo and oo::Helpers.
*/
static const struct StdCommands {
const char *name;
| | | < | | | | | | | | | | | | | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/*
* Commands in oo and oo::Helpers.
*/
static const struct StdCommands {
const char *name;
Tcl_ObjCmdProc *objProc;
Tcl_ObjCmdProc *nreProc;
CompileProc *compileProc;
} ooCmds[] = {
{"define", TclOODefineObjCmd, NULL, NULL},
{"objdefine", TclOOObjDefObjCmd, NULL, NULL},
{"copy", TclOOCopyObjectCmd, NULL, NULL},
{"DelegateName", TclOODelegateNameObjCmd, NULL, NULL},
{NULL, NULL, NULL, NULL}
}, helpCmds[] = {
{"callback", TclOOCallbackObjCmd, NULL, NULL},
{"mymethod", TclOOCallbackObjCmd, NULL, NULL},
{"classvariable", TclOOClassVariableObjCmd, NULL, NULL},
{"link", TclOOLinkObjCmd, NULL, NULL},
{"next", NULL, TclOONextObjCmd, TclCompileObjectNextCmd},
{"nextto", NULL, TclOONextToObjCmd, TclCompileObjectNextToCmd},
{"self", TclOOSelfObjCmd, NULL, TclCompileObjectSelfCmd},
{NULL, NULL, NULL, NULL}
};
/*
* Commands in oo::define and oo::objdefine.
*/
static const struct DefineCommands {
const char *name;
Tcl_ObjCmdProc *objProc;
int flag;
} defineCmds[] = {
{"classmethod", TclOODefineClassMethodObjCmd, 0},
{"constructor", TclOODefineConstructorObjCmd, 0},
{"definitionnamespace", TclOODefineDefnNsObjCmd, 0},
{"deletemethod", TclOODefineDeleteMethodObjCmd, 0},
{"destructor", TclOODefineDestructorObjCmd, 0},
|
| ︙ | ︙ | |||
112 113 114 115 116 117 118 | static Tcl_CmdDeleteProc MyDeleted; static Tcl_NamespaceDeleteProc ObjectNamespaceDeleted; static Tcl_CommandTraceProc ObjectRenamedTrace; static inline void RemoveClass(Class **list, size_t num, size_t idx); static inline void RemoveObject(Object **list, size_t num, size_t idx); static inline void SquelchCachedName(Object *oPtr); | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
static Tcl_CmdDeleteProc MyDeleted;
static Tcl_NamespaceDeleteProc ObjectNamespaceDeleted;
static Tcl_CommandTraceProc ObjectRenamedTrace;
static inline void RemoveClass(Class **list, size_t num, size_t idx);
static inline void RemoveObject(Object **list, size_t num, size_t idx);
static inline void SquelchCachedName(Object *oPtr);
static Tcl_ObjCmdProc PublicNRObjectCmd;
static Tcl_ObjCmdProc PrivateNRObjectCmd;
static Tcl_ObjCmdProc MyClassNRObjCmd;
static Tcl_CmdDeleteProc MyClassDeleted;
/*
* Methods in the oo::object and oo::class classes. First, we define a helper
* macro that makes building the method type declaration structure a lot
* easier. No point in making life harder than it has to be!
*
* Note that the core methods don't need clone or free proc callbacks.
*/
#define DCM(name,visibility,proc) \
{name,visibility,\
{TCL_OO_METHOD_VERSION_CURRENT,"core method: "#name,proc,NULL,NULL}}
static const DeclaredClassMethod objMethods[] = {
DCM("<cloned>", 0, TclOO_Object_Cloned),
DCM("destroy", 1, TclOO_Object_Destroy),
DCM("eval", 0, TclOO_Object_Eval),
DCM("unknown", 0, TclOO_Object_Unknown),
DCM("variable", 0, TclOO_Object_LinkVar),
DCM("varname", 0, TclOO_Object_VarName),
{NULL, 0, {0, NULL, NULL, NULL, NULL}}
}, clsMethods[] = {
DCM("<cloned>", 0, TclOO_Class_Cloned),
DCM("create", 1, TclOO_Class_Create),
DCM("new", 1, TclOO_Class_New),
DCM("createWithNamespace", 0, TclOO_Class_CreateNs),
{NULL, 0, {0, NULL, NULL, NULL, NULL}}
}, cfgMethods[] = {
DCM("configure", 1, TclOO_Configurable_Configure),
{NULL, 0, {0, NULL, NULL, NULL, NULL}}
}, singletonMethods[] = {
DCM("new", 1, TclOO_Singleton_New),
{NULL, 0, {0, NULL, NULL, NULL, NULL}}
}, singletonInstanceMethods[] = {
DCM("<cloned>", 0, TclOO_SingletonInstance_Cloned),
DCM("destroy", 1, TclOO_SingletonInstance_Destroy),
{NULL, 0, {0, NULL, NULL, NULL, NULL}}
};
/*
* And for the oo::class constructor...
*/
static const Tcl_MethodType classConstructor = {
TCL_OO_METHOD_VERSION_CURRENT,
"oo::class constructor",
TclOO_Class_Constructor, NULL, NULL
};
/*
* And the oo::configurable constructor...
*/
static const Tcl_MethodType configurableConstructor = {
TCL_OO_METHOD_VERSION_CURRENT,
"oo::configurable constructor",
TclOO_Configurable_Constructor, NULL, NULL
};
/*
* The scripted part of TclOO: (legacy) package registration. There's no C API
* at all for doing this, not even internally to Tcl.
|
| ︙ | ︙ | |||
335 336 337 338 339 340 341 |
* ----------------------------------------------------------------------
*/
static inline void
CreateCmdInNS(
Tcl_Interp *interp,
Tcl_Namespace *namespacePtr,
const char *name,
| | | | < | < | | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
* ----------------------------------------------------------------------
*/
static inline void
CreateCmdInNS(
Tcl_Interp *interp,
Tcl_Namespace *namespacePtr,
const char *name,
Tcl_ObjCmdProc *cmdProc,
Tcl_ObjCmdProc *nreProc,
CompileProc *compileProc)
{
Command *cmdPtr;
if (cmdProc == NULL && nreProc == NULL) {
Tcl_Panic("must supply at least one implementation function");
}
cmdPtr = (Command *) TclCreateObjCommandInNs(interp, name,
namespacePtr, cmdProc, NULL, NULL);
cmdPtr->nreProc = nreProc;
cmdPtr->compileProc = compileProc;
}
/*
* ----------------------------------------------------------------------
*
* CreateConstantInNSStr --
*
* Wrapper around TclCreateConstantInNS to make using it with string
* constants easier.
*
* ----------------------------------------------------------------------
*/
static inline void
CreateConstantInNSStr(
Tcl_Interp *interp,
Tcl_Namespace *namespacePtr,/* The namespace to contain the constant. */
const char *nameStr, /* The unqualified name of the constant. */
const char *valueStr) /* The value to put in the constant. */
{
Tcl_Obj *nameObj = Tcl_NewStringObj(nameStr, TCL_AUTO_LENGTH);
Tcl_IncrRefCount(nameObj);
Tcl_Obj *valueObj = Tcl_NewStringObj(valueStr, TCL_AUTO_LENGTH);
Tcl_IncrRefCount(valueObj);
TclCreateConstantInNS(interp, (Namespace *) namespacePtr, nameObj, valueObj);
Tcl_DecrRefCount(nameObj);
|
| ︙ | ︙ | |||
485 486 487 488 489 490 491 |
* Finish setting up the class of classes by marking the 'new' method as
* private; classes, unlike general objects, must have explicit names. We
* also need to create the constructor for classes.
*/
TclNewLiteralStringObj(namePtr, "new");
TclNewInstanceMethod(interp, (Tcl_Object) fPtr->classCls->thisPtr,
| | | | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
* Finish setting up the class of classes by marking the 'new' method as
* private; classes, unlike general objects, must have explicit names. We
* also need to create the constructor for classes.
*/
TclNewLiteralStringObj(namePtr, "new");
TclNewInstanceMethod(interp, (Tcl_Object) fPtr->classCls->thisPtr,
namePtr /* keeps ref */, 0 /* private */, NULL, NULL);
Tcl_BounceRefCount(namePtr);
fPtr->classCls->constructorPtr = (Method *) TclNewMethod(
(Tcl_Class) fPtr->classCls, NULL, 0, &classConstructor, NULL);
/*
* Create non-object commands and plug ourselves into the Tcl [info]
* ensemble.
*/
for (i = 0 ; helpCmds[i].name ; i++) {
CreateCmdInNS(interp, fPtr->helpersNs, helpCmds[i].name,
helpCmds[i].objProc, helpCmds[i].nreProc,
helpCmds[i].compileProc);
}
for (i = 0 ; ooCmds[i].name ; i++) {
CreateCmdInNS(interp, fPtr->ooNs, ooCmds[i].name,
ooCmds[i].objProc, ooCmds[i].nreProc,
ooCmds[i].compileProc);
}
TclOOInitInfo(interp);
/*
* Now make the class of slots.
*/
|
| ︙ | ︙ | |||
634 635 636 637 638 639 640 |
Class *classPtr)
{
Class **supers = (Class **) Tcl_Alloc(sizeof(Class *));
supers[0] = fPtr->classCls;
AddRef(supers[0]->thisPtr);
TclOOSetSuperclasses(classPtr, 1, supers);
}
| | > > > > > > > > > > > > > > > > > > > > > > > > > | | < < | | | | < < | | < < | | | < < < | | | | | | | | | < | | < | | > | | > | < | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 |
Class *classPtr)
{
Class **supers = (Class **) Tcl_Alloc(sizeof(Class *));
supers[0] = fPtr->classCls;
AddRef(supers[0]->thisPtr);
TclOOSetSuperclasses(classPtr, 1, supers);
}
/*
* ----------------------------------------------------------------------
*
* MakeAdditionalClasses --
*
* Make the extra classes in TclOO that aren't core to how it functions.
*
* ----------------------------------------------------------------------
*/
static void
MakeAdditionalClasses(
Foundation *fPtr,
Tcl_Namespace *defineNs,
Tcl_Namespace *objDefineNs)
{
Tcl_Interp *interp = fPtr->interp;
Object *singletonObj; /* A metaclass that is used to make classes
* that only permit one instance of them to
* exist. See singleton(n). */
Object *singletonInst; /* A mixin used to make an object so it won't
* be destroyed or cloned (or at least not
* easily). */
Object *abstractCls; /* A metaclass that is used to make classes
* that can't be directly instantiated. See
* abstract(n). */
Object *cfgSupObj; /* The class that contains the implementation
* of the actual 'configure' method (mixed into
* actually configurable classes). The
* 'configure' method is in tclOOBasic.c. */
Object *configurableObj; /* A metaclass that is used to make classes
* that can be configured in their creation
* phase (and later too). All the metaclass
* itself does is arrange for the class created
* to have a 'configure' method and for
* oo::define and oo::objdefine (on the class
* and its instances) to have a property
* definition for setting things up for
* 'configure'. */
Class *singletonCls, *cfgSupCls, *configurableCls;
Tcl_Namespace *cfgObjNs, *cfgClsNs;
Tcl_Obj *nsName;
/*
* Make the oo::singleton class, the SingletonInstance class, and install
* their standard defined methods.
*/
singletonObj = (Object *) Tcl_NewObjectInstance(interp,
(Tcl_Class) fPtr->classCls, "::oo::singleton",
NULL, TCL_INDEX_NONE, NULL, 0);
singletonCls = singletonObj->classPtr;
TclOODefineBasicMethods(singletonCls, singletonMethods);
/* Set the superclass to oo::class */
MarkAsMetaclass(fPtr, singletonCls);
/* Unexport methods */
TclOOUnexportMethods(singletonCls, "create", "createWithNamespace", NULL);
singletonInst = (Object *) Tcl_NewObjectInstance(interp,
(Tcl_Class) fPtr->classCls, "::oo::SingletonInstance",
NULL, TCL_INDEX_NONE, NULL, 0);
TclOODefineBasicMethods(singletonInst->classPtr, singletonInstanceMethods);
/*
* Make the oo::abstract class.
*/
abstractCls = (Object *) Tcl_NewObjectInstance(interp,
(Tcl_Class) fPtr->classCls, "::oo::abstract",
NULL, TCL_INDEX_NONE, NULL, 0);
/* Set the superclass to oo::class */
MarkAsMetaclass(fPtr, abstractCls->classPtr);
/* Unexport methods */
TclOOUnexportMethods(abstractCls->classPtr,
"create", "createWithNamespace", "new", NULL);
/*
* Make the configurable class and install its standard defined method.
*/
cfgSupObj = (Object *) Tcl_NewObjectInstance(interp,
(Tcl_Class) fPtr->classCls, "::oo::configuresupport::configurable",
NULL, TCL_INDEX_NONE, NULL, 0);
cfgSupCls = cfgSupObj->classPtr;
TclOODefineBasicMethods(cfgSupCls, cfgMethods);
/* Namespaces used as implementation vectors for oo::define and
* oo::objdefine when the class/instance is configurable.
* Note that these also contain commands implemented in C,
* especially the [property] definition command. */
cfgObjNs = Tcl_CreateNamespace(interp,
"::oo::configuresupport::configurableobject", NULL, NULL);
TclCreateObjCommandInNs(interp, "property", cfgObjNs,
TclOODefinePropertyCmd, INT2PTR(1) /*useInstance*/, NULL);
TclCreateObjCommandInNs(interp, "properties", cfgObjNs,
TclOODefinePropertyCmd, INT2PTR(1) /*useInstance*/, NULL);
Tcl_Export(interp, cfgObjNs, "property", /*reset*/1);
TclSetNsPath((Namespace *) cfgObjNs, 1, &objDefineNs);
cfgClsNs = Tcl_CreateNamespace(interp,
"::oo::configuresupport::configurableclass", NULL, NULL);
TclCreateObjCommandInNs(interp, "property", cfgClsNs,
TclOODefinePropertyCmd, INT2PTR(0) /*useInstance*/, NULL);
TclCreateObjCommandInNs(interp, "properties", cfgClsNs,
TclOODefinePropertyCmd, INT2PTR(0) /*useInstance*/, NULL);
Tcl_Export(interp, cfgClsNs, "property", /*reset*/1);
TclSetNsPath((Namespace *) cfgClsNs, 1, &defineNs);
/* The oo::configurable class itself, a metaclass to apply
* oo::configuresupport::configurable correctly. */
configurableObj = (Object *) Tcl_NewObjectInstance(interp,
(Tcl_Class) fPtr->classCls, "::oo::configurable",
NULL, TCL_INDEX_NONE, NULL, 0);
configurableCls = configurableObj->classPtr;
MarkAsMetaclass(fPtr, configurableCls);
Tcl_ClassSetConstructor(interp, (Tcl_Class) configurableCls, TclNewMethod(
(Tcl_Class) configurableCls, NULL, 0, &configurableConstructor, NULL));
/* Set the definition namespaces of oo::configurable and
* oo::configuresupport::configurable. */
nsName = TclNewNamespaceObj(cfgClsNs);
Tcl_IncrRefCount(nsName);
if (cfgSupCls->clsDefinitionNs != NULL) {
Tcl_DecrRefCount(cfgSupCls->clsDefinitionNs);
}
cfgSupCls->clsDefinitionNs = nsName;
Tcl_IncrRefCount(nsName);
if (configurableCls->clsDefinitionNs != NULL) {
Tcl_DecrRefCount(configurableCls->clsDefinitionNs);
}
configurableCls->clsDefinitionNs = nsName;
nsName = TclNewNamespaceObj(cfgObjNs);
Tcl_IncrRefCount(nsName);
if (cfgSupCls->objDefinitionNs != NULL) {
Tcl_DecrRefCount(cfgSupCls->objDefinitionNs);
}
cfgSupCls->objDefinitionNs = nsName;
}
|
| ︙ | ︙ | |||
980 981 982 983 984 985 986 |
/*
* Add the NRE command and trace directly. While this breaks a number of
* abstractions, it is faster and we're inside Tcl here so we're allowed.
*/
cmdPtr = (Command *) oPtr->command;
| | | 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 |
/*
* Add the NRE command and trace directly. While this breaks a number of
* abstractions, it is faster and we're inside Tcl here so we're allowed.
*/
cmdPtr = (Command *) oPtr->command;
cmdPtr->nreProc = PublicNRObjectCmd;
cmdPtr->tracePtr = tracePtr = (CommandTrace *)
Tcl_Alloc(sizeof(CommandTrace));
tracePtr->traceProc = ObjectRenamedTrace;
tracePtr->clientData = oPtr;
tracePtr->flags = TCL_TRACE_RENAME|TCL_TRACE_DELETE;
tracePtr->nextPtr = NULL;
tracePtr->refCount = 1;
|
| ︙ | ︙ | |||
1038 1039 1040 1041 1042 1043 1044 1045 1046 |
static void
MyDeleted(
void *clientData) /* Reference to the object whose [my] has been
* squelched. */
{
Object *oPtr = (Object *) clientData;
if (oPtr->linkedCmdsList) {
| > > < < | | 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 |
static void
MyDeleted(
void *clientData) /* Reference to the object whose [my] has been
* squelched. */
{
Object *oPtr = (Object *) clientData;
Tcl_Size linkc, i;
Tcl_Obj **linkv, *link;
if (oPtr->linkedCmdsList) {
TclListObjGetElements(NULL, oPtr->linkedCmdsList, &linkc, &linkv);
for (i=0 ; i<linkc ; i++) {
link = linkv[i];
(void) Tcl_DeleteCommand(oPtr->fPtr->interp, TclGetString(link));
}
Tcl_DecrRefCount(oPtr->linkedCmdsList);
oPtr->linkedCmdsList = NULL;
}
oPtr->myCommand = NULL;
}
|
| ︙ | ︙ | |||
1359 1360 1361 1362 1363 1364 1365 |
if (i) {
Tcl_Free(clsPtr->privateVariables.list);
}
if (IsRootClass(oPtr) && !Destructing(fPtr->objectCls->thisPtr)) {
Tcl_DeleteCommandFromToken(interp, fPtr->objectCls->thisPtr->command);
}
| < < < < < | 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 |
if (i) {
Tcl_Free(clsPtr->privateVariables.list);
}
if (IsRootClass(oPtr) && !Destructing(fPtr->objectCls->thisPtr)) {
Tcl_DeleteCommandFromToken(interp, fPtr->objectCls->thisPtr->command);
}
}
/*
* ----------------------------------------------------------------------
*
* ObjectNamespaceDeleted --
*
|
| ︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 |
if (contextPtr != NULL) {
int result;
Tcl_InterpState state;
contextPtr->callPtr->flags |= DESTRUCTOR;
contextPtr->skip = 0;
state = Tcl_SaveInterpState(interp, TCL_OK);
| | | 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 |
if (contextPtr != NULL) {
int result;
Tcl_InterpState state;
contextPtr->callPtr->flags |= DESTRUCTOR;
contextPtr->skip = 0;
state = Tcl_SaveInterpState(interp, TCL_OK);
result = Tcl_NRCallObjProc(interp, TclOOInvokeContext,
contextPtr, 0, NULL);
if (result != TCL_OK) {
Tcl_BackgroundException(interp, result);
}
Tcl_RestoreInterpState(interp, state);
TclOODeleteContext(contextPtr);
}
|
| ︙ | ︙ | |||
1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 |
*/
int
TclOODecrRefCount(
Object *oPtr)
{
if (oPtr->refCount-- <= 1) {
if (oPtr->classPtr != NULL) {
Tcl_Free(oPtr->classPtr);
}
Tcl_Free(oPtr);
return 1;
}
return 0;
}
/*
* ----------------------------------------------------------------------
*
* TclOOObjectDestroyed --
*
* Returns TCL_OK if an object is entirely deleted, i.e. the destruction
* sequence has completed.
*
* ----------------------------------------------------------------------
*/
| > < > | > > > | 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 |
*/
int
TclOODecrRefCount(
Object *oPtr)
{
if (oPtr->refCount-- <= 1) {
if (oPtr->classPtr != NULL) {
Tcl_Free(oPtr->classPtr);
}
Tcl_Free(oPtr);
return 1;
}
return 0;
}
/*
* ----------------------------------------------------------------------
*
* TclOOObjectDestroyed --
*
* Returns TCL_OK if an object is entirely deleted, i.e. the destruction
* sequence has completed.
*
* ----------------------------------------------------------------------
*/
int
TclOOObjectDestroyed(
Object *oPtr)
{
return (oPtr->namespacePtr == NULL);
}
/*
* ----------------------------------------------------------------------
*
* TclOORemoveFromInstances --
*
* Utility function to remove an object from the list of instances within
* a class.
*
* ----------------------------------------------------------------------
*/
int
TclOORemoveFromInstances(
Object *oPtr, /* The instance to remove. */
Class *clsPtr) /* The class (possibly) containing the
* reference to the instance. */
{
Tcl_Size i;
int res = 0;
Object *instPtr;
FOREACH(instPtr, clsPtr->instances) {
if (oPtr == instPtr) {
RemoveItem(Object, clsPtr->instances, i);
TclOODecrRefCount(oPtr);
res++;
break;
}
}
return res;
}
/*
* ----------------------------------------------------------------------
*
* TclOOAddToInstances --
*
|
| ︙ | ︙ | |||
1701 1702 1703 1704 1705 1706 1707 | * * Utility function to remove a class from the list of mixins within an * object. * * ---------------------------------------------------------------------- */ | | > > > | > > > | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 |
*
* Utility function to remove a class from the list of mixins within an
* object.
*
* ----------------------------------------------------------------------
*/
int
TclOORemoveFromMixins(
Class *mixinPtr, /* The mixin to remove. */
Object *oPtr) /* The object (possibly) containing the
* reference to the mixin. */
{
Tcl_Size i;
int res = 0;
Class *mixPtr;
FOREACH(mixPtr, oPtr->mixins) {
if (mixinPtr == mixPtr) {
RemoveItem(Class, oPtr->mixins, i);
TclOODecrRefCount(mixPtr->thisPtr);
res++;
break;
}
}
if (oPtr->mixins.num == 0) {
Tcl_Free(oPtr->mixins.list);
oPtr->mixins.list = NULL;
}
return res;
}
/*
* ----------------------------------------------------------------------
*
* TclOORemoveFromSubclasses --
*
* Utility function to remove a class from the list of subclasses within
* another class. Returns the number of removals performed.
*
* ----------------------------------------------------------------------
*/
int
TclOORemoveFromSubclasses(
Class *subPtr, /* The subclass to remove. */
Class *superPtr) /* The superclass to possibly remove the
* subclass reference from. */
{
Tcl_Size i;
int res = 0;
Class *subclsPtr;
FOREACH(subclsPtr, superPtr->subclasses) {
if (subPtr == subclsPtr) {
RemoveItem(Class, superPtr->subclasses, i);
TclOODecrRefCount(subPtr->thisPtr);
res++;
}
}
return res;
}
/*
* ----------------------------------------------------------------------
*
* TclOOAddToSubclasses --
*
|
| ︙ | ︙ | |||
1798 1799 1800 1801 1802 1803 1804 | * * Utility function to remove a class from the list of mixinSubs within * another class. * * ---------------------------------------------------------------------- */ | | > > > | 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 |
*
* Utility function to remove a class from the list of mixinSubs within
* another class.
*
* ----------------------------------------------------------------------
*/
int
TclOORemoveFromMixinSubs(
Class *subPtr, /* The subclass to remove. */
Class *superPtr) /* The superclass to possibly remove the
* subclass reference from. */
{
Tcl_Size i;
int res = 0;
Class *subclsPtr;
FOREACH(subclsPtr, superPtr->mixinSubs) {
if (subPtr == subclsPtr) {
RemoveItem(Class, superPtr->mixinSubs, i);
TclOODecrRefCount(subPtr->thisPtr);
res++;
break;
}
}
return res;
}
/*
* ----------------------------------------------------------------------
*
* TclOOAddToMixinSubs --
*
|
| ︙ | ︙ | |||
1981 1982 1983 1984 1985 1986 1987 | contextPtr->skip = skip; /* * Adjust the ensemble tracking record if necessary. [Bug 3514761] */ isRoot = TclInitRewriteEnsemble(interp, skip, skip, objv); | | | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 |
contextPtr->skip = skip;
/*
* Adjust the ensemble tracking record if necessary. [Bug 3514761]
*/
isRoot = TclInitRewriteEnsemble(interp, skip, skip, objv);
result = Tcl_NRCallObjProc(interp, TclOOInvokeContext, contextPtr,
objc, objv);
if (isRoot) {
TclResetRewriteEnsemble(interp, 1);
}
clientData[0] = contextPtr;
|
| ︙ | ︙ | |||
2061 2062 2063 2064 2065 2066 2067 |
TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL);
}
/*
* Fire off the constructors non-recursively.
*/
| | | | 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 |
TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL);
}
/*
* Fire off the constructors non-recursively.
*/
TclNRAddCallback(interp, FinalizeAlloc, contextPtr, oPtr, state,
objectPtr);
TclPushTailcallPoint(interp);
return TclOOInvokeContext(contextPtr, interp, objc, objv);
}
/*
* ----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2514 2515 2516 2517 2518 2519 2520 |
if (contextPtr) {
args[0] = TclOOObjectName(interp, o2Ptr);
args[1] = oPtr->fPtr->clonedName;
args[2] = TclOOObjectName(interp, oPtr);
Tcl_IncrRefCount(args[0]);
Tcl_IncrRefCount(args[1]);
Tcl_IncrRefCount(args[2]);
| | | 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 |
if (contextPtr) {
args[0] = TclOOObjectName(interp, o2Ptr);
args[1] = oPtr->fPtr->clonedName;
args[2] = TclOOObjectName(interp, oPtr);
Tcl_IncrRefCount(args[0]);
Tcl_IncrRefCount(args[1]);
Tcl_IncrRefCount(args[2]);
result = Tcl_NRCallObjProc(interp, TclOOInvokeContext, contextPtr, 3,
args);
TclDecrRefCount(args[0]);
TclDecrRefCount(args[1]);
TclDecrRefCount(args[2]);
TclOODeleteContext(contextPtr);
if (result == TCL_ERROR) {
Tcl_AddErrorInfo(interp,
|
| ︙ | ︙ | |||
2552 2553 2554 2555 2556 2557 2558 |
static int
CloneObjectMethod(
Tcl_Interp *interp,
Object *oPtr,
Method *mPtr,
Tcl_Obj *namePtr)
{
| | | | | | | | | | | | 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 |
static int
CloneObjectMethod(
Tcl_Interp *interp,
Object *oPtr,
Method *mPtr,
Tcl_Obj *namePtr)
{
if (mPtr->typePtr == NULL) {
TclNewInstanceMethod(interp, (Tcl_Object) oPtr, namePtr,
mPtr->flags & PUBLIC_METHOD, NULL, NULL);
} else if (mPtr->typePtr->cloneProc) {
void *newClientData;
if (mPtr->typePtr->cloneProc(interp, mPtr->clientData,
&newClientData) != TCL_OK) {
return TCL_ERROR;
}
TclNewInstanceMethod(interp, (Tcl_Object) oPtr, namePtr,
mPtr->flags & PUBLIC_METHOD, mPtr->typePtr, newClientData);
} else {
TclNewInstanceMethod(interp, (Tcl_Object) oPtr, namePtr,
mPtr->flags & PUBLIC_METHOD, mPtr->typePtr, mPtr->clientData);
}
return TCL_OK;
}
static int
CloneClassMethod(
Tcl_Interp *interp,
Class *clsPtr,
Method *mPtr,
Tcl_Obj *namePtr,
Method **m2PtrPtr)
{
Method *m2Ptr;
if (mPtr->typePtr == NULL) {
m2Ptr = (Method *) TclNewMethod((Tcl_Class) clsPtr,
namePtr, mPtr->flags & PUBLIC_METHOD, NULL, NULL);
} else if (mPtr->typePtr->cloneProc) {
void *newClientData;
if (mPtr->typePtr->cloneProc(interp, mPtr->clientData,
&newClientData) != TCL_OK) {
return TCL_ERROR;
}
m2Ptr = (Method *) TclNewMethod((Tcl_Class) clsPtr,
namePtr, mPtr->flags & PUBLIC_METHOD, mPtr->typePtr,
newClientData);
} else {
m2Ptr = (Method *) TclNewMethod((Tcl_Class) clsPtr,
namePtr, mPtr->flags & PUBLIC_METHOD, mPtr->typePtr,
mPtr->clientData);
}
if (m2PtrPtr != NULL) {
*m2PtrPtr = m2Ptr;
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
2809 2810 2811 2812 2813 2814 2815 |
* ----------------------------------------------------------------------
*/
int
TclOOPublicObjectCmd(
void *clientData,
Tcl_Interp *interp,
| | | | | | | | 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 |
* ----------------------------------------------------------------------
*/
int
TclOOPublicObjectCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
return Tcl_NRCallObjProc(interp, PublicNRObjectCmd, clientData, objc, objv);
}
static int
PublicNRObjectCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
return TclOOObjectCmdCore((Object *) clientData, interp, objc, objv,
PUBLIC_METHOD, NULL);
}
int
TclOOPrivateObjectCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
return Tcl_NRCallObjProc(interp, PrivateNRObjectCmd, clientData, objc, objv);
}
static int
PrivateNRObjectCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
return TclOOObjectCmdCore((Object *) clientData, interp, objc, objv, 0, NULL);
}
int
TclOOInvokeObject(
|
| ︙ | ︙ | |||
2891 2892 2893 2894 2895 2896 2897 |
* ----------------------------------------------------------------------
*/
int
TclOOMyClassObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | | | 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 |
* ----------------------------------------------------------------------
*/
int
TclOOMyClassObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
return Tcl_NRCallObjProc(interp, MyClassNRObjCmd, clientData, objc, objv);
}
static int
MyClassNRObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) clientData;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "methodName ?arg ...?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
3064 3065 3066 3067 3068 3069 3070 |
}
/*
* Invoke the call chain, locking the object structure against deletion
* for the duration.
*/
| | | 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 |
}
/*
* Invoke the call chain, locking the object structure against deletion
* for the duration.
*/
TclNRAddCallback(interp, FinalizeObjectCall, contextPtr, NULL,NULL,NULL);
return TclOOInvokeContext(contextPtr, interp, objc, objv);
}
static int
FinalizeObjectCall(
void *data[],
TCL_UNUSED(Tcl_Interp *),
|
| ︙ | ︙ | |||
3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 |
Tcl_Size objc,
Tcl_Obj *const *objv,
Tcl_Size skip)
{
CallContext *contextPtr = (CallContext *) context;
size_t savedIndex = contextPtr->index;
size_t savedSkip = contextPtr->skip;
if (contextPtr->index + 1 >= contextPtr->callPtr->numChain) {
/*
* We're at the end of the chain; generate an error message unless the
* interpreter is being torn down, in which case we might be getting
* here because of methods/destructors doing a [next] (or equivalent)
* unexpectedly.
*/
if (Tcl_InterpDeleted(interp)) {
return TCL_OK;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
| > > > > > > > > > > > > | | 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 |
Tcl_Size objc,
Tcl_Obj *const *objv,
Tcl_Size skip)
{
CallContext *contextPtr = (CallContext *) context;
size_t savedIndex = contextPtr->index;
size_t savedSkip = contextPtr->skip;
int result;
if (contextPtr->index + 1 >= contextPtr->callPtr->numChain) {
/*
* We're at the end of the chain; generate an error message unless the
* interpreter is being torn down, in which case we might be getting
* here because of methods/destructors doing a [next] (or equivalent)
* unexpectedly.
*/
const char *methodType;
if (Tcl_InterpDeleted(interp)) {
return TCL_OK;
}
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
methodType = "constructor";
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
methodType = "destructor";
} else {
methodType = "method";
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"no next %s implementation", methodType));
OO_ERROR(interp, NOTHING_NEXT);
return TCL_ERROR;
}
/*
* Advance to the next method implementation in the chain in the method
* call context while we process the body. However, need to adjust the
|
| ︙ | ︙ | |||
3143 3144 3145 3146 3147 3148 3149 |
contextPtr->index++;
contextPtr->skip = skip;
/*
* Invoke the (advanced) method call context in the caller context.
*/
| | | | 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 |
contextPtr->index++;
contextPtr->skip = skip;
/*
* Invoke the (advanced) method call context in the caller context.
*/
result = Tcl_NRCallObjProc(interp, TclOOInvokeContext, contextPtr, objc,
objv);
/*
* Restore the call chain context index as we've finished the inner invoke
* and want to operate in the outer context again.
*/
contextPtr->index = savedIndex;
|
| ︙ | ︙ | |||
3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 |
if (contextPtr->index + 1 >= contextPtr->callPtr->numChain) {
/*
* We're at the end of the chain; generate an error message unless the
* interpreter is being torn down, in which case we might be getting
* here because of methods/destructors doing a [next] (or equivalent)
* unexpectedly.
*/
if (Tcl_InterpDeleted(interp)) {
return TCL_OK;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
| > > > > > > > > > > > | | 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 |
if (contextPtr->index + 1 >= contextPtr->callPtr->numChain) {
/*
* We're at the end of the chain; generate an error message unless the
* interpreter is being torn down, in which case we might be getting
* here because of methods/destructors doing a [next] (or equivalent)
* unexpectedly.
*/
const char *methodType;
if (Tcl_InterpDeleted(interp)) {
return TCL_OK;
}
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
methodType = "constructor";
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
methodType = "destructor";
} else {
methodType = "method";
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"no next %s implementation", methodType));
OO_ERROR(interp, NOTHING_NEXT);
return TCL_ERROR;
}
/*
* Advance to the next method implementation in the chain in the method
* call context while we process the body. However, need to adjust the
|
| ︙ | ︙ | |||
3247 3248 3249 3250 3251 3252 3253 |
* exactly the name of its public command. */
{
Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objPtr);
if (cmdPtr == NULL) {
goto notAnObject;
}
| | | | | 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 |
* exactly the name of its public command. */
{
Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, objPtr);
if (cmdPtr == NULL) {
goto notAnObject;
}
if (cmdPtr->objProc != TclOOPublicObjectCmd) {
cmdPtr = (Command *) TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (cmdPtr == NULL || cmdPtr->objProc != TclOOPublicObjectCmd) {
goto notAnObject;
}
}
return (Tcl_Object) cmdPtr->objClientData;
notAnObject:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s does not refer to an object", TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "OBJECT", TclGetString(objPtr),
(char *)NULL);
return NULL;
|
| ︙ | ︙ | |||
3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 |
* ----------------------------------------------------------------------
*/
Tcl_Obj *
TclOOObjectMyName(
Tcl_Interp *interp,
Object *oPtr)
{
if (!oPtr->myCommand) {
return NULL;
}
| > < | 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 |
* ----------------------------------------------------------------------
*/
Tcl_Obj *
TclOOObjectMyName(
Tcl_Interp *interp,
Object *oPtr)
{
Tcl_Obj *namePtr;
if (!oPtr->myCommand) {
return NULL;
}
TclNewObj(namePtr);
Tcl_GetCommandFullName(interp, oPtr->myCommand, namePtr);
return namePtr;
}
/*
* ----------------------------------------------------------------------
|
| ︙ | ︙ |
Changes to generic/tclOO.h.
1 2 3 4 5 6 | /* * tclOO.h -- * * This file contains the public API definitions and some of the function * declarations for the object-system (NB: not Tcl_Obj, but ::oo). * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * tclOO.h -- * * This file contains the public API definitions and some of the function * declarations for the object-system (NB: not Tcl_Obj, but ::oo). * * Copyright (c) 2006-2010 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef TCLOO_H_INCLUDED #define TCLOO_H_INCLUDED |
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | /* * Public datatypes for callbacks and structures used in the TIP#257 (OO) * implementation. These are used to implement custom types of method calls * and to allow the attachment of arbitrary data to objects and classes. */ | < | > < < > > < | > > < > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
/*
* Public datatypes for callbacks and structures used in the TIP#257 (OO)
* implementation. These are used to implement custom types of method calls
* and to allow the attachment of arbitrary data to objects and classes.
*/
typedef int (Tcl_MethodCallProc)(void *clientData, Tcl_Interp *interp,
Tcl_ObjectContext objectContext, int objc, Tcl_Obj *const *objv);
#if TCL_MAJOR_VERSION > 8
typedef int (Tcl_MethodCallProc2)(void *clientData, Tcl_Interp *interp,
Tcl_ObjectContext objectContext, Tcl_Size objc, Tcl_Obj *const *objv);
#endif
typedef void (Tcl_MethodDeleteProc)(void *clientData);
typedef int (Tcl_CloneProc)(Tcl_Interp *interp, void *oldClientData,
void **newClientData);
typedef void (Tcl_ObjectMetadataDeleteProc)(void *clientData);
typedef int (Tcl_ObjectMapMethodNameProc)(Tcl_Interp *interp,
Tcl_Object object, Tcl_Class *startClsPtr, Tcl_Obj *methodNameObj);
/*
* The type of a method implementation. This describes how to call the method
* implementation, how to delete it (when the object or class is deleted) and
* how to create a clone of it (when the object or class is copied).
*/
typedef struct Tcl_MethodType {
int version; /* Structure version field. Always to be equal
* to TCL_OO_METHOD_VERSION_(1|CURRENT) in
* declarations. */
const char *name; /* Name of this type of method, mostly for
* debugging purposes. */
Tcl_MethodCallProc *callProc;
/* How to invoke this method. */
Tcl_MethodDeleteProc *deleteProc;
/* How to delete this method's type-specific
* data, or NULL if the type-specific data
* does not need deleting. */
Tcl_CloneProc *cloneProc; /* How to copy this method's type-specific
* data, or NULL if the type-specific data can
* be copied directly. */
} Tcl_MethodType;
#if TCL_MAJOR_VERSION > 8
typedef struct Tcl_MethodType2 {
int version; /* Structure version field. Always to be equal
* to TCL_OO_METHOD_VERSION_2 in
* declarations. */
const char *name; /* Name of this type of method, mostly for
* debugging purposes. */
Tcl_MethodCallProc2 *callProc;
/* How to invoke this method. */
Tcl_MethodDeleteProc *deleteProc;
/* How to delete this method's type-specific
* data, or NULL if the type-specific data
* does not need deleting. */
Tcl_CloneProc *cloneProc; /* How to copy this method's type-specific
* data, or NULL if the type-specific data can
* be copied directly. */
} Tcl_MethodType2;
#endif
/*
* The correct value for the version field of the Tcl_MethodType structure.
* This allows new versions of the structure to be introduced without breaking
* binary compatibility.
*/
enum TclOOMethodVersion {
TCL_OO_METHOD_VERSION_CURRENT = 1
#if TCL_MAJOR_VERSION > 8
,
TCL_OO_METHOD_VERSION_1 = 1,
TCL_OO_METHOD_VERSION_2 = 2
#endif
};
/*
* Visibility constants for the flags parameter to Tcl_NewMethod and
* Tcl_NewInstanceMethod.
*/
enum TclOOMethodVisibilityFlags {
|
| ︙ | ︙ |
Changes to generic/tclOOBasic.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | static Tcl_NRPostProc AfterNRDestructor; static Tcl_NRPostProc PostClassConstructor; static Tcl_NRPostProc FinalizeConstruction; static Tcl_NRPostProc FinalizeEval; static Tcl_NRPostProc NextRestoreFrame; static Tcl_NRPostProc MarkAsSingleton; static Tcl_NRPostProc UpdateClassDelegatesAfterClone; | < < < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | static Tcl_NRPostProc AfterNRDestructor; static Tcl_NRPostProc PostClassConstructor; static Tcl_NRPostProc FinalizeConstruction; static Tcl_NRPostProc FinalizeEval; static Tcl_NRPostProc NextRestoreFrame; static Tcl_NRPostProc MarkAsSingleton; static Tcl_NRPostProc UpdateClassDelegatesAfterClone; /* * ---------------------------------------------------------------------- * * AddCreateCallback, FinalizeConstruction -- * * Special version of TclNRAddCallback that allows the caller to splice |
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
return result;
}
Tcl_SetObjResult(interp, TclOOObjectName(interp, oPtr));
return TCL_OK;
}
/*
| | | | | < | < < < | < < < < < < < < < < < < < < < < < < | < < | > | < < < < | | < < < | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
return result;
}
Tcl_SetObjResult(interp, TclOOObjectName(interp, oPtr));
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* MixinClassDelegates --
*
* Internal utility for setting up the class delegate.
* Runs after the class has called [oo::define] on its argument.
*
* ----------------------------------------------------------------------
*/
/*
* Look up the delegate for a class.
*/
static inline Class *
GetClassDelegate(
Tcl_Interp *interp,
Class *clsPtr)
{
Tcl_Obj *delegateName = Tcl_ObjPrintf("%s:: oo ::delegate",
clsPtr->thisPtr->namespacePtr->fullName);
Class *delegatePtr = TclOOGetClassFromObj(interp, delegateName);
Tcl_DecrRefCount(delegateName);
return delegatePtr;
}
/*
* Patches in the appropriate class delegates' superclasses.
* Somewhat messy because the list of superclasses isn't modified frequently.
*/
static inline void
SetDelegateSuperclasses(
Tcl_Interp *interp,
Class *clsPtr,
Class *delegatePtr)
{
/* Build new list of superclasses */
int i, j = delegatePtr->superclasses.num, k;
Class *superPtr, **supers = (Class **) Tcl_Alloc(sizeof(Class *) *
(delegatePtr->superclasses.num + clsPtr->superclasses.num));
if (delegatePtr->superclasses.num) {
memcpy(supers, delegatePtr->superclasses.list,
sizeof(Class *) * delegatePtr->superclasses.num);
}
FOREACH(superPtr, clsPtr->superclasses) {
|
| ︙ | ︙ | |||
157 158 159 160 161 162 163 |
break;
} else if (supers[k] == superDelegatePtr) {
break;
}
}
}
| | | < < < < | < < > > > | | < < < < | < < < | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
break;
} else if (supers[k] == superDelegatePtr) {
break;
}
}
}
/* Install new list of superclasses */
if (delegatePtr->superclasses.num) {
Tcl_Free(delegatePtr->superclasses.list);
}
delegatePtr->superclasses.list = supers;
delegatePtr->superclasses.num = j;
/* Definitely don't need to bump any epoch here */
}
/*
* Mixes the delegate into its controlling class.
*/
static inline void
InstallDelegateAsMixin(
Tcl_Interp *interp,
Class *clsPtr,
Class *delegatePtr)
{
Class **mixins;
int i;
if (clsPtr->thisPtr->mixins.num == 0) {
TclOOObjectSetMixins(clsPtr->thisPtr, 1, &delegatePtr);
return;
}
mixins = (Class **) TclStackAlloc(interp,
sizeof(Class *) * (clsPtr->thisPtr->mixins.num + 1));
for (i = 0; i < clsPtr->thisPtr->mixins.num; i++) {
mixins[i] = clsPtr->thisPtr->mixins.list[i];
if (mixins[i] == delegatePtr) {
TclStackFree(interp, (void *) mixins);
return;
}
}
mixins[clsPtr->thisPtr->mixins.num] = delegatePtr;
TclOOObjectSetMixins(clsPtr->thisPtr, clsPtr->thisPtr->mixins.num + 1, mixins);
TclStackFree(interp, mixins);
}
/*
* Patches in the appropriate class delegates.
*/
static void
MixinClassDelegates(
Tcl_Interp *interp,
Object *oPtr,
Tcl_Obj *delegateName)
{
Class *clsPtr = oPtr->classPtr, *delegatePtr;
if (clsPtr) {
delegatePtr = TclOOGetClassFromObj(interp, delegateName);
if (delegatePtr) {
SetDelegateSuperclasses(interp, clsPtr, delegatePtr);
InstallDelegateAsMixin(interp, clsPtr, delegatePtr);
}
}
}
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 |
*/
int
TclOO_Class_Constructor(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | > > | | > | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 |
*/
int
TclOO_Class_Constructor(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
size_t skip = Tcl_ObjectContextSkippedArgs(context);
Tcl_Obj **invoke, *delegateName;
if ((size_t) objc > skip + 1) {
Tcl_WrongNumArgs(interp, skip, objv,
"?definitionScript?");
return TCL_ERROR;
}
/*
* Make the class definition delegate. This is special; it doesn't reenter
* here (and the class definition delegate doesn't run any constructors).
*
* This needs to be done before consideration of whether to pass the script
* argument to [oo::define]. [Bug 680503]
*/
delegateName = Tcl_ObjPrintf("%s:: oo ::delegate",
oPtr->namespacePtr->fullName);
Tcl_IncrRefCount(delegateName);
Tcl_NewObjectInstance(interp, (Tcl_Class) oPtr->fPtr->classCls,
TclGetString(delegateName), NULL, TCL_INDEX_NONE, NULL, 0);
/*
* If there's nothing else to do, we're done.
*/
if ((size_t) objc == skip) {
Tcl_InterpState saved = Tcl_SaveInterpState(interp, TCL_OK);
MixinClassDelegates(interp, oPtr, delegateName);
Tcl_DecrRefCount(delegateName);
return Tcl_RestoreInterpState(interp, saved);
}
/*
* Delegate to [oo::define] to do the work.
*/
invoke = (Tcl_Obj **) TclStackAlloc(interp, 3 * sizeof(Tcl_Obj *));
invoke[0] = oPtr->fPtr->defineName;
invoke[1] = TclOOObjectName(interp, oPtr);
invoke[2] = objv[objc - 1];
/*
* Must add references or errors in configuration script will cause
* trouble.
|
| ︙ | ︙ | |||
305 306 307 308 309 310 311 |
* trace, so use TCL_EVAL_NOERR.
*/
return TclNREvalObjv(interp, 3, invoke, TCL_EVAL_NOERR, NULL);
}
/*
| < < < < | | < < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > > | > > > | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
* trace, so use TCL_EVAL_NOERR.
*/
return TclNREvalObjv(interp, 3, invoke, TCL_EVAL_NOERR, NULL);
}
/*
* Called *after* [oo::define] inside the constructor of a class.
* Cleans up some temporary storage and sets up the delegate.
*/
static int
PostClassConstructor(
void *data[],
Tcl_Interp *interp,
int result)
{
Tcl_Obj **invoke = (Tcl_Obj **) data[0];
Object *oPtr = (Object *) data[1];
Tcl_Obj *delegateName = (Tcl_Obj *) data[2];
Tcl_InterpState saved;
TclDecrRefCount(invoke[0]);
TclDecrRefCount(invoke[1]);
TclDecrRefCount(invoke[2]);
TclStackFree(interp, invoke);
saved = Tcl_SaveInterpState(interp, result);
MixinClassDelegates(interp, oPtr, delegateName);
Tcl_DecrRefCount(delegateName);
return Tcl_RestoreInterpState(interp, saved);
}
/*
* ----------------------------------------------------------------------
*
* TclOO_Class_Create --
*
* Implementation for oo::class->create method.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Class_Create(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
const char *objName;
Tcl_Size len;
/*
* Sanity check; should not be possible to invoke this method on a
* non-class.
*/
if (oPtr->classPtr == NULL) {
Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"object \"%s\" is not a class", TclGetString(cmdnameObj)));
OO_ERROR(interp, INSTANTIATE_NONCLASS);
return TCL_ERROR;
}
/*
* Check we have the right number of (sensible) arguments.
*/
|
| ︙ | ︙ | |||
428 429 430 431 432 433 434 |
return TCL_ERROR;
}
/*
* Make the object and return its name.
*/
| | > | | > > | > > > | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
return TCL_ERROR;
}
/*
* Make the object and return its name.
*/
return TclNRNewObjectInstance(interp, (Tcl_Class) oPtr->classPtr,
objName, NULL, objc, objv,
Tcl_ObjectContextSkippedArgs(context)+1,
AddConstructionFinalizer(interp));
}
/*
* ----------------------------------------------------------------------
*
* TclOO_Class_CreateNs --
*
* Implementation for oo::class->createWithNamespace method.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Class_CreateNs(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
const char *objName, *nsName;
Tcl_Size len;
/*
* Sanity check; should not be possible to invoke this method on a
* non-class.
*/
if (oPtr->classPtr == NULL) {
Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"object \"%s\" is not a class", TclGetString(cmdnameObj)));
OO_ERROR(interp, INSTANTIATE_NONCLASS);
return TCL_ERROR;
}
/*
* Check we have the right number of (sensible) arguments.
*/
|
| ︙ | ︙ | |||
495 496 497 498 499 500 501 |
return TCL_ERROR;
}
/*
* Make the object and return its name.
*/
| | > | | > > | > > > | | | | | | > > > > > | | > | < | | | | > | | | | | < < | | > > > | | | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
return TCL_ERROR;
}
/*
* Make the object and return its name.
*/
return TclNRNewObjectInstance(interp, (Tcl_Class) oPtr->classPtr,
objName, nsName, objc, objv,
Tcl_ObjectContextSkippedArgs(context) + 2,
AddConstructionFinalizer(interp));
}
/*
* ----------------------------------------------------------------------
*
* TclOO_Class_New --
*
* Implementation for oo::class->new method.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Class_New(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
/*
* Sanity check; should not be possible to invoke this method on a
* non-class.
*/
if (oPtr->classPtr == NULL) {
Tcl_Obj *cmdnameObj = TclOOObjectName(interp, oPtr);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"object \"%s\" is not a class", TclGetString(cmdnameObj)));
OO_ERROR(interp, INSTANTIATE_NONCLASS);
return TCL_ERROR;
}
/*
* Make the object and return its name.
*/
return TclNRNewObjectInstance(interp, (Tcl_Class) oPtr->classPtr,
NULL, NULL, objc, objv, Tcl_ObjectContextSkippedArgs(context),
AddConstructionFinalizer(interp));
}
/*
* ----------------------------------------------------------------------
*
* TclOO_Class_Cloned --
*
* Handler for cloning classes, which fixes up the delegates. This allows
* the clone's class methods to evolve independently of the origin's
* class methods; this is how TclOO works by default.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Class_Cloned(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Tcl_Object targetObject = Tcl_ObjectContextObject(context);
Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
if (skip >= objc) {
Tcl_WrongNumArgs(interp, skip, objv, "originObject");
return TCL_ERROR;
}
Tcl_Object originObject = Tcl_GetObjectFromObj(interp, objv[skip]);
if (!originObject) {
return TCL_ERROR;
}
/* Add references so things won't vanish until after
* UpdateClassDelegatesAfterClone is finished with them. */
AddRef((Object *) originObject);
AddRef((Object *) targetObject);
TclNRAddCallback(interp, UpdateClassDelegatesAfterClone,
originObject, targetObject, NULL, NULL);
return TclNRObjectContextInvokeNext(interp, context, objc, objv, skip);
}
/* Rebuilds the class inheritance delegation class. */
static int
UpdateClassDelegatesAfterClone(
void *data[],
Tcl_Interp *interp,
int result)
{
Object *originPtr = (Object *) data[0];
Object *targetPtr = (Object *) data[1];
if (result == TCL_OK && originPtr->classPtr && targetPtr->classPtr) {
Tcl_Obj *originName, *targetName;
Object *originDelegate, *targetDelegate;
Tcl_Size i;
Class *mixin;
/* Get the originating delegate to be cloned. */
originName = Tcl_ObjPrintf("%s:: oo ::delegate",
originPtr->namespacePtr->fullName);
originDelegate = (Object *) Tcl_GetObjectFromObj(interp, originName);
Tcl_BounceRefCount(originName);
/* Delegates never have their own delegates, so silently make sure we
* don't try to make a clone of them. */
if (!(originDelegate && originDelegate->classPtr)) {
goto noOriginDelegate;
}
/* Create the cloned target delegate. */
targetName = Tcl_ObjPrintf("%s:: oo ::delegate",
targetPtr->namespacePtr->fullName);
targetDelegate = (Object *) Tcl_CopyObjectInstance(interp,
(Tcl_Object) originDelegate, Tcl_GetString(targetName), NULL);
Tcl_BounceRefCount(targetName);
if (targetDelegate == NULL) {
result = TCL_ERROR;
goto noOriginDelegate;
}
/* Point the cloned target class at the cloned target delegate.
* This is like TclOOObjectSetMixins() but more efficient in this
* case as there's definitely no relevant call chains to invalidate
* and we're doing a one-for-one replacement. */
FOREACH(mixin, targetPtr->mixins) {
if (mixin == originDelegate->classPtr) {
TclOORemoveFromInstances(targetPtr, originDelegate->classPtr);
TclOODecrRefCount(originDelegate);
targetPtr->mixins.list[i] = targetDelegate->classPtr;
TclOOAddToInstances(targetPtr, targetDelegate->classPtr);
AddRef(targetDelegate);
break;
}
}
}
noOriginDelegate:
TclOODecrRefCount(originPtr);
TclOODecrRefCount(targetPtr);
return result;
};
/*
* ----------------------------------------------------------------------
*
* TclOO_Configurable_Constructor --
*
* Implementation for oo::configurable constructor.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Configurable_Constructor(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
Tcl_Obj *cfgSupportName;
Class *mixin;
if (objc != skip && objc != skip + 1) {
Tcl_WrongNumArgs(interp, skip, objv, "?definitionScript?");
return TCL_ERROR;
}
cfgSupportName = Tcl_NewStringObj(
"::oo::configuresupport::configurable", TCL_AUTO_LENGTH);
mixin = TclOOGetClassFromObj(interp, cfgSupportName);
Tcl_BounceRefCount(cfgSupportName);
if (!mixin) {
return TCL_ERROR;
}
TclOOClassSetMixins(interp, oPtr->classPtr, 1, &mixin);
return TclNRObjectContextInvokeNext(interp, context, objc, objv, skip);
}
|
| ︙ | ︙ | |||
683 684 685 686 687 688 689 |
* more complex (and class-specific) handling.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Object_Cloned(
TCL_UNUSED(void *),
| | | | | | > > > > | | | | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
* more complex (and class-specific) handling.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Object_Cloned(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
int skip = Tcl_ObjectContextSkippedArgs(context);
Object *originObject, *targetObject;
Namespace *originNs, *targetNs;
if (objc != skip + 1) {
Tcl_WrongNumArgs(interp, skip, objv, "originObject");
return TCL_ERROR;
}
targetObject = (Object *) Tcl_ObjectContextObject(context);
originObject = (Object *) Tcl_GetObjectFromObj(interp, objv[skip]);
if (!originObject) {
return TCL_ERROR;
}
originNs = (Namespace *) originObject->namespacePtr;
targetNs = (Namespace *) targetObject->namespacePtr;
if (TclCopyNamespaceProcedures(interp, originNs, targetNs) != TCL_OK) {
return TCL_ERROR;
}
return TclCopyNamespaceVariables(interp, originNs, targetNs);
}
/*
|
| ︙ | ︙ | |||
723 724 725 726 727 728 729 |
int
TclOO_Object_Destroy(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
| | | | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
int
TclOO_Object_Destroy(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
CallContext *contextPtr;
if (objc != (int) Tcl_ObjectContextSkippedArgs(context)) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
NULL);
return TCL_ERROR;
}
if (!(oPtr->flags & DESTRUCTOR_CALLED)) {
oPtr->flags |= DESTRUCTOR_CALLED;
contextPtr = TclOOGetCallContext(oPtr, NULL, DESTRUCTOR, NULL, NULL,
|
| ︙ | ︙ | |||
787 788 789 790 791 792 793 |
int
TclOO_Object_Eval(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
| | | | | | | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
int
TclOO_Object_Eval(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
CallContext *contextPtr = (CallContext *) context;
Tcl_Object object = Tcl_ObjectContextObject(context);
size_t skip = Tcl_ObjectContextSkippedArgs(context);
CallFrame *framePtr, **framePtrPtr = &framePtr;
Tcl_Obj *scriptPtr;
CmdFrame *invoker;
if ((size_t) objc < skip + 1) {
Tcl_WrongNumArgs(interp, skip, objv, "arg ?arg ...?");
return TCL_ERROR;
}
/*
* Make the object's namespace the current namespace and evaluate the
* command(s).
*/
(void) TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
Tcl_GetObjectNamespace(object), FRAME_IS_METHOD);
framePtr->clientData = context;
framePtr->objc = objc;
framePtr->objv = objv; /* Reference counts do not need to be
* incremented here. */
if (!(contextPtr->callPtr->flags & PUBLIC_METHOD)) {
object = NULL; /* Now just for error mesage printing. */
}
/*
* Work out what script we are actually going to evaluate.
*
* When there's more than one argument, we concatenate them together with
* spaces between, then evaluate the result. Tcl_EvalObjEx will delete the
* object when it decrements its refcount after eval'ing it.
*/
if ((size_t) objc != skip+1) {
scriptPtr = Tcl_ConcatObj(objc-skip, objv+skip);
invoker = NULL;
} else {
scriptPtr = objv[skip];
invoker = ((Interp *) interp)->cmdFramePtr;
}
|
| ︙ | ︙ | |||
890 891 892 893 894 895 896 |
int
TclOO_Object_Unknown(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
| | | | | | > | | 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 |
int
TclOO_Object_Unknown(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
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;
size_t skip = Tcl_ObjectContextSkippedArgs(context);
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
Tcl_Obj *errorMsg;
/*
* If no method name, generate an error asking for a method name. (Only by
* overriding *this* method can an object handle the absence of a method
* name without an error).
*/
if ((size_t) objc < skip + 1) {
Tcl_WrongNumArgs(interp, skip, objv, "method ?arg ...?");
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 = (CallContext *) 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)) {
|
| ︙ | ︙ | |||
967 968 969 970 971 972 973 |
errorMsg = Tcl_ObjPrintf("unknown method \"%s\": must be ",
TclGetString(objv[skip]));
for (i=0 ; i<numMethodNames-1 ; i++) {
if (i) {
Tcl_AppendToObj(errorMsg, ", ", TCL_AUTO_LENGTH);
}
| | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 |
errorMsg = Tcl_ObjPrintf("unknown method \"%s\": must be ",
TclGetString(objv[skip]));
for (i=0 ; i<numMethodNames-1 ; i++) {
if (i) {
Tcl_AppendToObj(errorMsg, ", ", TCL_AUTO_LENGTH);
}
Tcl_AppendToObj(errorMsg, methodNames[i], TCL_AUTO_LENGTH);
}
if (i) {
Tcl_AppendToObj(errorMsg, " or ", TCL_AUTO_LENGTH);
}
Tcl_AppendToObj(errorMsg, methodNames[i], TCL_AUTO_LENGTH);
Tcl_Free((void *)methodNames);
Tcl_SetObjResult(interp, errorMsg);
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[skip]), (char *)NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
996 997 998 999 1000 1001 1002 |
int
TclOO_Object_LinkVar(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
| | | 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 |
int
TclOO_Object_LinkVar(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Interp *iPtr = (Interp *) interp;
Tcl_Object object = Tcl_ObjectContextObject(context);
Namespace *savedNsPtr;
Tcl_Size i;
|
| ︙ | ︙ | |||
1119 1120 1121 1122 1123 1124 1125 |
* We still need to do the lookup; the variable could be linked to another
* variable and we want the target's name.
*/
if (arg[0] == ':' && arg[1] == ':') {
varNamePtr = varName;
} else {
| < < | < > | | | < | > | 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 |
* We still need to do the lookup; the variable could be linked to another
* variable and we want the target's name.
*/
if (arg[0] == ':' && arg[1] == ':') {
varNamePtr = varName;
} else {
Tcl_Namespace *namespacePtr = Tcl_GetObjectNamespace(object);
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
/*
* 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 *) object;
CallContext *callerContext = (CallContext *) framePtr->clientData;
Method *mPtr = callerContext->callPtr->chain[
callerContext->index].mPtr;
PrivateVariableMapping *pvPtr;
Tcl_Size i;
if (mPtr->declaringObjectPtr == oPtr) {
FOREACH_STRUCT(pvPtr, oPtr->privateVariables) {
if (!TclStringCmp(pvPtr->variableObj, varName, 1, 0,
TCL_INDEX_NONE)) {
varName = 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 (!TclStringCmp(pvPtr->variableObj, varName, 1, 0,
TCL_INDEX_NONE)) {
varName = pvPtr->fullNameObj;
break;
}
}
}
}
}
// The namespace isn't the global one; necessarily true for any object!
varNamePtr = Tcl_ObjPrintf("%s::%s",
namespacePtr->fullName, TclGetString(varName));
}
Tcl_IncrRefCount(varNamePtr);
Tcl_Var var = (Tcl_Var) TclObjLookupVar(interp, varNamePtr, NULL,
TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG, "refer to", 1, 1,
(Var **) aryPtr);
Tcl_DecrRefCount(varNamePtr);
if (var == NULL) {
|
| ︙ | ︙ | |||
1215 1216 1217 1218 1219 1220 1221 |
int
TclOO_Object_VarName(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
| | | | 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 |
int
TclOO_Object_VarName(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Tcl_Var varPtr, aryVar;
Tcl_Obj *varNamePtr;
if ((int) Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"varName");
return TCL_ERROR;
}
varPtr = TclOOLookupObjectVar(interp, Tcl_ObjectContextObject(context),
objv[objc - 1], &aryVar);
|
| ︙ | ︙ | |||
1275 1276 1277 1278 1279 1280 1281 |
*
* ----------------------------------------------------------------------
*/
int
TclOOLinkObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > | > > > > > > > > > | | > | | | | < < < | | | < | | < | < < < | | | 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 |
*
* ----------------------------------------------------------------------
*/
int
TclOOLinkObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
/* Set up common bits. */
CallFrame *framePtr = ((Interp *) interp)->varFramePtr;
CallContext *context;
Object *oPtr;
Tcl_Obj *myCmd, **linkv, *src, *dst;
Tcl_Size linkc;
const char *srcStr;
int i;
if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s may only be called from inside a method",
TclGetString(objv[0])));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
}
context = (CallContext *) framePtr->clientData;
oPtr = context->oPtr;
if (!oPtr->myCommand) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"cannot link to non-existent callback handle"));
OO_ERROR(interp, MY_GONE);
return TCL_ERROR;
}
myCmd = Tcl_NewObj();
Tcl_GetCommandFullName(interp, oPtr->myCommand, myCmd);
if (!oPtr->linkedCmdsList) {
oPtr->linkedCmdsList = Tcl_NewListObj(0, NULL);
Tcl_IncrRefCount(oPtr->linkedCmdsList);
}
/* For each argument */
for (i=1; i<objc; i++) {
/* Parse as list of (one or) two items: source and destination names */
if (TclListObjGetElements(interp, objv[i], &linkc, &linkv) != TCL_OK) {
Tcl_BounceRefCount(myCmd);
return TCL_ERROR;
}
switch (linkc) {
case 1:
/* Degenerate case */
src = dst = linkv[0];
break;
case 2:
src = linkv[0];
dst = linkv[1];
break;
default:
Tcl_BounceRefCount(myCmd);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad link description; must only have one or two elements"));
OO_ERROR(interp, CMDLINK_FORMAT);
return TCL_ERROR;
}
/* Qualify the source if necessary */
srcStr = TclGetString(src);
if (srcStr[0] != ':' || srcStr[1] != ':') {
src = Tcl_ObjPrintf("%s::%s",
context->oPtr->namespacePtr->fullName, srcStr);
}
/* Make the alias command */
if (TclAliasCreate(interp, interp, interp, src, myCmd, 1, &dst) != TCL_OK) {
Tcl_BounceRefCount(myCmd);
Tcl_BounceRefCount(src);
return TCL_ERROR;
}
/* Remember the alias for cleanup if necessary */
Tcl_ListObjAppendElement(NULL, oPtr->linkedCmdsList, src);
}
Tcl_BounceRefCount(myCmd);
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
1367 1368 1369 1370 1371 1372 1373 |
* ----------------------------------------------------------------------
*/
int
TclOONextObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | < > > > > | > | > > > > > > > > > | > | | > | > > > > > > > < < < < > > > > > > > | | 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 |
* ----------------------------------------------------------------------
*/
int
TclOONextObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
CallFrame *framePtr = iPtr->varFramePtr;
Tcl_ObjectContext context;
/*
* Start with sanity checks on the calling context to make sure that we
* are invoked from a suitable method context. If so, we can safely
* retrieve the handle to the object call context.
*/
if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s may only be called from inside a method",
TclGetString(objv[0])));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
}
context = (Tcl_ObjectContext) framePtr->clientData;
/*
* Invoke the (advanced) method call context in the caller context. Note
* that this is like [uplevel 1] and not [eval].
*/
TclNRAddCallback(interp, NextRestoreFrame, framePtr, NULL,NULL,NULL);
iPtr->varFramePtr = framePtr->callerVarPtr;
return TclNRObjectContextInvokeNext(interp, context, objc, objv, 1);
}
int
TclOONextToObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
CallFrame *framePtr = iPtr->varFramePtr;
Class *classPtr;
CallContext *contextPtr;
Tcl_Size i;
Tcl_Object object;
const char *methodType;
/*
* Start with sanity checks on the calling context to make sure that we
* are invoked from a suitable method context. If so, we can safely
* retrieve the handle to the object call context.
*/
if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s may only be called from inside a method",
TclGetString(objv[0])));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
}
contextPtr = (CallContext *) framePtr->clientData;
/*
* Sanity check the arguments; we need the first one to refer to a class.
*/
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "class ?arg...?");
return TCL_ERROR;
}
object = Tcl_GetObjectFromObj(interp, objv[1]);
if (object == NULL) {
return TCL_ERROR;
}
classPtr = ((Object *) object)->classPtr;
if (classPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"%s\" is not a class", TclGetString(objv[1])));
OO_ERROR(interp, CLASS_REQUIRED);
return TCL_ERROR;
}
/*
* Search for an implementation of a method associated with the current
* call on the call chain past the point where we currently are. Do not
* allow jumping backwards!
*/
for (i=contextPtr->index+1 ; i<contextPtr->callPtr->numChain ; i++) {
MInvoke *miPtr = &contextPtr->callPtr->chain[i];
if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) {
/*
* Invoke the (advanced) method call context in the caller
* context. Note that this is like [uplevel 1] and not [eval].
*/
TclNRAddCallback(interp, NextRestoreFrame, framePtr,
contextPtr, INT2PTR(contextPtr->index), NULL);
contextPtr->index = i - 1;
iPtr->varFramePtr = framePtr->callerVarPtr;
return TclNRObjectContextInvokeNext(interp,
(Tcl_ObjectContext) contextPtr, objc, objv, 2);
}
}
/*
* Generate an appropriate error message, depending on whether the value
* is on the chain but unreachable, or not on the chain at all.
*/
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
methodType = "constructor";
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
methodType = "destructor";
} else {
methodType = "method";
}
for (i=contextPtr->index ; i != TCL_INDEX_NONE ; i--) {
MInvoke *miPtr = &contextPtr->callPtr->chain[i];
if (!miPtr->isFilter && miPtr->mPtr->declaringClassPtr == classPtr) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s implementation by \"%s\" not reachable from here",
methodType, TclGetString(objv[1])));
|
| ︙ | ︙ | |||
1499 1500 1501 1502 1503 1504 1505 |
}
return result;
}
/*
* ----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < > > > > | > | | > > | 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 |
}
return result;
}
/*
* ----------------------------------------------------------------------
*
* TclOOSelfObjCmd --
*
* Implementation of the [self] command, which provides introspection of
* the call context.
*
* ----------------------------------------------------------------------
*/
int
TclOOSelfObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
static const char *const subcmds[] = {
"call", "caller", "class", "filter", "method", "namespace", "next",
"object", "target", NULL
};
enum SelfCmds {
SELF_CALL, SELF_CALLER, SELF_CLASS, SELF_FILTER, SELF_METHOD, SELF_NS,
SELF_NEXT, SELF_OBJECT, SELF_TARGET
} index;
Interp *iPtr = (Interp *) interp;
CallFrame *framePtr = iPtr->varFramePtr;
CallContext *contextPtr;
Tcl_Obj *result[3];
#define CurrentlyInvoked(contextPtr) \
((contextPtr)->callPtr->chain[(contextPtr)->index])
/*
* Start with sanity checks on the calling context and the method context.
*/
if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s may only be called from inside a method",
TclGetString(objv[0])));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
}
contextPtr = (CallContext *) framePtr->clientData;
/*
* Now we do "conventional" argument parsing for a while. Note that no
* subcommand takes arguments.
*/
if (objc > 2) {
|
| ︙ | ︙ | |||
1622 1623 1624 1625 1626 1627 1628 |
return TCL_ERROR;
}
Tcl_SetObjResult(interp, TclOOObjectName(interp, clsPtr->thisPtr));
return TCL_OK;
}
case SELF_METHOD:
| > > > > > | | > | 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 |
return TCL_ERROR;
}
Tcl_SetObjResult(interp, TclOOObjectName(interp, clsPtr->thisPtr));
return TCL_OK;
}
case SELF_METHOD:
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
Tcl_SetObjResult(interp, contextPtr->oPtr->fPtr->constructorName);
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
Tcl_SetObjResult(interp, contextPtr->oPtr->fPtr->destructorName);
} else {
Tcl_SetObjResult(interp,
CurrentlyInvoked(contextPtr).mPtr->namePtr);
}
return TCL_OK;
case SELF_FILTER:
if (!CurrentlyInvoked(contextPtr).isFilter) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"not inside a filtering context", TCL_AUTO_LENGTH));
OO_ERROR(interp, UNMATCHED_CONTEXT);
return TCL_ERROR;
|
| ︙ | ︙ | |||
1660 1661 1662 1663 1664 1665 1666 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"caller is not an object", TCL_AUTO_LENGTH));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
} else {
CallContext *callerPtr = (CallContext *)
framePtr->callerVarPtr->clientData;
| > > | > > > > > > | > | > > > > > | > > > > > > > > > > | > > > > > | > > > > > > > > > | | | 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 |
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"caller is not an object", TCL_AUTO_LENGTH));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
} else {
CallContext *callerPtr = (CallContext *)
framePtr->callerVarPtr->clientData;
Method *mPtr = callerPtr->callPtr->chain[callerPtr->index].mPtr;
Object *declarerPtr;
if (mPtr->declaringClassPtr != NULL) {
declarerPtr = mPtr->declaringClassPtr->thisPtr;
} else if (mPtr->declaringObjectPtr != NULL) {
declarerPtr = mPtr->declaringObjectPtr;
} else {
TCL_UNREACHABLE();
}
result[0] = TclOOObjectName(interp, declarerPtr);
result[1] = TclOOObjectName(interp, callerPtr->oPtr);
if (callerPtr->callPtr->flags & CONSTRUCTOR) {
result[2] = declarerPtr->fPtr->constructorName;
} else if (callerPtr->callPtr->flags & DESTRUCTOR) {
result[2] = declarerPtr->fPtr->destructorName;
} else {
result[2] = mPtr->namePtr;
}
Tcl_SetObjResult(interp, Tcl_NewListObj(3, result));
return TCL_OK;
}
case SELF_NEXT:
if (contextPtr->index < contextPtr->callPtr->numChain - 1) {
Method *mPtr =
contextPtr->callPtr->chain[contextPtr->index + 1].mPtr;
Object *declarerPtr;
if (mPtr->declaringClassPtr != NULL) {
declarerPtr = mPtr->declaringClassPtr->thisPtr;
} else if (mPtr->declaringObjectPtr != NULL) {
declarerPtr = mPtr->declaringObjectPtr;
} else {
TCL_UNREACHABLE();
}
result[0] = TclOOObjectName(interp, declarerPtr);
if (contextPtr->callPtr->flags & CONSTRUCTOR) {
result[1] = declarerPtr->fPtr->constructorName;
} else if (contextPtr->callPtr->flags & DESTRUCTOR) {
result[1] = declarerPtr->fPtr->destructorName;
} else {
result[1] = mPtr->namePtr;
}
Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
}
return TCL_OK;
case SELF_TARGET:
if (!CurrentlyInvoked(contextPtr).isFilter) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"not inside a filtering context", TCL_AUTO_LENGTH));
OO_ERROR(interp, UNMATCHED_CONTEXT);
return TCL_ERROR;
} else {
Method *mPtr;
Object *declarerPtr;
Tcl_Size i;
for (i=contextPtr->index ; i<contextPtr->callPtr->numChain ; i++) {
if (!contextPtr->callPtr->chain[i].isFilter) {
break;
}
}
if (i == contextPtr->callPtr->numChain) {
Tcl_Panic("filtering call chain without terminal non-filter");
}
mPtr = contextPtr->callPtr->chain[i].mPtr;
if (mPtr->declaringClassPtr != NULL) {
declarerPtr = mPtr->declaringClassPtr->thisPtr;
} else if (mPtr->declaringObjectPtr != NULL) {
declarerPtr = mPtr->declaringObjectPtr;
} else {
TCL_UNREACHABLE();
}
result[0] = TclOOObjectName(interp, declarerPtr);
result[1] = mPtr->namePtr;
Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
return TCL_OK;
}
case SELF_CALL:
result[0] = TclOORenderCallChain(interp, contextPtr->callPtr);
TclNewIndexObj(result[1], contextPtr->index);
Tcl_SetObjResult(interp, Tcl_NewListObj(2, result));
|
| ︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 |
* ----------------------------------------------------------------------
*/
int
TclOOCopyObjectCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 |
* ----------------------------------------------------------------------
*/
int
TclOOCopyObjectCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Object oPtr, o2Ptr;
if (objc < 2 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv,
"sourceName ?targetName? ?targetNamespace?");
|
| ︙ | ︙ | |||
1809 1810 1811 1812 1813 1814 1815 |
*
* ----------------------------------------------------------------------
*/
int
TclOOCallbackObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | > > > > > > | > | | > > | | | | | > > > > > > > > | | > | | > > > | | | | | < | | | | | | 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 |
*
* ----------------------------------------------------------------------
*/
int
TclOOCallbackObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
CallFrame *framePtr = iPtr->varFramePtr;
CallContext *contextPtr;
Tcl_Obj *namePtr, *listPtr;
/*
* Start with sanity checks on the calling context to make sure that we
* are invoked from a suitable method context. If so, we can safely
* retrieve the handle to the object call context.
*/
if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s may only be called from inside a method",
TclGetString(objv[0])));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
}
contextPtr = (CallContext *) framePtr->clientData;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "method ...");
return TCL_ERROR;
}
/* Get the [my] real name. */
namePtr = TclOOObjectMyName(interp, contextPtr->oPtr);
if (!namePtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"no possible safe callback without my", TCL_AUTO_LENGTH));
OO_ERROR(interp, NO_MY);
return TCL_ERROR;
}
/* No check that the method exists; could be dynamically added. */
listPtr = Tcl_NewListObj(1, &namePtr);
(void) TclListObjAppendElements(NULL, listPtr, objc-1, objv+1);
Tcl_SetObjResult(interp, listPtr);
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* TclOOClassVariableObjCmd --
*
* Implementation of the [classvariable] command, which links to
* variables in the class of the current object.
*
* ----------------------------------------------------------------------
*/
int
TclOOClassVariableObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Interp *iPtr = (Interp *) interp;
CallFrame *framePtr = iPtr->varFramePtr;
CallContext *contextPtr;
Class *clsPtr;
Tcl_Namespace *clsNsPtr, *ourNsPtr;
Var *arrayPtr, *otherPtr;
int i;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name ...");
return TCL_ERROR;
}
/*
* Start with sanity checks on the calling context to make sure that we
* are invoked from a suitable method context. If so, we can safely
* retrieve the handle to the object call context.
*/
if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s may only be called from inside a method",
TclGetString(objv[0])));
OO_ERROR(interp, CONTEXT_REQUIRED);
return TCL_ERROR;
}
/* Get a reference to the class's namespace */
contextPtr = (CallContext *) framePtr->clientData;
clsPtr = CurrentlyInvoked(contextPtr).mPtr->declaringClassPtr;
if (clsPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"method not defined by a class", TCL_AUTO_LENGTH));
OO_ERROR(interp, UNMATCHED_CONTEXT);
return TCL_ERROR;
}
clsNsPtr = clsPtr->thisPtr->namespacePtr;
/* Check the list of variable names */
for (i = 1; i < objc; i++) {
const char *varName = TclGetString(objv[i]);
if (Tcl_StringMatch(varName, "*(*)")) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad variable name \"%s\": can't create a %s",
varName, "scalar variable that looks like an array element"));
Tcl_SetErrorCode(interp, "TCL", "UPVAR", "LOCAL_ELEMENT", (char *)NULL);
return TCL_ERROR;
}
if (Tcl_StringMatch(varName, "*::*")) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad variable name \"%s\": can't create a %s",
varName, "local variable with a namespace separator in it"));
Tcl_SetErrorCode(interp, "TCL", "UPVAR", "LOCAL_ELEMENT", (char *)NULL);
return TCL_ERROR;
}
}
/* Lastly, link the caller's local variables to the class's variables */
ourNsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
for (i = 1; i < objc; i++) {
/* Locate the other variable. */
iPtr->varFramePtr->nsPtr = (Namespace *) clsNsPtr;
otherPtr = TclObjLookupVarEx(interp, objv[i], NULL,
(TCL_NAMESPACE_ONLY|TCL_LEAVE_ERR_MSG|TCL_AVOID_RESOLVERS),
"access", /*createPart1*/ 1, /*createPart2*/ 0, &arrayPtr);
iPtr->varFramePtr->nsPtr = (Namespace *) ourNsPtr;
if (otherPtr == NULL) {
return TCL_ERROR;
}
/* Create the new variable and link it to otherPtr. */
if (TclPtrObjMakeUpvarIdx(interp, otherPtr, objv[i], 0,
TCL_INDEX_NONE) != TCL_OK) {
return TCL_ERROR;
}
}
return TCL_OK;
|
| ︙ | ︙ | |||
1949 1950 1951 1952 1953 1954 1955 |
*
* ----------------------------------------------------------------------
*/
int
TclOODelegateNameObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > | | 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 |
*
* ----------------------------------------------------------------------
*/
int
TclOODelegateNameObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "class");
return TCL_ERROR;
}
Class *clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf("%s:: oo ::delegate",
clsPtr->thisPtr->namespacePtr->fullName));
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* TclOO_Singleton_New, MarkAsSingleton --
*
* Implementation for oo::singleton->new method.
*
* ----------------------------------------------------------------------
*/
int
TclOO_Singleton_New(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
Class *clsPtr = oPtr->classPtr;
if (clsPtr->instances.num) {
Tcl_SetObjResult(interp, TclOOObjectName(interp, clsPtr->instances.list[0]));
|
| ︙ | ︙ | |||
2007 2008 2009 2010 2011 2012 2013 |
MarkAsSingleton(
void *data[],
Tcl_Interp *interp,
int result)
{
Class *clsPtr = (Class *) data[0];
if (result == TCL_OK && clsPtr->instances.num) {
| | > > > > | | | < | 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 |
MarkAsSingleton(
void *data[],
Tcl_Interp *interp,
int result)
{
Class *clsPtr = (Class *) data[0];
if (result == TCL_OK && clsPtr->instances.num) {
/* Prepend oo::SingletonInstance to the list of mixins */
Tcl_Obj *singletonInstanceName = Tcl_NewStringObj(
"::oo::SingletonInstance", TCL_AUTO_LENGTH);
Class *singInst = TclOOGetClassFromObj(interp, singletonInstanceName);
Object *oPtr;
Tcl_Size mixinc;
Class **mixins;
Tcl_BounceRefCount(singletonInstanceName);
if (!singInst) {
return TCL_ERROR;
}
oPtr = clsPtr->instances.list[0];
mixinc = oPtr->mixins.num;
mixins = (Class **)TclStackAlloc(interp, sizeof(Class *) * (mixinc + 1));
if (mixinc > 0) {
memcpy(mixins + 1, oPtr->mixins.list, mixinc * sizeof(Class *));
}
mixins[0] = singInst;
TclOOObjectSetMixins(oPtr, mixinc + 1, mixins);
TclStackFree(interp, mixins);
}
|
| ︙ | ︙ | |||
2045 2046 2047 2048 2049 2050 2051 |
*/
int
TclOO_SingletonInstance_Destroy(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for error reporting. */
TCL_UNUSED(Tcl_ObjectContext),
| | | | 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 |
*/
int
TclOO_SingletonInstance_Destroy(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for error reporting. */
TCL_UNUSED(Tcl_ObjectContext),
TCL_UNUSED(int),
TCL_UNUSED(Tcl_Obj *const *))
{
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"may not destroy a singleton object"));
OO_ERROR(interp, SINGLETON);
return TCL_ERROR;
}
int
TclOO_SingletonInstance_Cloned(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter in which to create the object;
* also used for error reporting. */
TCL_UNUSED(Tcl_ObjectContext),
TCL_UNUSED(int),
TCL_UNUSED(Tcl_Obj *const *))
{
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"may not clone a singleton object"));
OO_ERROR(interp, SINGLETON);
return TCL_ERROR;
}
|
| ︙ | ︙ |
Changes to generic/tclOOCall.c.
| ︙ | ︙ | |||
107 108 109 110 111 112 113 | static inline void AddDefinitionNamespaceToChain(Class *const definerCls, Tcl_Obj *const namespaceName, DefineChain *const definePtr, int flags); static inline void AddMethodToCallChain(Method *const mPtr, ChainBuilder *const cbPtr, Tcl_HashTable *const doneFilters, Class *const filterDecl, int flags); | | | | | | | | | > | | > | 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
static inline void AddDefinitionNamespaceToChain(Class *const definerCls,
Tcl_Obj *const namespaceName,
DefineChain *const definePtr, int flags);
static inline void AddMethodToCallChain(Method *const mPtr,
ChainBuilder *const cbPtr,
Tcl_HashTable *const doneFilters,
Class *const filterDecl, int flags);
static inline int AddInstancePrivateToCallContext(Object *const oPtr,
Tcl_Obj *const methodNameObj,
ChainBuilder *const cbPtr, int flags);
static inline void AddStandardMethodName(int flags, Tcl_Obj *namePtr,
Method *mPtr, Tcl_HashTable *namesPtr);
static inline void AddPrivateMethodNames(Tcl_HashTable *methodsTablePtr,
Tcl_HashTable *namesPtr);
static inline int AddSimpleChainToCallContext(Object *const oPtr,
Class *const contextCls,
Tcl_Obj *const methodNameObj,
ChainBuilder *const cbPtr,
Tcl_HashTable *const doneFilters, int flags,
Class *const filterDecl);
static int AddPrivatesFromClassChainToCallContext(Class *classPtr,
Class *const contextCls,
Tcl_Obj *const methodNameObj,
ChainBuilder *const cbPtr,
Tcl_HashTable *const doneFilters, int flags,
Class *const filterDecl);
static int AddSimpleClassChainToCallContext(Class *classPtr,
Tcl_Obj *const methodNameObj,
ChainBuilder *const cbPtr,
Tcl_HashTable *const doneFilters, int flags,
Class *const filterDecl);
static void AddSimpleClassDefineNamespaces(Class *classPtr,
DefineChain *const definePtr, int flags);
static inline void AddSimpleDefineNamespaces(Object *const oPtr,
DefineChain *const definePtr, int flags);
static int CmpStr(const void *ptr1, const void *ptr2);
static void DupMethodNameRep(Tcl_Obj *srcPtr, Tcl_Obj *dstPtr);
static Tcl_NRPostProc FinalizeMethodRefs;
static void FreeMethodNameRep(Tcl_Obj *objPtr);
static inline int IsStillValid(CallChain *callPtr, Object *oPtr,
int flags, int reuseMask);
static Tcl_NRPostProc ResetFilterFlags;
static Tcl_NRPostProc SetFilterFlags;
static size_t SortMethodNames(Tcl_HashTable *namesPtr, int flags,
const char ***stringsPtr);
static inline void StashCallChain(Tcl_Obj *objPtr, CallChain *callPtr);
/*
* Object type used to manage type caches attached to method names.
*/
static const Tcl_ObjType methodNameType = {
"TclOO method name",
FreeMethodNameRep,
DupMethodNameRep,
NULL,
NULL,
TCL_OBJTYPE_V0
};
/*
* ----------------------------------------------------------------------
*
* TclOODeleteContext --
*
* Destroys a method call-chain context, which should not be in use.
*
* ----------------------------------------------------------------------
*/
void
TclOODeleteContext(
CallContext *contextPtr)
{
Object *oPtr = contextPtr->oPtr;
TclOODeleteChain(contextPtr->callPtr);
|
| ︙ | ︙ | |||
195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
*
* TclOODeleteChainCache --
*
* Destroy the cache of method call-chains.
*
* ----------------------------------------------------------------------
*/
void
TclOODeleteChainCache(
Tcl_HashTable *tablePtr)
{
FOREACH_HASH_DECLS;
CallChain *callPtr;
| > | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
*
* TclOODeleteChainCache --
*
* Destroy the cache of method call-chains.
*
* ----------------------------------------------------------------------
*/
void
TclOODeleteChainCache(
Tcl_HashTable *tablePtr)
{
FOREACH_HASH_DECLS;
CallChain *callPtr;
|
| ︙ | ︙ | |||
220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
*
* TclOODeleteChain --
*
* Destroys a method call-chain.
*
* ----------------------------------------------------------------------
*/
void
TclOODeleteChain(
CallChain *callPtr)
{
if (callPtr == NULL || callPtr->refCount-- > 1) {
return;
}
| > | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
*
* TclOODeleteChain --
*
* Destroys a method call-chain.
*
* ----------------------------------------------------------------------
*/
void
TclOODeleteChain(
CallChain *callPtr)
{
if (callPtr == NULL || callPtr->refCount-- > 1) {
return;
}
|
| ︙ | ︙ | |||
305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
* Invokes a single step along a method call-chain context. Note that the
* invocation of a step along the chain can cause further steps along the
* chain to be invoked. Note that this function is written to be as light
* in stack usage as possible.
*
* ----------------------------------------------------------------------
*/
int
TclOOInvokeContext(
void *clientData, /* The method call context. */
Tcl_Interp *interp, /* Interpreter for error reporting, and many
* other sorts of context handling (e.g.,
* commands, variables) depending on method
* implementation. */
| > | | | | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
* Invokes a single step along a method call-chain context. Note that the
* invocation of a step along the chain can cause further steps along the
* chain to be invoked. Note that this function is written to be as light
* in stack usage as possible.
*
* ----------------------------------------------------------------------
*/
int
TclOOInvokeContext(
void *clientData, /* The method call context. */
Tcl_Interp *interp, /* Interpreter for error reporting, and many
* other sorts of context handling (e.g.,
* commands, variables) depending on method
* implementation. */
int objc, /* The number of arguments. */
Tcl_Obj *const objv[]) /* The arguments as actually seen. */
{
CallContext *const contextPtr = (CallContext *) clientData;
Method *const mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr;
const int isFilter =
contextPtr->callPtr->chain[contextPtr->index].isFilter;
/*
* If this is the first step along the chain, we preserve the method
* entries in the chain so that they do not get deleted out from under our
* feet.
*/
|
| ︙ | ︙ | |||
356 357 358 359 360 361 362 |
}
/*
* Save whether we were in a filter and set up whether we are now.
*/
if (contextPtr->oPtr->flags & FILTER_HANDLING) {
| | | < | < | 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
}
/*
* Save whether we were in a filter and set up whether we are now.
*/
if (contextPtr->oPtr->flags & FILTER_HANDLING) {
TclNRAddCallback(interp, SetFilterFlags, contextPtr, NULL,NULL,NULL);
} else {
TclNRAddCallback(interp, ResetFilterFlags,contextPtr,NULL,NULL,NULL);
}
if (isFilter || contextPtr->callPtr->flags & FILTER_HANDLING) {
contextPtr->oPtr->flags |= FILTER_HANDLING;
} else {
contextPtr->oPtr->flags &= ~FILTER_HANDLING;
}
/*
* Run the method implementation.
*/
if (mPtr->typePtr->version < TCL_OO_METHOD_VERSION_2) {
return (mPtr->typePtr->callProc)(mPtr->clientData, interp,
(Tcl_ObjectContext) contextPtr, objc, objv);
}
return (mPtr->type2Ptr->callProc)(mPtr->clientData, interp,
(Tcl_ObjectContext) contextPtr, objc, objv);
}
static int
SetFilterFlags(
void *data[],
|
| ︙ | ︙ | |||
422 423 424 425 426 427 428 |
}
return result;
}
/*
* ----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < < < < < | | | | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 |
}
return result;
}
/*
* ----------------------------------------------------------------------
*
* TclOOGetSortedMethodList, TclOOGetSortedClassMethodList --
*
* Discovers the list of method names supported by an object or class.
*
* ----------------------------------------------------------------------
*/
int
TclOOGetSortedMethodList(
Object *oPtr, /* The object to get the method names for. */
Object *contextObj, /* From what context object we are inquiring.
* NULL when the context shouldn't see
* object-level private methods. Note that
* flags can override this. */
Class *contextCls, /* From what context class we are inquiring.
* NULL when the context shouldn't see
* class-level private methods. Note that
* flags can override this. */
int flags, /* Whether we just want the public method
* names. */
const char ***stringsPtr) /* Where to write a pointer to the array of
* strings to. */
{
Tcl_HashTable names; /* Tcl_Obj* method name to "wanted in list"
* mapping. */
Tcl_HashTable examinedClasses;
/* Used to track what classes have been looked
* at. Is set-like in nature and keyed by
* pointer to class. */
FOREACH_HASH_DECLS;
Tcl_Size i, numStrings;
|
| ︙ | ︙ | |||
540 541 542 543 544 545 546 |
/*
* Tidy up, sort the names and resolve finally whether we really want
* them (processing export layering).
*/
Tcl_DeleteHashTable(&examinedClasses);
| | | | | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
/*
* Tidy up, sort the names and resolve finally whether we really want
* them (processing export layering).
*/
Tcl_DeleteHashTable(&examinedClasses);
numStrings = SortMethodNames(&names, flags, stringsPtr);
Tcl_DeleteHashTable(&names);
return numStrings;
}
size_t
TclOOGetSortedClassMethodList(
Class *clsPtr, /* The class to get the method names for. */
int flags, /* Whether we just want the public method
* names. */
const char ***stringsPtr) /* Where to write a pointer to the array of
* strings to. */
{
Tcl_HashTable names; /* Tcl_Obj* method name to "wanted in list"
* mapping. */
Tcl_HashTable examinedClasses;
/* Used to track what classes have been looked
* at. Is set-like in nature and keyed by
* pointer to class. */
size_t numStrings;
Tcl_InitObjHashTable(&names);
Tcl_InitHashTable(&examinedClasses, TCL_ONE_WORD_KEYS);
/*
* Process method names from the class hierarchy and the mixin hierarchy.
*/
|
| ︙ | ︙ | |||
585 586 587 588 589 590 591 |
}
/*
* Tidy up, sort the names and resolve finally whether we really want
* them (processing export layering).
*/
| | > | | | | | | | | | | | | | | < < | | < | < < | | | | > | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 |
}
/*
* Tidy up, sort the names and resolve finally whether we really want
* them (processing export layering).
*/
numStrings = SortMethodNames(&names, flags, stringsPtr);
Tcl_DeleteHashTable(&names);
return numStrings;
}
/*
* ----------------------------------------------------------------------
*
* SortMethodNames --
*
* Shared helper for TclOOGetSortedMethodList etc. that knows the method
* sorting rules.
*
* Returns:
* The length of the sorted list.
*
* ----------------------------------------------------------------------
*/
static size_t
SortMethodNames(
Tcl_HashTable *namesPtr, /* The table of names; unsorted, but contains
* whether the names are wanted and under what
* circumstances. */
int flags, /* Whether we are looking for unexported
* methods. Full private methods are handled
* on insertion to the table. */
const char ***stringsPtr) /* Where to store the sorted list of strings
* that we produce. Tcl_Alloced() */
{
const char **strings;
FOREACH_HASH_DECLS;
Tcl_Obj *namePtr;
void *isWanted;
size_t i = 0;
/*
* See how many (visible) method names there are. If none, we do not (and
* should not) try to sort the list of them.
*/
if (namesPtr->numEntries == 0) {
*stringsPtr = NULL;
return 0;
}
/*
* We need to build the list of methods to sort. We will be using qsort()
* for this, because it is very unlikely that the list will be heavily
* sorted when it is long enough to matter.
*/
strings = (const char **) Tcl_Alloc(sizeof(char *) * namesPtr->numEntries);
FOREACH_HASH(namePtr, isWanted, namesPtr) {
if (!WANT_PUBLIC(flags) || (PTR2INT(isWanted) & IN_LIST)) {
if (PTR2INT(isWanted) & NO_IMPLEMENTATION) {
continue;
}
strings[i++] = TclGetString(namePtr);
}
}
/*
* Note that 'i' may well be less than names.numEntries when we are
* dealing with public method names. We don't sort unless there's at least
* two method names.
*/
if (i > 0) {
if (i > 1) {
qsort((void *) strings, i, sizeof(char *), CmpStr);
}
*stringsPtr = strings;
} else {
Tcl_Free((void *)strings);
*stringsPtr = NULL;
}
return i;
}
/*
* Comparator for SortMethodNames
*/
static int
CmpStr(
const void *ptr1,
const void *ptr2)
{
const char **strPtr1 = (const char **) ptr1;
const char **strPtr2 = (const char **) ptr2;
return TclpUtfNcmp2(*strPtr1, *strPtr2, strlen(*strPtr1) + 1);
}
/*
* ----------------------------------------------------------------------
*
* AddClassMethodNames --
*
* Adds the method names defined by a class (or its superclasses) to the
* collection being built. The collection is built in a hash table to
* ensure that duplicates are excluded. Helper for GetSortedMethodList().
*
* ----------------------------------------------------------------------
*/
static void
AddClassMethodNames(
Class *clsPtr, /* Class to get method names from. */
int flags, /* Whether we are interested in just the
* public method names. */
Tcl_HashTable *const namesPtr,
/* Reference to the hash table to put the
|
| ︙ | ︙ | |||
794 795 796 797 798 799 800 |
{
FOREACH_HASH_DECLS;
Method *mPtr;
Tcl_Obj *namePtr;
FOREACH_HASH(namePtr, mPtr, methodsTablePtr) {
if (IS_PRIVATE(mPtr)) {
| > > | | 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 |
{
FOREACH_HASH_DECLS;
Method *mPtr;
Tcl_Obj *namePtr;
FOREACH_HASH(namePtr, mPtr, methodsTablePtr) {
if (IS_PRIVATE(mPtr)) {
int isNew;
hPtr = Tcl_CreateHashEntry(namesPtr, namePtr, &isNew);
Tcl_SetHashValue(hPtr, INT2PTR(IN_LIST));
}
}
}
static inline void
AddStandardMethodName(
|
| ︙ | ︙ | |||
816 817 818 819 820 821 822 |
Tcl_HashEntry *hPtr =
Tcl_CreateHashEntry(namesPtr, namePtr, &isNew);
if (isNew) {
int isWanted = (!WANT_PUBLIC(flags) || IS_PUBLIC(mPtr))
? IN_LIST : 0;
| | | | > | | | > | | | | 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 |
Tcl_HashEntry *hPtr =
Tcl_CreateHashEntry(namesPtr, namePtr, &isNew);
if (isNew) {
int isWanted = (!WANT_PUBLIC(flags) || IS_PUBLIC(mPtr))
? IN_LIST : 0;
isWanted |= (mPtr->typePtr == NULL ? NO_IMPLEMENTATION : 0);
Tcl_SetHashValue(hPtr, INT2PTR(isWanted));
} else if ((PTR2INT(Tcl_GetHashValue(hPtr)) & NO_IMPLEMENTATION)
&& mPtr->typePtr != NULL) {
int isWanted = PTR2INT(Tcl_GetHashValue(hPtr));
isWanted &= ~NO_IMPLEMENTATION;
Tcl_SetHashValue(hPtr, INT2PTR(isWanted));
}
}
}
/*
* ----------------------------------------------------------------------
*
* AddInstancePrivateToCallContext --
*
* Add private methods from the instance. Called when the calling Tcl
* context is a TclOO method declared by an object that is the same as
* the current object. Returns true iff a private method was actually
* found and added to the call chain (as this suppresses caching).
*
* ----------------------------------------------------------------------
*/
static inline int
AddInstancePrivateToCallContext(
Object *const oPtr, /* Object to add call chain entries for. */
Tcl_Obj *const methodName, /* Name of method to add the call chain
* entries for. */
ChainBuilder *const cbPtr, /* Where to add the call chain entries. */
int flags) /* What sort of call chain are we building. */
{
Tcl_HashEntry *hPtr;
Method *mPtr;
int donePrivate = 0;
if (oPtr->methodsPtr) {
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, methodName);
if (hPtr != NULL) {
mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (IS_PRIVATE(mPtr)) {
AddMethodToCallChain(mPtr, cbPtr, NULL, NULL, flags);
donePrivate = 1;
}
}
}
return donePrivate;
}
/*
* ----------------------------------------------------------------------
*
* AddSimpleChainToCallContext --
*
* The core of the call-chain construction engine, this handles calling a
* particular method on a particular object. Note that filters and
* unknown handling are already handled by the logic that uses this
* function. Returns true if a private method was one of those found.
*
* ----------------------------------------------------------------------
*/
static inline int
AddSimpleChainToCallContext(
Object *const oPtr, /* Object to add call chain entries for. */
Class *const contextCls, /* Context class; the currently considered
* class is equal to this, private methods may
* also be added. [TIP 500] */
Tcl_Obj *const methodNameObj,
/* Name of method to add the call chain
* entries for. */
ChainBuilder *const cbPtr, /* Where to add the call chain entries. */
Tcl_HashTable *const doneFilters,
/* Where to record what call chain entries
* have been processed. */
int flags, /* What sort of call chain are we building. */
Class *const filterDecl) /* The class that declared the filter. If
* NULL, either the filter was declared by the
* object or this isn't a filter. */
{
Tcl_Size i;
int foundPrivate = 0, blockedUnexported = 0;
Tcl_HashEntry *hPtr;
Method *mPtr;
if (!(flags & (KNOWN_STATE | SPECIAL)) && oPtr->methodsPtr) {
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, methodNameObj);
if (hPtr != NULL) {
mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (!IS_PRIVATE(mPtr)) {
if (WANT_PUBLIC(flags)) {
if (!IS_PUBLIC(mPtr)) {
blockedUnexported = 1;
} else {
flags |= DEFINITE_PUBLIC;
}
} else {
flags |= DEFINITE_PROTECTED;
}
}
|
| ︙ | ︙ | |||
967 968 969 970 971 972 973 974 975 976 977 978 979 980 |
* AddMethodToCallChain --
*
* Utility method that manages the adding of a particular method
* implementation to a call-chain.
*
* ----------------------------------------------------------------------
*/
static inline void
AddMethodToCallChain(
Method *const mPtr, /* Actual method implementation to add to call
* chain (or NULL, a no-op). */
ChainBuilder *const cbPtr, /* The call chain to add the method
* implementation to. */
Tcl_HashTable *const doneFilters,
| > | 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 |
* AddMethodToCallChain --
*
* Utility method that manages the adding of a particular method
* implementation to a call-chain.
*
* ----------------------------------------------------------------------
*/
static inline void
AddMethodToCallChain(
Method *const mPtr, /* Actual method implementation to add to call
* chain (or NULL, a no-op). */
ChainBuilder *const cbPtr, /* The call chain to add the method
* implementation to. */
Tcl_HashTable *const doneFilters,
|
| ︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 |
* Return if this is just an entry used to record whether this is a public
* method. If so, there's nothing real to call and so nothing to add to
* the call chain.
*
* This is also where we enforce mixin-consistency.
*/
| | | 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 |
* Return if this is just an entry used to record whether this is a public
* method. If so, there's nothing real to call and so nothing to add to
* the call chain.
*
* This is also where we enforce mixin-consistency.
*/
if (mPtr == NULL || mPtr->typePtr == NULL || !MIXIN_CONSISTENT(flags)) {
return;
}
/*
* Enforce real private method handling here. We will skip adding this
* method IF
* 1) we are not allowing private methods, AND
|
| ︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 |
callPtr->numChain++;
}
/*
* ----------------------------------------------------------------------
*
* InitCallChain --
| < > | 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 |
callPtr->numChain++;
}
/*
* ----------------------------------------------------------------------
*
* InitCallChain --
* Encoding of the policy of how to set up a call chain. Doesn't populate
* the chain with the method implementation data.
*
* ----------------------------------------------------------------------
*/
static inline void
InitCallChain(
CallChain *callPtr,
Object *oPtr,
int flags)
{
/*
|
| ︙ | ︙ | |||
1130 1131 1132 1133 1134 1135 1136 | * - Still across the same object structure (same local epoch), and * - No public/private/filter magic leakage (same flags, modulo the fact * that a public chain will satisfy a non-public call). * * ---------------------------------------------------------------------- */ | | | 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 |
* - Still across the same object structure (same local epoch), and
* - No public/private/filter magic leakage (same flags, modulo the fact
* that a public chain will satisfy a non-public call).
*
* ----------------------------------------------------------------------
*/
static inline int
IsStillValid(
CallChain *callPtr,
Object *oPtr,
int flags,
int mask)
{
if ((oPtr->flags & USE_CLASS_CACHE)) {
|
| ︙ | ︙ | |||
1190 1191 1192 1193 1194 1195 1196 |
* to be in the same object as the
* methodNameObj. */
{
CallContext *contextPtr;
CallChain *callPtr;
ChainBuilder cb;
Tcl_Size i, count;
| | | | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 |
* to be in the same object as the
* methodNameObj. */
{
CallContext *contextPtr;
CallChain *callPtr;
ChainBuilder cb;
Tcl_Size i, count;
int doFilters, donePrivate = 0;
Tcl_HashEntry *hPtr;
Tcl_HashTable doneFilters;
if (cacheInThisObj == NULL) {
cacheInThisObj = methodNameObj;
}
if (flags&(SPECIAL|FILTER_HANDLING) || (oPtr->flags&FILTER_HANDLING)) {
hPtr = NULL;
doFilters = 0;
/*
* Check if we have a cached valid constructor or destructor.
*/
if (flags & CONSTRUCTOR) {
callPtr = oPtr->selfCls->constructorChainPtr;
|
| ︙ | ︙ | |||
1230 1231 1232 1233 1234 1235 1236 1237 | /* * Check if we can get the chain out of the Tcl_Obj method name or out * of the cache. This is made a bit more complex by the fact that * there are multiple different layers of cache (in the Tcl_Obj, in * the object, and in the class). */ const int reuseMask = (WANT_PUBLIC(flags) ? ~0 : ~PUBLIC_METHOD); | > < < | | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 |
/*
* Check if we can get the chain out of the Tcl_Obj method name or out
* of the cache. This is made a bit more complex by the fact that
* there are multiple different layers of cache (in the Tcl_Obj, in
* the object, and in the class).
*/
const Tcl_ObjInternalRep *irPtr;
const int reuseMask = (WANT_PUBLIC(flags) ? ~0 : ~PUBLIC_METHOD);
if ((irPtr = TclFetchInternalRep(cacheInThisObj, &methodNameType))) {
callPtr = (CallChain *) irPtr->twoPtrValue.ptr1;
if (IsStillValid(callPtr, oPtr, flags, reuseMask)) {
callPtr->refCount++;
goto returnContext;
}
Tcl_StoreInternalRep(cacheInThisObj, &methodNameType, NULL);
}
|
| ︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 | callPtr->refCount++; goto returnContext; } Tcl_SetHashValue(hPtr, NULL); TclOODeleteChain(callPtr); } | | | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 |
callPtr->refCount++;
goto returnContext;
}
Tcl_SetHashValue(hPtr, NULL);
TclOODeleteChain(callPtr);
}
doFilters = 1;
}
callPtr = (CallChain *) Tcl_Alloc(sizeof(CallChain));
InitCallChain(callPtr, oPtr, flags);
cb.callChainPtr = callPtr;
cb.filterLength = 0;
|
| ︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 |
* in the middle of processing a filter).
*/
if (doFilters) {
Tcl_Obj *filterObj;
Class *mixinPtr;
Tcl_InitObjHashTable(&doneFilters);
FOREACH(mixinPtr, oPtr->mixins) {
AddClassFiltersToCallContext(oPtr, mixinPtr, &cb, &doneFilters,
TRAVERSED_MIXIN|BUILDING_MIXINS|OBJECT_MIXIN);
AddClassFiltersToCallContext(oPtr, mixinPtr, &cb, &doneFilters,
OBJECT_MIXIN);
}
| > | 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 |
* in the middle of processing a filter).
*/
if (doFilters) {
Tcl_Obj *filterObj;
Class *mixinPtr;
doFilters = 1;
Tcl_InitObjHashTable(&doneFilters);
FOREACH(mixinPtr, oPtr->mixins) {
AddClassFiltersToCallContext(oPtr, mixinPtr, &cb, &doneFilters,
TRAVERSED_MIXIN|BUILDING_MIXINS|OBJECT_MIXIN);
AddClassFiltersToCallContext(oPtr, mixinPtr, &cb, &doneFilters,
OBJECT_MIXIN);
}
|
| ︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 |
callPtr->epoch = 0;
if (count == callPtr->numChain) {
TclOODeleteChain(callPtr);
return NULL;
}
} else {
if (hPtr == NULL) {
if (clsPtr->classChainCache == NULL) {
clsPtr->classChainCache = (Tcl_HashTable *)
Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(clsPtr->classChainCache);
}
hPtr = Tcl_CreateHashEntry(clsPtr->classChainCache,
| > | | 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 |
callPtr->epoch = 0;
if (count == callPtr->numChain) {
TclOODeleteChain(callPtr);
return NULL;
}
} else {
if (hPtr == NULL) {
int isNew;
if (clsPtr->classChainCache == NULL) {
clsPtr->classChainCache = (Tcl_HashTable *)
Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(clsPtr->classChainCache);
}
hPtr = Tcl_CreateHashEntry(clsPtr->classChainCache,
methodNameObj, &isNew);
}
callPtr->refCount++;
Tcl_SetHashValue(hPtr, callPtr);
StashCallChain(methodNameObj, callPtr);
}
return callPtr;
}
|
| ︙ | ︙ | |||
1677 1678 1679 1680 1681 1682 1683 | * Helper for AddSimpleChainToCallContext that is used to find private * methds and add them to the call chain. Returns true when a private * method is found and added. [TIP 500] * * ---------------------------------------------------------------------- */ | | | 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 |
* Helper for AddSimpleChainToCallContext that is used to find private
* methds and add them to the call chain. Returns true when a private
* method is found and added. [TIP 500]
*
* ----------------------------------------------------------------------
*/
static int
AddPrivatesFromClassChainToCallContext(
Class *classPtr, /* Class to add the call chain entries for. */
Class *const contextCls, /* Context class; the currently considered
* class is equal to this, private methods may
* also be added. */
Tcl_Obj *const methodName, /* Name of method to add the call chain
* entries for. */
|
| ︙ | ︙ | |||
1711 1712 1713 1714 1715 1716 1717 |
* Note also that it's possible to end up with a null classPtr here if
* there is a call into stereotypical object after it has finished running
* its destructor phase. [Bug 7842f33a5c]
*/
tailRecurse:
if (classPtr == NULL) {
| | | | | | | | | 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 |
* Note also that it's possible to end up with a null classPtr here if
* there is a call into stereotypical object after it has finished running
* its destructor phase. [Bug 7842f33a5c]
*/
tailRecurse:
if (classPtr == NULL) {
return 0;
}
FOREACH(superPtr, classPtr->mixins) {
if (AddPrivatesFromClassChainToCallContext(superPtr, contextCls,
methodName, cbPtr, doneFilters, flags|TRAVERSED_MIXIN,
filterDecl)) {
return 1;
}
}
if (classPtr == contextCls) {
Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&classPtr->classMethods,
methodName);
if (hPtr != NULL) {
Method *mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (IS_PRIVATE(mPtr)) {
AddMethodToCallChain(mPtr, cbPtr, doneFilters, filterDecl,
flags);
return 1;
}
}
}
switch (classPtr->superclasses.num) {
case 1:
classPtr = classPtr->superclasses.list[0];
goto tailRecurse;
default:
FOREACH(superPtr, classPtr->superclasses) {
if (AddPrivatesFromClassChainToCallContext(superPtr, contextCls,
methodName, cbPtr, doneFilters, flags, filterDecl)) {
return 1;
}
}
TCL_FALLTHROUGH();
case 0:
return 0;
}
}
/*
* ----------------------------------------------------------------------
*
* AddSimpleClassChainToCallContext --
*
* Construct a call-chain from a class hierarchy.
*
* ----------------------------------------------------------------------
*/
static int
AddSimpleClassChainToCallContext(
Class *classPtr, /* Class to add the call chain entries for. */
Tcl_Obj *const methodNameObj,
/* Name of method to add the call chain
* entries for. */
ChainBuilder *const cbPtr, /* Where to add the call chain entries. */
Tcl_HashTable *const doneFilters,
/* Where to record what call chain entries
* have been processed. */
int flags, /* What sort of call chain are we building. */
Class *const filterDecl) /* The class that declared the filter. If
* NULL, either the filter was declared by the
* object or this isn't a filter. */
{
Tcl_Size i;
int privateDanger = 0;
Class *superPtr;
/*
* We hard-code the tail-recursive form. It's by far the most common case
* *and* it is much more gentle on the stack.
*
* Note that mixins must be processed before the main class hierarchy.
|
| ︙ | ︙ | |||
1811 1812 1813 1814 1815 1816 1817 |
AddMethodToCallChain(classPtr->destructorPtr, cbPtr, doneFilters,
filterDecl, flags);
} else {
Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&classPtr->classMethods,
methodNameObj);
if (classPtr->flags & HAS_PRIVATE_METHODS) {
| | | 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 |
AddMethodToCallChain(classPtr->destructorPtr, cbPtr, doneFilters,
filterDecl, flags);
} else {
Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&classPtr->classMethods,
methodNameObj);
if (classPtr->flags & HAS_PRIVATE_METHODS) {
privateDanger |= 1;
}
if (hPtr != NULL) {
Method *mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (!IS_PRIVATE(mPtr)) {
if (!(flags & KNOWN_STATE)) {
if (flags & PUBLIC_METHOD) {
|
| ︙ | ︙ | |||
1896 1897 1898 1899 1900 1901 1902 |
objv = (Tcl_Obj **)
TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *));
for (i = 0 ; i < callPtr->numChain ; i++) {
MInvoke *miPtr = &callPtr->chain[i];
descObjs[0] =
| | | | | | | | | | 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 |
objv = (Tcl_Obj **)
TclStackAlloc(interp, callPtr->numChain * sizeof(Tcl_Obj *));
for (i = 0 ; i < callPtr->numChain ; i++) {
MInvoke *miPtr = &callPtr->chain[i];
descObjs[0] =
miPtr->isFilter ? filterLiteral :
callPtr->flags & OO_UNKNOWN_METHOD ? fPtr->unknownMethodNameObj :
IS_PRIVATE(miPtr->mPtr) ? privateLiteral :
methodLiteral;
descObjs[1] =
callPtr->flags & CONSTRUCTOR ? fPtr->constructorName :
callPtr->flags & DESTRUCTOR ? fPtr->destructorName :
miPtr->mPtr->namePtr;
descObjs[2] = miPtr->mPtr->declaringClassPtr
? Tcl_GetObjectName(interp,
(Tcl_Object) miPtr->mPtr->declaringClassPtr->thisPtr)
: objectLiteral;
descObjs[3] = Tcl_NewStringObj(miPtr->mPtr->typePtr->name,
TCL_AUTO_LENGTH);
objv[i] = Tcl_NewListObj(4, descObjs);
}
/*
* Drop the local references to the literals; if they're actually used,
|
| ︙ | ︙ | |||
1959 1960 1961 1962 1963 1964 1965 |
#define DEFINE_CHAIN_STATIC_SIZE 4 /* Enough space to store most cases. */
Tcl_Namespace *
TclOOGetDefineContextNamespace(
Tcl_Interp *interp, /* In what interpreter should namespace names
* actually be resolved. */
Object *oPtr, /* The object to get the context for. */
| | | 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 |
#define DEFINE_CHAIN_STATIC_SIZE 4 /* Enough space to store most cases. */
Tcl_Namespace *
TclOOGetDefineContextNamespace(
Tcl_Interp *interp, /* In what interpreter should namespace names
* actually be resolved. */
Object *oPtr, /* The object to get the context for. */
int forClass) /* What sort of context are we looking for.
* If true, we are going to use this for
* [oo::define], otherwise, we are going to
* use this for [oo::objdefine]. */
{
DefineChain define;
DefineEntry staticSpace[DEFINE_CHAIN_STATIC_SIZE];
DefineEntry *entryPtr;
|
| ︙ | ︙ |
Changes to generic/tclOODecls.h.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | #endif #ifdef USE_TCL_STUBS # undef USE_TCLOO_STUBS # define USE_TCLOO_STUBS #endif | | | > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#endif
#ifdef USE_TCL_STUBS
# undef USE_TCLOO_STUBS
# define USE_TCLOO_STUBS
#endif
#if TCL_MAJOR_VERSION < 9
# define Tcl_MethodType2 void
#if !defined(Tcl_Size)
# define Tcl_Size int
# define _TCLSIZEHANDLED
# endif
#endif
/* !BEGIN!: Do not edit below this line. */
#ifdef __cplusplus
extern "C" {
#endif
|
| ︙ | ︙ | |||
270 271 272 273 274 275 276 | #define Tcl_NewMethod2 \ (tclOOStubsPtr->tcl_NewMethod2) /* 34 */ #endif /* defined(USE_TCLOO_STUBS) */ /* !END!: Do not edit above this line. */ | | > | | | | | < < < < < < | < < < < < < < < < < | < < < < < < < < < < < < < < < | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
#define Tcl_NewMethod2 \
(tclOOStubsPtr->tcl_NewMethod2) /* 34 */
#endif /* defined(USE_TCLOO_STUBS) */
/* !END!: Do not edit above this line. */
#if TCL_MAJOR_VERSION < 9
/* TIP #630 */
# undef Tcl_MethodType2
# undef Tcl_MethodIsType2
# undef Tcl_NewInstanceMethod2
# undef Tcl_NewMethod2
#endif
#ifdef _TCLSIZEHANDLED
# undef _TCLSIZEHANDLED
# undef Tcl_Size
#endif
#endif /* _TCLOODECLS */
|
Changes to generic/tclOODefineCmds.c.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
#define OBJNAME_LENGTH_IN_ERRORINFO_LIMIT 30
/*
* Some things that make it easier to declare a slot.
*/
typedef struct DeclaredSlot {
const char *name;
| | | | | | | | | | | | | | > > | > > | > > | > > | > > | | > | > > | > > | > > | > > > > > | > > > > > > > > > > > > > > | > > | > > | > > | > > > > > | > > > > > | > > | > > | > > | > > | > > | > > | > > | > > > > > | | | | | | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
#define OBJNAME_LENGTH_IN_ERRORINFO_LIMIT 30
/*
* Some things that make it easier to declare a slot.
*/
typedef struct DeclaredSlot {
const char *name;
const Tcl_MethodType getterType;
const Tcl_MethodType setterType;
const Tcl_MethodType resolverType;
const char *defaultOp; /* The default op, if not set by the class */
} DeclaredSlot;
#define SLOT(name,getter,setter,resolver,defOp) \
{"::oo::" name, \
{TCL_OO_METHOD_VERSION_1, "core method: " name " Getter", \
getter, NULL, NULL}, \
{TCL_OO_METHOD_VERSION_1, "core method: " name " Setter", \
setter, NULL, NULL}, \
{TCL_OO_METHOD_VERSION_1, "core method: " name " Resolver", \
resolver, NULL, NULL}, (defOp)}
typedef struct DeclaredSlotMethod {
const char *name;
int flags;
const Tcl_MethodType implType;
} DeclaredSlotMethod;
#define SLOT_METHOD(name,impl,flags) \
{name, flags, {TCL_OO_METHOD_VERSION_1, \
"core method: " name " slot", impl, NULL, NULL}}
/*
* A [string match] pattern used to determine if a method should be exported.
*/
#define PUBLIC_PATTERN "[a-z]*"
/*
* Forward declarations.
*/
static inline void BumpGlobalEpoch(Tcl_Interp *interp, Class *classPtr);
static inline void BumpInstanceEpoch(Object *oPtr);
static Tcl_Command FindCommand(Tcl_Interp *interp, Tcl_Obj *stringObj,
Tcl_Namespace *const namespacePtr);
static inline void GenerateErrorInfo(Tcl_Interp *interp, Object *oPtr,
Tcl_Obj *savedNameObj, const char *typeOfSubject);
static inline int MagicDefinitionInvoke(Tcl_Interp *interp,
Tcl_Namespace *nsPtr, int cmdIndex,
int objc, Tcl_Obj *const *objv);
static inline Class * GetClassInOuterContext(Tcl_Interp *interp,
Tcl_Obj *className, const char *errMsg);
static inline Tcl_Namespace *GetNamespaceInOuterContext(Tcl_Interp *interp,
Tcl_Obj *namespaceName);
static inline int InitDefineContext(Tcl_Interp *interp,
Tcl_Namespace *namespacePtr, Object *oPtr,
int objc, Tcl_Obj *const objv[]);
static inline void RecomputeClassCacheFlag(Object *oPtr);
static int RenameDeleteMethod(Tcl_Interp *interp, Object *oPtr,
int useClass, Tcl_Obj *const fromPtr,
Tcl_Obj *const toPtr);
static int Slot_Append(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_AppendNew(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_Clear(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_Prepend(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_Remove(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_Resolve(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_Set(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_Unimplemented(void *,
Tcl_Interp *interp, Tcl_ObjectContext,
int, Tcl_Obj *const *);
static int Slot_Unknown(void *,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassFilter_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassFilter_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassMixin_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassMixin_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassSuper_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassSuper_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassVars_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ClassVars_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ObjFilter_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ObjFilter_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ObjMixin_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ObjMixin_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ObjVars_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int ObjVars_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ClassReadableProps_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ClassReadableProps_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ClassWritableProps_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ClassWritableProps_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ObjectReadableProps_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ObjectReadableProps_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ObjectWritableProps_Get(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_ObjectWritableProps_Set(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Slot_ResolveClass(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
/*
* Now define the slots used in declarations.
*/
static const DeclaredSlot slots[] = {
SLOT("define::filter", ClassFilter_Get, ClassFilter_Set, NULL, NULL),
SLOT("define::mixin", ClassMixin_Get, ClassMixin_Set, Slot_ResolveClass, "-set"),
SLOT("define::superclass", ClassSuper_Get, ClassSuper_Set, Slot_ResolveClass, "-set"),
SLOT("define::variable", ClassVars_Get, ClassVars_Set, NULL, NULL),
SLOT("objdefine::filter", ObjFilter_Get, ObjFilter_Set, NULL, NULL),
SLOT("objdefine::mixin", ObjMixin_Get, ObjMixin_Set, Slot_ResolveClass, "-set"),
SLOT("objdefine::variable", ObjVars_Get, ObjVars_Set, NULL, NULL),
SLOT("configuresupport::readableproperties",
Configurable_ClassReadableProps_Get,
Configurable_ClassReadableProps_Set, NULL, NULL),
SLOT("configuresupport::writableproperties",
Configurable_ClassWritableProps_Get,
Configurable_ClassWritableProps_Set, NULL, NULL),
SLOT("configuresupport::objreadableproperties",
|
| ︙ | ︙ | |||
157 158 159 160 161 162 163 | }; /* * How to build the in-namespace name of a private variable. This is a pattern * used with Tcl_ObjPrintf(). */ | | | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
};
/*
* 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;
}
/*
* ----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
if ((oPtr->methodsPtr == NULL || oPtr->methodsPtr->numEntries == 0)
&& (oPtr->mixins.num == 0) && (oPtr->filters.num == 0)) {
oPtr->flags |= USE_CLASS_CACHE;
} else {
oPtr->flags &= ~USE_CLASS_CACHE;
}
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
if ((oPtr->methodsPtr == NULL || oPtr->methodsPtr->numEntries == 0)
&& (oPtr->mixins.num == 0) && (oPtr->filters.num == 0)) {
oPtr->flags |= USE_CLASS_CACHE;
} else {
oPtr->flags &= ~USE_CLASS_CACHE;
}
}
/*
* ----------------------------------------------------------------------
*
* TclOOObjectSetFilters --
*
* Install a list of filter method names into an object.
|
| ︙ | ︙ | |||
602 603 604 605 606 607 608 |
InstallStandardVariableMapping(
VariableNameList *vnlPtr,
Tcl_Size varc,
Tcl_Obj *const *varv)
{
Tcl_Obj *variableObj;
Tcl_Size i, n;
| | | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
InstallStandardVariableMapping(
VariableNameList *vnlPtr,
Tcl_Size varc,
Tcl_Obj *const *varv)
{
Tcl_Obj *variableObj;
Tcl_Size i, n;
int created;
Tcl_HashTable uniqueTable;
for (i=0 ; i<varc ; i++) {
Tcl_IncrRefCount(varv[i]);
}
FOREACH(variableObj, *vnlPtr) {
Tcl_DecrRefCount(variableObj);
|
| ︙ | ︙ | |||
625 626 627 628 629 630 631 |
vnlPtr->list = (Tcl_Obj **) Tcl_Alloc(sizeof(Tcl_Obj *) * varc);
}
}
vnlPtr->num = 0;
if (varc > 0) {
Tcl_InitObjHashTable(&uniqueTable);
for (i=n=0 ; i<varc ; i++) {
| | | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 |
vnlPtr->list = (Tcl_Obj **) Tcl_Alloc(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;
|
| ︙ | ︙ | |||
651 652 653 654 655 656 657 |
}
static inline void
InstallPrivateVariableMapping(
PrivateVariableList *pvlPtr,
Tcl_Size varc,
Tcl_Obj *const *varv,
| | | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 |
}
static inline void
InstallPrivateVariableMapping(
PrivateVariableList *pvlPtr,
Tcl_Size varc,
Tcl_Obj *const *varv,
int creationEpoch)
{
PrivateVariableMapping *privatePtr;
Tcl_Size i, n;
int created;
Tcl_HashTable uniqueTable;
for (i=0 ; i<varc ; i++) {
Tcl_IncrRefCount(varv[i]);
}
FOREACH_STRUCT(privatePtr, *pvlPtr) {
Tcl_DecrRefCount(privatePtr->variableObj);
|
| ︙ | ︙ | |||
682 683 684 685 686 687 688 |
}
}
pvlPtr->num = 0;
if (varc > 0) {
Tcl_InitObjHashTable(&uniqueTable);
for (i=n=0 ; i<varc ; i++) {
| | | | 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 |
}
}
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, TclGetString(varv[i]));
Tcl_IncrRefCount(privatePtr->fullNameObj);
} else {
|
| ︙ | ︙ | |||
722 723 724 725 726 727 728 |
* ----------------------------------------------------------------------
*/
static int
RenameDeleteMethod(
Tcl_Interp *interp,
Object *oPtr,
| | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 |
* ----------------------------------------------------------------------
*/
static int
RenameDeleteMethod(
Tcl_Interp *interp,
Object *oPtr,
int useClass,
Tcl_Obj *const fromPtr,
Tcl_Obj *const toPtr)
{
Tcl_HashEntry *hPtr, *newHPtr = NULL;
Method *mPtr;
int isNew;
|
| ︙ | ︙ | |||
814 815 816 817 818 819 820 |
* ----------------------------------------------------------------------
*/
int
TclOOUnknownDefinition(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 |
* ----------------------------------------------------------------------
*/
int
TclOOUnknownDefinition(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Namespace *nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
FOREACH_HASH_DECLS;
Tcl_Size soughtLen;
const char *soughtStr, *nameStr, *matchedStr = NULL;
|
| ︙ | ︙ | |||
851 852 853 854 855 856 857 |
if (matchedStr != NULL) {
/*
* Got one match, and only one match!
*/
Tcl_Obj **newObjv = (Tcl_Obj **)
| | | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 |
if (matchedStr != NULL) {
/*
* Got one match, and only one match!
*/
Tcl_Obj **newObjv = (Tcl_Obj **)
TclStackAlloc(interp, sizeof(Tcl_Obj*) * (objc - 1));
int result;
newObjv[0] = Tcl_NewStringObj(matchedStr, TCL_AUTO_LENGTH);
Tcl_IncrRefCount(newObjv[0]);
if (objc > 2) {
memcpy(newObjv + 1, objv + 2, sizeof(Tcl_Obj *) * (objc - 2));
}
|
| ︙ | ︙ | |||
950 951 952 953 954 955 956 |
*/
static inline int
InitDefineContext(
Tcl_Interp *interp,
Tcl_Namespace *namespacePtr,
Object *oPtr,
| | | | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 |
*/
static inline int
InitDefineContext(
Tcl_Interp *interp,
Tcl_Namespace *namespacePtr,
Object *oPtr,
int objc,
Tcl_Obj *const objv[])
{
CallFrame *framePtr, **framePtrPtr = &framePtr;
if (namespacePtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"no definition namespace available", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
|
| ︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 |
Tcl_Interp *interp)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return NULL;
}
if (!oPtr->classPtr) {
| > > | | 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 |
Tcl_Interp *interp)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return NULL;
}
if (!oPtr->classPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return NULL;
}
return oPtr->classPtr;
}
/*
* ----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1129 1130 1131 1132 1133 1134 1135 |
* was being configured. */
{
Tcl_Size length;
Tcl_Obj *realNameObj = Tcl_ObjectDeleted((Tcl_Object) oPtr)
? savedNameObj : TclOOObjectName(interp, oPtr);
const char *objName = TclGetStringFromObj(realNameObj, &length);
int limit = OBJNAME_LENGTH_IN_ERRORINFO_LIMIT;
| | | 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 |
* was being configured. */
{
Tcl_Size length;
Tcl_Obj *realNameObj = Tcl_ObjectDeleted((Tcl_Object) oPtr)
? savedNameObj : TclOOObjectName(interp, oPtr);
const char *objName = TclGetStringFromObj(realNameObj, &length);
int limit = OBJNAME_LENGTH_IN_ERRORINFO_LIMIT;
int overflow = (length > limit);
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (in definition script for %s \"%.*s%s\" line %d)",
typeOfSubject, (overflow ? limit : (int) length), objName,
(overflow ? "..." : ""), Tcl_GetErrorLine(interp)));
}
|
| ︙ | ︙ | |||
1155 1156 1157 1158 1159 1160 1161 |
*/
static inline int
MagicDefinitionInvoke(
Tcl_Interp *interp,
Tcl_Namespace *nsPtr,
int cmdIndex,
| | | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 |
*/
static inline int
MagicDefinitionInvoke(
Tcl_Interp *interp,
Tcl_Namespace *nsPtr,
int cmdIndex,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *objPtr, *obj2Ptr, **objs;
Tcl_Command cmd;
int isRoot, result, offset = cmdIndex + 1;
Tcl_Size dummy;
/*
* More than one argument: fire them through the ensemble processing
* engine so that everything appears to be good and proper in error
* messages. Note that we cannot just concatenate and send through
* Tcl_EvalObjEx, as that doesn't do ensemble processing, and we cannot go
* through Tcl_EvalObjv without the extra work to pre-find the command, as
* that finds command names in the wrong namespace at the moment. Ugly!
*/
isRoot = TclInitRewriteEnsemble(interp, offset, 1, objv);
/*
* Build the list of arguments using a Tcl_Obj as a workspace. See
* comments above for why these contortions are necessary.
*/
TclNewObj(objPtr);
|
| ︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 |
// Make a blank method record or look up the existing one.
static inline Method *
GetOrCreateMethod(
Tcl_HashTable *tablePtr,
Tcl_Obj *namePtr,
int *isNew)
{
| | > > | | | 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 |
// Make a blank method record or look up the existing one.
static inline Method *
GetOrCreateMethod(
Tcl_HashTable *tablePtr,
Tcl_Obj *namePtr,
int *isNew)
{
Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(tablePtr, namePtr,
isNew);
if (*isNew) {
Method *mPtr = (Method *) Tcl_Alloc(sizeof(Method));
memset(mPtr, 0, sizeof(Method));
mPtr->refCount = 1;
mPtr->namePtr = namePtr;
Tcl_IncrRefCount(namePtr);
Tcl_SetHashValue(hPtr, mPtr);
return mPtr;
} else {
return (Method *) Tcl_GetHashValue(hPtr);
}
}
static int
ExportMethod(
Class *clsPtr,
Tcl_Obj *namePtr)
{
int isNew;
Method *mPtr = GetOrCreateMethod(&clsPtr->classMethods, namePtr, &isNew);
if (isNew || !(mPtr->flags & (PUBLIC_METHOD | PRIVATE_METHOD))) {
mPtr->flags |= PUBLIC_METHOD;
mPtr->flags &= ~TRUE_PRIVATE_METHOD;
isNew = 1;
}
return isNew;
}
static int
UnexportMethod(
Class *clsPtr,
Tcl_Obj *namePtr)
{
int isNew;
Method *mPtr = GetOrCreateMethod(&clsPtr->classMethods, namePtr, &isNew);
if (isNew || mPtr->flags & (PUBLIC_METHOD | TRUE_PRIVATE_METHOD)) {
|
| ︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 |
if (!oPtr->methodsPtr) {
oPtr->methodsPtr = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(oPtr->methodsPtr);
oPtr->flags &= ~USE_CLASS_CACHE;
}
}
| | | < > | > > | < > | > > | | 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 |
if (!oPtr->methodsPtr) {
oPtr->methodsPtr = (Tcl_HashTable *) Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitObjHashTable(oPtr->methodsPtr);
oPtr->flags &= ~USE_CLASS_CACHE;
}
}
static int
ExportInstanceMethod(
Object *oPtr,
Tcl_Obj *namePtr)
{
InitMethodTable(oPtr);
int isNew;
Method *mPtr = GetOrCreateMethod(oPtr->methodsPtr, namePtr, &isNew);
if (isNew || !(mPtr->flags & (PUBLIC_METHOD | PRIVATE_METHOD))) {
mPtr->flags |= PUBLIC_METHOD;
mPtr->flags &= ~TRUE_PRIVATE_METHOD;
isNew = 1;
}
return isNew;
}
static int
UnexportInstanceMethod(
Object *oPtr,
Tcl_Obj *namePtr)
{
InitMethodTable(oPtr);
int isNew;
Method *mPtr = GetOrCreateMethod(oPtr->methodsPtr, namePtr, &isNew);
if (isNew || mPtr->flags & (PUBLIC_METHOD | TRUE_PRIVATE_METHOD)) {
mPtr->flags &= ~(PUBLIC_METHOD | TRUE_PRIVATE_METHOD);
isNew = 1;
}
return isNew;
}
int
TclOOExportMethods(
Class *clsPtr,
...)
{
va_list argList;
int changed = 0;
va_start(argList, clsPtr);
while (1) {
const char *name = va_arg(argList, char *);
Tcl_Obj *namePtr;
if (!name) {
break;
}
namePtr = Tcl_NewStringObj(name, TCL_AUTO_LENGTH);
changed |= ExportMethod(clsPtr, namePtr);
Tcl_BounceRefCount(namePtr);
}
va_end(argList);
return changed;
}
int
TclOOUnexportMethods(
Class *clsPtr,
...)
{
va_list argList;
int changed = 0;
va_start(argList, clsPtr);
while (1) {
const char *name = va_arg(argList, char *);
Tcl_Obj *namePtr;
if (!name) {
break;
}
namePtr = Tcl_NewStringObj(name, TCL_AUTO_LENGTH);
changed |= UnexportMethod(clsPtr, namePtr);
Tcl_BounceRefCount(namePtr);
}
va_end(argList);
return changed;
}
|
| ︙ | ︙ | |||
1377 1378 1379 1380 1381 1382 1383 |
* ----------------------------------------------------------------------
*/
int
TclOODefineObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 |
* ----------------------------------------------------------------------
*/
int
TclOODefineObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Namespace *nsPtr;
Object *oPtr;
int result;
if (objc < 3) {
|
| ︙ | ︙ | |||
1406 1407 1408 1409 1410 1411 1412 |
}
/*
* Make the oo::define namespace the current namespace and evaluate the
* command(s).
*/
| | | 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 |
}
/*
* Make the oo::define namespace the current namespace and evaluate the
* command(s).
*/
nsPtr = TclOOGetDefineContextNamespace(interp, oPtr, 1);
if (InitDefineContext(interp, nsPtr, oPtr, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
AddRef(oPtr);
if (objc == 3) {
Tcl_Obj *objNameObj = TclOOObjectName(interp, oPtr);
|
| ︙ | ︙ | |||
1453 1454 1455 1456 1457 1458 1459 |
* ----------------------------------------------------------------------
*/
int
TclOOObjDefObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 |
* ----------------------------------------------------------------------
*/
int
TclOOObjDefObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Namespace *nsPtr;
Object *oPtr;
int result;
if (objc < 3) {
|
| ︙ | ︙ | |||
1475 1476 1477 1478 1479 1480 1481 |
}
/*
* Make the oo::objdefine namespace the current namespace and evaluate the
* command(s).
*/
| | | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 |
}
/*
* Make the oo::objdefine namespace the current namespace and evaluate the
* command(s).
*/
nsPtr = TclOOGetDefineContextNamespace(interp, oPtr, 0);
if (InitDefineContext(interp, nsPtr, oPtr, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
AddRef(oPtr);
if (objc == 3) {
Tcl_Obj *objNameObj = TclOOObjectName(interp, oPtr);
|
| ︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 |
* ----------------------------------------------------------------------
*/
int
TclOODefineSelfObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 |
* ----------------------------------------------------------------------
*/
int
TclOODefineSelfObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Namespace *nsPtr;
Object *oPtr;
int result, isPrivate;
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (objc < 2) {
Tcl_SetObjResult(interp, TclOOObjectName(interp, oPtr));
return TCL_OK;
}
isPrivate = IsPrivateDefine(interp);
/*
* Make the oo::objdefine namespace the current namespace and evaluate the
* command(s).
*/
nsPtr = TclOOGetDefineContextNamespace(interp, oPtr, 0);
if (InitDefineContext(interp, nsPtr, oPtr, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
if (isPrivate) {
((Interp *) interp)->varFramePtr->isProcCallFrame = PRIVATE_FRAME;
}
|
| ︙ | ︙ | |||
1593 1594 1595 1596 1597 1598 1599 |
* ----------------------------------------------------------------------
*/
int
TclOODefineObjSelfObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 |
* ----------------------------------------------------------------------
*/
int
TclOODefineObjSelfObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, NULL);
return TCL_ERROR;
|
| ︙ | ︙ | |||
1627 1628 1629 1630 1631 1632 1633 |
* ----------------------------------------------------------------------
*/
int
TclOODefinePrivateObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | | 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 |
* ----------------------------------------------------------------------
*/
int
TclOODefinePrivateObjCmd(
void *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
|
| ︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 |
* ----------------------------------------------------------------------
*/
int
TclOODefineClassObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | > | 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 |
* ----------------------------------------------------------------------
*/
int
TclOODefineClassObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr;
Class *clsPtr;
Foundation *fPtr = TclOOGetFoundation(interp);
int wasClass, willBeClass;
/*
* Parse the context to get the object to operate on.
*/
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
|
| ︙ | ︙ | |||
1755 1756 1757 1758 1759 1760 1761 |
return TCL_ERROR;
}
/*
* Set the object's class.
*/
| | | | 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 |
return TCL_ERROR;
}
/*
* Set the object's class.
*/
wasClass = (oPtr->classPtr != NULL);
willBeClass = (TclOOIsReachable(fPtr->classCls, clsPtr));
if (oPtr->selfCls != clsPtr) {
TclOORemoveFromInstances(oPtr, oPtr->selfCls);
TclOODecrRefCount(oPtr->selfCls->thisPtr);
oPtr->selfCls = clsPtr;
AddRef(oPtr->selfCls->thisPtr);
TclOOAddToInstances(oPtr, oPtr->selfCls);
|
| ︙ | ︙ | |||
1811 1812 1813 1814 1815 1816 1817 |
* ----------------------------------------------------------------------
*/
int
TclOODefineConstructorObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 |
* ----------------------------------------------------------------------
*/
int
TclOODefineConstructorObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Method method;
Tcl_Size bodyLength;
if (clsPtr == NULL) {
|
| ︙ | ︙ | |||
1870 1871 1872 1873 1874 1875 1876 |
* ----------------------------------------------------------------------
*/
int
TclOODefineDefnNsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 |
* ----------------------------------------------------------------------
*/
int
TclOODefineDefnNsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
static const char *const kindList[] = {
"-class",
"-instance",
NULL
};
|
| ︙ | ︙ | |||
1947 1948 1949 1950 1951 1952 1953 |
* ----------------------------------------------------------------------
*/
int
TclOODefineDeleteMethodObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | > > > > | | | 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 |
* ----------------------------------------------------------------------
*/
int
TclOODefineDeleteMethodObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int isInstanceDeleteMethod = (clientData != NULL);
Object *oPtr;
int i;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?name ...?");
return TCL_ERROR;
}
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!isInstanceDeleteMethod && !oPtr->classPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return TCL_ERROR;
}
for (i = 1; i < objc; i++) {
/*
* Delete the method structure from the appropriate hash table.
*/
if (RenameDeleteMethod(interp, oPtr, !isInstanceDeleteMethod,
objv[i], NULL) != TCL_OK) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
2000 2001 2002 2003 2004 2005 2006 |
* ----------------------------------------------------------------------
*/
int
TclOODefineDestructorObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | > | 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 |
* ----------------------------------------------------------------------
*/
int
TclOODefineDestructorObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Method method;
Tcl_Size bodyLength;
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
if (clsPtr == NULL) {
return TCL_ERROR;
} else if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "body");
return TCL_ERROR;
}
(void) TclGetStringFromObj(objv[1], &bodyLength);
if (bodyLength > 0) {
/*
* Create the method structure.
*/
|
| ︙ | ︙ | |||
2060 2061 2062 2063 2064 2065 2066 |
* ----------------------------------------------------------------------
*/
int
TclOODefineExportObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | > > > | | > > > | | | 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 |
* ----------------------------------------------------------------------
*/
int
TclOODefineExportObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int isInstanceExport = (clientData != NULL);
int i, changed = 0;
Object *oPtr;
Class *clsPtr;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?name ...?");
return TCL_ERROR;
}
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
}
clsPtr = oPtr->classPtr;
if (!isInstanceExport && !clsPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return TCL_ERROR;
}
for (i = 1; i < objc; i++) {
/*
* Exporting is done by adding the PUBLIC_METHOD flag to the method
* record. If there is no such method in this object or class (i.e.
* the method comes from something inherited from or that we're an
* instance of) then we put in a blank record with that flag; such
* records are skipped over by the call chain engine *except* for
* their flags member.
|
| ︙ | ︙ | |||
2125 2126 2127 2128 2129 2130 2131 |
* ----------------------------------------------------------------------
*/
int
TclOODefineForwardObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | | > > > | | | | | | 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 |
* ----------------------------------------------------------------------
*/
int
TclOODefineForwardObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int isInstanceForward = (clientData != NULL);
Object *oPtr;
Method *mPtr;
int isPublic;
Tcl_Obj *prefixObj;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "name cmdName ?arg ...?");
return TCL_ERROR;
}
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!isInstanceForward && !oPtr->classPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return TCL_ERROR;
}
isPublic = Tcl_StringMatch(TclGetString(objv[1]), PUBLIC_PATTERN)
? PUBLIC_METHOD : 0;
if (IsPrivateDefine(interp)) {
isPublic = TRUE_PRIVATE_METHOD;
}
/*
* Create the method structure.
*/
prefixObj = Tcl_NewListObj(objc - 2, objv + 2);
if (isInstanceForward) {
mPtr = TclOONewForwardInstanceMethod(interp, oPtr, isPublic, objv[1],
prefixObj);
} else {
mPtr = TclOONewForwardMethod(interp, oPtr->classPtr, isPublic,
objv[1], prefixObj);
}
if (mPtr == NULL) {
Tcl_DecrRefCount(prefixObj);
return TCL_ERROR;
}
return TCL_OK;
|
| ︙ | ︙ | |||
2186 2187 2188 2189 2190 2191 2192 |
* ----------------------------------------------------------------------
*/
int
TclOODefineInitialiseObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | > > > > | | < | | | < | < | | < | | | | > > > | | | | | | | | | 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 |
* ----------------------------------------------------------------------
*/
int
TclOODefineInitialiseObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Object object;
Tcl_Obj *lambdaWords[3], *applyArgs[2];
int result;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "body");
return TCL_ERROR;
}
/* Build the lambda */
object = TclOOGetDefineCmdContext(interp);
if (object == NULL) {
return TCL_ERROR;
}
lambdaWords[0] = Tcl_NewObj();
lambdaWords[1] = objv[1];
lambdaWords[2] = TclNewNamespaceObj(Tcl_GetObjectNamespace(object));
/* Delegate to [apply] to run it */
applyArgs[0] = Tcl_NewStringObj("apply", -1);
applyArgs[1] = Tcl_NewListObj(3, lambdaWords);
Tcl_IncrRefCount(applyArgs[0]);
Tcl_IncrRefCount(applyArgs[1]);
result = Tcl_ApplyObjCmd(NULL, interp, 2, applyArgs);
Tcl_DecrRefCount(applyArgs[0]);
Tcl_DecrRefCount(applyArgs[1]);
return result;
}
/*
* ----------------------------------------------------------------------
*
* TclOODefineMethodObjCmd --
*
* Implementation of the "method" subcommand of the "oo::define" and
* "oo::objdefine" commands.
*
* ----------------------------------------------------------------------
*/
int
TclOODefineMethodObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
/*
* Table of export modes for methods and their corresponding enum.
*/
static const char *const exportModes[] = {
"-export",
"-private",
"-unexport",
NULL
};
enum ExportMode {
MODE_EXPORT,
MODE_PRIVATE,
MODE_UNEXPORT
} exportMode;
int isInstanceMethod = (clientData != NULL);
Object *oPtr;
int isPublic = 0;
if (objc < 4 || objc > 5) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?option? args body");
return TCL_ERROR;
}
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!isInstanceMethod && !oPtr->classPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return TCL_ERROR;
}
if (objc == 5) {
if (Tcl_GetIndexFromObj(interp, objv[2], exportModes, "export flag",
0, &exportMode) != TCL_OK) {
return TCL_ERROR;
}
switch (exportMode) {
case MODE_EXPORT:
isPublic = PUBLIC_METHOD;
break;
case MODE_PRIVATE:
isPublic = TRUE_PRIVATE_METHOD;
break;
case MODE_UNEXPORT:
isPublic = 0;
break;
default:
TCL_UNREACHABLE();
}
} else {
if (IsPrivateDefine(interp)) {
isPublic = TRUE_PRIVATE_METHOD;
} else {
isPublic = Tcl_StringMatch(TclGetString(objv[1]), PUBLIC_PATTERN)
? PUBLIC_METHOD : 0;
}
}
/*
* Create the method by using the right back-end API.
*/
if (isInstanceMethod) {
if (TclOONewProcInstanceMethod(interp, oPtr, isPublic, objv[1],
objv[objc - 2], objv[objc - 1], NULL) == NULL) {
return TCL_ERROR;
}
} else {
if (TclOONewProcMethod(interp, oPtr->classPtr, isPublic, objv[1],
objv[objc - 2], objv[objc - 1], NULL) == NULL) {
return TCL_ERROR;
}
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
2328 2329 2330 2331 2332 2333 2334 |
* ----------------------------------------------------------------------
*/
int
TclOODefineClassMethodObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | > > > > > | | > | > > | > > | | | | | < | | < | | < | 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 |
* ----------------------------------------------------------------------
*/
int
TclOODefineClassMethodObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr;
int isPublic;
Tcl_Obj *forwardArgs[2], *prefixObj;
Method *mPtr;
if (objc != 2 && objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?args body?");
return TCL_ERROR;
}
clsPtr = TclOOGetClassDefineCmdContext(interp);
if (!clsPtr) {
return TCL_ERROR;
}
isPublic = Tcl_StringMatch(TclGetString(objv[1]), PUBLIC_PATTERN)
? PUBLIC_METHOD : 0;
/*
* Create the method on the delegate class if the caller gave arguments
* and body.
*/
if (objc == 4) {
Tcl_Obj *delegateName = Tcl_ObjPrintf("%s:: oo ::delegate",
clsPtr->thisPtr->namespacePtr->fullName);
Class *delegatePtr = TclOOGetClassFromObj(interp, delegateName);
Tcl_DecrRefCount(delegateName);
if (!delegatePtr) {
return TCL_ERROR;
}
if (IsPrivateDefine(interp)) {
isPublic = 0;
}
if (TclOONewProcMethod(interp, delegatePtr, isPublic, objv[1],
objv[2], objv[3], NULL) == NULL) {
return TCL_ERROR;
}
}
/* Make the connection to the delegate by forwarding */
if (IsPrivateDefine(interp)) {
isPublic = TRUE_PRIVATE_METHOD;
}
forwardArgs[0] = Tcl_NewStringObj("myclass", -1);
forwardArgs[1] = objv[1];
prefixObj = Tcl_NewListObj(2, forwardArgs);
mPtr = TclOONewForwardMethod(interp, clsPtr, isPublic, objv[1], prefixObj);
if (mPtr == NULL) {
Tcl_DecrRefCount(prefixObj);
return TCL_ERROR;
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
2393 2394 2395 2396 2397 2398 2399 |
* ----------------------------------------------------------------------
*/
int
TclOODefineRenameMethodObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | > > > | | 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 |
* ----------------------------------------------------------------------
*/
int
TclOODefineRenameMethodObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int isInstanceRenameMethod = (clientData != NULL);
Object *oPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "oldName newName");
return TCL_ERROR;
}
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!isInstanceRenameMethod && !oPtr->classPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return TCL_ERROR;
}
/*
* Delete the method entry from the appropriate hash table, and transfer
* the thing it points to to its new entry. To do this, we first need to
* get the entries from the appropriate hash tables (this can generate a
* range of errors...)
|
| ︙ | ︙ | |||
2447 2448 2449 2450 2451 2452 2453 |
* ----------------------------------------------------------------------
*/
int
TclOODefineUnexportObjCmd(
void *clientData,
Tcl_Interp *interp,
| | | > > > > | | | 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 |
* ----------------------------------------------------------------------
*/
int
TclOODefineUnexportObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
int isInstanceUnexport = (clientData != NULL);
Object *oPtr;
Class *clsPtr;
int i, changed = 0;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "name ?name ...?");
return TCL_ERROR;
}
oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
}
clsPtr = oPtr->classPtr;
if (!isInstanceUnexport && !clsPtr) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"attempt to misuse API", TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return TCL_ERROR;
}
for (i = 1; i < objc; i++) {
if (isInstanceUnexport) {
changed |= UnexportInstanceMethod(oPtr, objv[i]);
} else {
changed |= UnexportMethod(clsPtr, objv[i]);
}
}
|
| ︙ | ︙ | |||
2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 |
int
TclOODefineSlots(
Foundation *fPtr)
{
Tcl_Interp *interp = fPtr->interp;
Tcl_Object object = Tcl_NewObjectInstance(interp, (Tcl_Class)
fPtr->classCls, "::oo::Slot", NULL, TCL_INDEX_NONE, NULL, 0);
if (object == NULL) {
return TCL_ERROR;
}
| > > > > | | | | | < | | < | < < | < | | | > > | | < | | | | | | < | | > > | | | < | | | > > > | | | | | | > > | | | | | | | | | > > > > | | | | | < < < | | | | < | | | | > > | | | | > | | | | | | | | > > > > | | | | | < < < | | | | | | | | | | 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 |
int
TclOODefineSlots(
Foundation *fPtr)
{
Tcl_Interp *interp = fPtr->interp;
Tcl_Object object = Tcl_NewObjectInstance(interp, (Tcl_Class)
fPtr->classCls, "::oo::Slot", NULL, TCL_INDEX_NONE, NULL, 0);
Tcl_Class slotCls;
const DeclaredSlotMethod *smPtr;
const DeclaredSlot *slotPtr;
Tcl_Obj *defaults[2];
if (object == NULL) {
return TCL_ERROR;
}
slotCls = (Tcl_Class) ((Object *) object)->classPtr;
if (slotCls == NULL) {
return TCL_ERROR;
}
for (smPtr = slotMethods; smPtr->name; smPtr++) {
Tcl_Obj *name = Tcl_NewStringObj(smPtr->name, -1);
Tcl_NewMethod(interp, slotCls, name, smPtr->flags,
&smPtr->implType, NULL);
Tcl_BounceRefCount(name);
}
/* If a slot can't figure out what method to call directly, it uses
* --default-operation. That defaults to -append; we set that here. */
defaults[0] = fPtr->myName;
defaults[1] = Tcl_NewStringObj("-append", TCL_AUTO_LENGTH);
TclOONewForwardMethod(interp, (Class *) slotCls, 0,
fPtr->slotDefOpName, Tcl_NewListObj(2, defaults));
// Hide the destroy method. (We're definitely taking a ref to the name.)
UnexportMethod((Class *) slotCls,
Tcl_NewStringObj("destroy", TCL_AUTO_LENGTH));
for (slotPtr = slots ; slotPtr->name ; slotPtr++) {
Tcl_Object slotObject = Tcl_NewObjectInstance(interp,
slotCls, slotPtr->name, NULL, TCL_INDEX_NONE, NULL, 0);
if (slotObject == NULL) {
continue;
}
TclNewInstanceMethod(interp, slotObject, fPtr->slotGetName, 0,
&slotPtr->getterType, NULL);
TclNewInstanceMethod(interp, slotObject, fPtr->slotSetName, 0,
&slotPtr->setterType, NULL);
if (slotPtr->resolverType.callProc) {
TclNewInstanceMethod(interp, slotObject, fPtr->slotResolveName, 0,
&slotPtr->resolverType, NULL);
}
if (slotPtr->defaultOp) {
defaults[1] = Tcl_NewStringObj(slotPtr->defaultOp, TCL_AUTO_LENGTH);
TclOONewForwardInstanceMethod(interp, (Object *) slotObject, 0,
fPtr->slotDefOpName, Tcl_NewListObj(2, defaults));
}
}
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* CallSlotGet, CallSlotSet, CallSlotResolve, ResolveAll --
*
* How to call the standard low-level methods of a slot.
* ResolveAll is the lifting of CallSlotResolve to work over a whole
* list of items.
*
* ----------------------------------------------------------------------
*/
/* Call [$slot Get] to retrieve the list of contents of the slot. */
static inline Tcl_Obj *
CallSlotGet(
Tcl_Interp *interp,
Object *slot)
{
Tcl_Obj *getArgs[2];
int code;
getArgs[0] = slot->fPtr->myName;
getArgs[1] = slot->fPtr->slotGetName;
code = TclOOPrivateObjectCmd(slot, interp, 2, getArgs);
if (code != TCL_OK) {
return NULL;
}
return Tcl_GetObjResult(interp);
}
/* Call [$slot Set $list] to set the list of contents of the slot. */
static inline int
CallSlotSet(
Tcl_Interp *interp,
Object *slot,
Tcl_Obj *list)
{
Tcl_Obj *setArgs[3];
setArgs[0] = slot->fPtr->myName;
setArgs[1] = slot->fPtr->slotSetName;
setArgs[2] = list;
return TclOOPrivateObjectCmd(slot, interp, 3, setArgs);
}
/* Call [$slot Resolve $item] to convert a slot item into canonical form. */
static inline Tcl_Obj *
CallSlotResolve(
Tcl_Interp *interp,
Object *slot,
Tcl_Obj *item)
{
Tcl_Obj *resolveArgs[3];
int code;
resolveArgs[0] = slot->fPtr->myName;
resolveArgs[1] = slot->fPtr->slotResolveName;
resolveArgs[2] = item;
code = TclOOPrivateObjectCmd(slot, interp, 3, resolveArgs);
if (code != TCL_OK) {
return NULL;
}
return Tcl_GetObjResult(interp);
}
/* Call [$slot Resolve $item] for each of a whole list of items. */
static inline Tcl_Obj *
ResolveAll(
Tcl_Interp *interp,
Object *slot,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj **resolvedItems = (Tcl_Obj **) TclStackAlloc(interp,
sizeof(Tcl_Obj *) * objc);
Tcl_Obj *resolvedList;
int i;
for (i = 0; i < objc; i++) {
resolvedItems[i] = CallSlotResolve(interp, slot, objv[i]);
if (resolvedItems[i] == NULL) {
for (int j = 0; j < i; j++) {
Tcl_DecrRefCount(resolvedItems[j]);
}
TclStackFree(interp, (void *) resolvedItems);
return NULL;
}
Tcl_IncrRefCount(resolvedItems[i]);
Tcl_ResetResult(interp);
}
resolvedList = Tcl_NewListObj(objc, resolvedItems);
for (i = 0; i < objc; i++) {
TclDecrRefCount(resolvedItems[i]);
}
TclStackFree(interp, (void *) resolvedItems);
return resolvedList;
}
/*
* ----------------------------------------------------------------------
*
* Slot_Append --
*
* Implementation of the "-append" slot operation.
*
* ----------------------------------------------------------------------
*/
static int
Slot_Append(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
int skip = Tcl_ObjectContextSkippedArgs(context), code;
Tcl_Obj *resolved, *list;
if (skip == objc) {
return TCL_OK;
}
/* Resolve all values */
resolved = ResolveAll(interp, oPtr, objc - skip, objv + skip);
if (resolved == NULL) {
return TCL_ERROR;
}
/* Get slot contents; store in list */
list = CallSlotGet(interp, oPtr);
if (list == NULL) {
Tcl_DecrRefCount(resolved);
return TCL_ERROR;
}
Tcl_IncrRefCount(list);
Tcl_ResetResult(interp);
/* Append */
if (Tcl_IsShared(list)) {
Tcl_Obj *dup = Tcl_DuplicateObj(list);
Tcl_IncrRefCount(dup);
Tcl_DecrRefCount(list);
list = dup;
}
if (Tcl_ListObjAppendList(interp, list, resolved) != TCL_OK) {
Tcl_DecrRefCount(list);
Tcl_DecrRefCount(resolved);
return TCL_ERROR;
}
Tcl_DecrRefCount(resolved);
/* Set slot contents */
code = CallSlotSet(interp, oPtr, list);
Tcl_DecrRefCount(list);
return code;
}
/*
* ----------------------------------------------------------------------
*
* Slot_AppendNew --
*
* Implementation of the "-appendifnew" slot operation.
*
* ----------------------------------------------------------------------
*/
static int
Slot_AppendNew(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
int skip = Tcl_ObjectContextSkippedArgs(context), code, isNew;
Tcl_Obj *resolved, *list, **listv;
Tcl_Size listc, i;
Tcl_HashTable unique;
if (skip == objc) {
return TCL_OK;
}
/* Resolve all values */
resolved = ResolveAll(interp, oPtr, objc - skip, objv + skip);
if (resolved == NULL) {
return TCL_ERROR;
}
/* Get slot contents; store in list */
list = CallSlotGet(interp, oPtr);
if (list == NULL) {
Tcl_DecrRefCount(resolved);
return TCL_ERROR;
}
Tcl_IncrRefCount(list);
Tcl_ResetResult(interp);
/* Prepare a set of items in the list to set */
if (TclListObjGetElements(interp, list, &listc, &listv) != TCL_OK) {
Tcl_DecrRefCount(list);
Tcl_DecrRefCount(resolved);
return TCL_ERROR;
}
Tcl_InitObjHashTable(&unique);
for (i=0 ; i<listc; i++) {
Tcl_CreateHashEntry(&unique, listv[i], &isNew);
}
/* Append the new items if they're not already there */
if (Tcl_IsShared(list)) {
Tcl_Obj *dup = Tcl_DuplicateObj(list);
Tcl_IncrRefCount(dup);
Tcl_DecrRefCount(list);
list = dup;
}
TclListObjGetElements(NULL, resolved, &listc, &listv);
for (i=0 ; i<listc; i++) {
Tcl_CreateHashEntry(&unique, listv[i], &isNew);
if (isNew) {
Tcl_ListObjAppendElement(interp, list, listv[i]);
}
}
Tcl_DecrRefCount(resolved);
Tcl_DeleteHashTable(&unique);
/* Set slot contents */
code = CallSlotSet(interp, oPtr, list);
Tcl_DecrRefCount(list);
return code;
}
/*
* ----------------------------------------------------------------------
*
* Slot_Clear --
*
* Implementation of the "-clear" slot operation.
*
* ----------------------------------------------------------------------
*/
static int
Slot_Clear(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
int skip = Tcl_ObjectContextSkippedArgs(context), code;
Tcl_Obj *list;
if (skip != objc) {
Tcl_WrongNumArgs(interp, skip, objv, NULL);
return TCL_ERROR;
}
list = Tcl_NewObj();
Tcl_IncrRefCount(list);
code = CallSlotSet(interp, oPtr, list);
Tcl_DecrRefCount(list);
return code;
}
/*
* ----------------------------------------------------------------------
*
* Slot_Prepend --
*
* Implementation of the "-prepend" slot operation.
*
* ----------------------------------------------------------------------
*/
static int
Slot_Prepend(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
int skip = Tcl_ObjectContextSkippedArgs(context), code;
Tcl_Obj *list, *oldList;
if (skip == objc) {
return TCL_OK;
}
/* Resolve all values */
list = ResolveAll(interp, oPtr, objc - skip, objv + skip);
if (list == NULL) {
return TCL_ERROR;
}
Tcl_IncrRefCount(list);
/* Get slot contents and append to list */
oldList = CallSlotGet(interp, oPtr);
if (oldList == NULL) {
Tcl_DecrRefCount(list);
return TCL_ERROR;
}
Tcl_ListObjAppendList(NULL, list, oldList);
Tcl_ResetResult(interp);
/* Set slot contents */
code = CallSlotSet(interp, oPtr, list);
Tcl_DecrRefCount(list);
return code;
}
/*
* ----------------------------------------------------------------------
*
* Slot_Remove --
*
* Implementation of the "-remove" slot operation.
*
* ----------------------------------------------------------------------
*/
static int
Slot_Remove(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
int skip = Tcl_ObjectContextSkippedArgs(context), code, isNew;
Tcl_Size listc, i;
Tcl_Obj *resolved, *oldList, *newList, **listv;
Tcl_HashTable removeSet;
if (skip == objc) {
return TCL_OK;
}
/* Resolve all values */
resolved = ResolveAll(interp, oPtr, objc - skip, objv + skip);
if (resolved == NULL) {
return TCL_ERROR;
}
/* Get slot contents; store in list */
oldList = CallSlotGet(interp, oPtr);
if (oldList == NULL) {
Tcl_DecrRefCount(resolved);
return TCL_ERROR;
}
Tcl_IncrRefCount(oldList);
Tcl_ResetResult(interp);
/* Prepare a set of items in the list to remove */
TclListObjGetElements(NULL, resolved, &listc, &listv);
Tcl_InitObjHashTable(&removeSet);
for (i=0 ; i<listc; i++) {
Tcl_CreateHashEntry(&removeSet, listv[i], &isNew);
}
Tcl_DecrRefCount(resolved);
/* Append the new items from the old items if they're not in the remove set */
if (TclListObjGetElements(interp, oldList, &listc, &listv) != TCL_OK) {
Tcl_DecrRefCount(oldList);
Tcl_DeleteHashTable(&removeSet);
return TCL_ERROR;
}
newList = Tcl_NewObj();
for (i=0 ; i<listc; i++) {
if (Tcl_FindHashEntry(&removeSet, listv[i]) == NULL) {
Tcl_ListObjAppendElement(NULL, newList, listv[i]);
}
}
Tcl_DecrRefCount(oldList);
Tcl_DeleteHashTable(&removeSet);
/* Set slot contents */
Tcl_IncrRefCount(newList);
code = CallSlotSet(interp, oPtr, newList);
Tcl_DecrRefCount(newList);
return code;
}
/*
* ----------------------------------------------------------------------
*
* Slot_Resolve --
*
* Default implementation of the "Resolve" slot accessor. Just returns
* its argument unchanged; particular slots may override.
*
* ----------------------------------------------------------------------
*/
static int
Slot_Resolve(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
int skip = Tcl_ObjectContextSkippedArgs(context);
if (skip + 1 != objc) {
Tcl_WrongNumArgs(interp, skip, objv, "list");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, objv[objc - 1]);
return TCL_OK;
}
|
| ︙ | ︙ | |||
3034 3035 3036 3037 3038 3039 3040 |
* ----------------------------------------------------------------------
*/
static int
Slot_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | | | | | | 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 |
* ----------------------------------------------------------------------
*/
static int
Slot_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
int skip = Tcl_ObjectContextSkippedArgs(context), code;
Tcl_Obj *list;
/* Resolve all values */
if (skip == objc) {
list = Tcl_NewObj();
} else {
list = ResolveAll(interp, oPtr, objc - skip, objv + skip);
if (list == NULL) {
return TCL_ERROR;
}
}
Tcl_IncrRefCount(list);
/* Set slot contents */
code = CallSlotSet(interp, oPtr, list);
Tcl_DecrRefCount(list);
return code;
}
/*
* ----------------------------------------------------------------------
*
* Slot_Unimplemented --
*
* Default implementation of the "Get" and "Set" slot accessors. Just
* returns an error; actual slots must override.
*
* ----------------------------------------------------------------------
*/
static int
Slot_Unimplemented(
TCL_UNUSED(void *),
Tcl_Interp *interp,
TCL_UNUSED(Tcl_ObjectContext),
TCL_UNUSED(int),
TCL_UNUSED(Tcl_Obj *const *))
{
Tcl_SetObjResult(interp, Tcl_NewStringObj("unimplemented", -1));
OO_ERROR(interp, ABSTRACT_SLOT);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3097 3098 3099 3100 3101 3102 3103 |
* ----------------------------------------------------------------------
*/
static int
Slot_Unknown(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | | | | < | | | 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 |
* ----------------------------------------------------------------------
*/
static int
Slot_Unknown(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
int skip = Tcl_ObjectContextSkippedArgs(context), code;
if (skip >= objc) {
Tcl_Obj *args[2];
args[0] = oPtr->fPtr->myName;
args[1] = oPtr->fPtr->slotDefOpName;
return TclOOPrivateObjectCmd(oPtr, interp, 2, args);
} else if (TclGetString(objv[skip])[0] != '-') {
Tcl_Obj **args = (Tcl_Obj **) TclStackAlloc(interp,
sizeof(Tcl_Obj *) * (objc - skip + 2));
args[0] = oPtr->fPtr->myName;
args[1] = oPtr->fPtr->slotDefOpName;
memcpy(args+2, objv+skip, sizeof(Tcl_Obj*) * (objc - skip));
code = TclOOPrivateObjectCmd(oPtr, interp, objc - skip + 2, args);
TclStackFree(interp, args);
return code;
}
return TclNRObjectContextInvokeNext(interp, context, objc, objv, skip);
}
/*
|
| ︙ | ︙ | |||
3172 3173 3174 3175 3176 3177 3178 |
*/
static int
ClassFilter_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 |
*/
static int
ClassFilter_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Obj *resultObj, *filterObj;
Tcl_Size i;
if (clsPtr == NULL) {
|
| ︙ | ︙ | |||
3200 3201 3202 3203 3204 3205 3206 |
}
static int
ClassFilter_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 |
}
static int
ClassFilter_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Size filterc;
Tcl_Obj **filterv;
if (clsPtr == NULL) {
|
| ︙ | ︙ | |||
3241 3242 3243 3244 3245 3246 3247 |
*/
static int
ClassMixin_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 |
*/
static int
ClassMixin_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Obj *resultObj;
Class *mixinPtr;
Tcl_Size i;
|
| ︙ | ︙ | |||
3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 |
TclNewObj(resultObj);
FOREACH(mixinPtr, clsPtr->mixins) {
Tcl_ListObjAppendElement(NULL, resultObj,
TclOOObjectName(interp, mixinPtr->thisPtr));
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
static int
ClassMixin_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| > | | 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 |
TclNewObj(resultObj);
FOREACH(mixinPtr, clsPtr->mixins) {
Tcl_ListObjAppendElement(NULL, resultObj,
TclOOObjectName(interp, mixinPtr->thisPtr));
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
static int
ClassMixin_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Size mixinc, i;
Tcl_Obj **mixinv;
Class **mixins; /* The references to the classes to actually
* install. */
|
| ︙ | ︙ | |||
3307 3308 3309 3310 3311 3312 3313 |
for (i = 0; i < mixinc; i++) {
mixins[i] = GetClassInOuterContext(interp, mixinv[i],
"may only mix in classes");
if (mixins[i] == NULL) {
i--;
goto freeAndError;
}
| | | 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 |
for (i = 0; i < mixinc; i++) {
mixins[i] = GetClassInOuterContext(interp, mixinv[i],
"may only mix in classes");
if (mixins[i] == NULL) {
i--;
goto freeAndError;
}
(void) Tcl_CreateHashEntry(&uniqueCheck, (void *) mixins[i], &isNew);
if (!isNew) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"class should only be a direct mixin once",
TCL_AUTO_LENGTH));
OO_ERROR(interp, REPETITIOUS);
goto freeAndError;
}
|
| ︙ | ︙ | |||
3350 3351 3352 3353 3354 3355 3356 |
*/
static int
ClassSuper_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 |
*/
static int
ClassSuper_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Obj *resultObj;
Class *superPtr;
Tcl_Size i;
|
| ︙ | ︙ | |||
3380 3381 3382 3383 3384 3385 3386 |
}
static int
ClassSuper_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | > > | < | | 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 |
}
static int
ClassSuper_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Foundation *fPtr;
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Size superc, j;
Tcl_Size i;
Tcl_Obj **superv;
Class **superclasses;
if (clsPtr == NULL) {
return TCL_ERROR;
} else if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"superclassList");
return TCL_ERROR;
}
objv += Tcl_ObjectContextSkippedArgs(context);
fPtr = clsPtr->thisPtr->fPtr;
if (clsPtr == fPtr->objectCls) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"may not modify the superclass of the root object",
TCL_AUTO_LENGTH));
OO_ERROR(interp, MONKEY_BUSINESS);
return TCL_ERROR;
} else if (TclListObjGetElements(interp, objv[0], &superc,
&superv) != TCL_OK) {
return TCL_ERROR;
}
/*
* Allocate some working space.
*/
superclasses = (Class **) Tcl_Alloc(sizeof(Class *) * (superc ? superc : 1));
/*
* Parse the arguments to get the class to use as superclasses.
*
* Note that zero classes is special, as it is equivalent to just the
* class of objects. [Bug 9d61624b3d]
*/
|
| ︙ | ︙ | |||
3498 3499 3500 3501 3502 3503 3504 |
*/
static int
ClassVars_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 |
*/
static int
ClassVars_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Obj *resultObj;
Tcl_Size i;
if (clsPtr == NULL) {
|
| ︙ | ︙ | |||
3536 3537 3538 3539 3540 3541 3542 |
}
static int
ClassVars_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 |
}
static int
ClassVars_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Size i;
Tcl_Size varc;
Tcl_Obj **varv;
|
| ︙ | ︙ | |||
3558 3559 3560 3561 3562 3563 3564 |
objv += Tcl_ObjectContextSkippedArgs(context);
if (TclListObjGetElements(interp, objv[0], &varc, &varv) != TCL_OK) {
return TCL_ERROR;
}
for (i = 0; i < varc; i++) {
| > | > > > > > > > > > > > > | 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 |
objv += Tcl_ObjectContextSkippedArgs(context);
if (TclListObjGetElements(interp, objv[0], &varc, &varv) != TCL_OK) {
return TCL_ERROR;
}
for (i = 0; i < varc; i++) {
const char *varName = TclGetString(varv[i]);
if (strstr(varName, "::") != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"invalid declared variable name \"%s\": must not %s",
varName, "contain namespace separators"));
OO_ERROR(interp, BAD_DECLVAR);
return TCL_ERROR;
}
if (Tcl_StringMatch(varName, "*(*)")) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"invalid declared variable name \"%s\": must not %s",
varName, "refer to an array element"));
OO_ERROR(interp, BAD_DECLVAR);
return TCL_ERROR;
}
}
if (IsPrivateDefine(interp)) {
InstallPrivateVariableMapping(&clsPtr->privateVariables,
varc, varv, clsPtr->thisPtr->creationEpoch);
|
| ︙ | ︙ | |||
3588 3589 3590 3591 3592 3593 3594 |
*/
static int
ObjFilter_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 |
*/
static int
ObjFilter_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Obj *resultObj, *filterObj;
Tcl_Size i;
if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
| ︙ | ︙ | |||
3616 3617 3618 3619 3620 3621 3622 |
}
static int
ObjFilter_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 |
}
static int
ObjFilter_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Size filterc;
Tcl_Obj **filterv;
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
|
| ︙ | ︙ | |||
3655 3656 3657 3658 3659 3660 3661 |
*/
static int
ObjMixin_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 |
*/
static int
ObjMixin_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Obj *resultObj;
Class *mixinPtr;
Tcl_Size i;
|
| ︙ | ︙ | |||
3687 3688 3689 3690 3691 3692 3693 |
}
static int
ObjMixin_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 |
}
static int
ObjMixin_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Size mixinc, i;
Tcl_Obj **mixinv;
Class **mixins; /* The references to the classes to actually
* install. */
|
| ︙ | ︙ | |||
3721 3722 3723 3724 3725 3726 3727 |
for (i = 0; i < mixinc; i++) {
mixins[i] = GetClassInOuterContext(interp, mixinv[i],
"may only mix in classes");
if (mixins[i] == NULL) {
goto freeAndError;
}
| | | 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 |
for (i = 0; i < mixinc; i++) {
mixins[i] = GetClassInOuterContext(interp, mixinv[i],
"may only mix in classes");
if (mixins[i] == NULL) {
goto freeAndError;
}
(void) Tcl_CreateHashEntry(&uniqueCheck, (void *) mixins[i], &isNew);
if (!isNew) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"class should only be a direct mixin once",
TCL_AUTO_LENGTH));
OO_ERROR(interp, REPETITIOUS);
goto freeAndError;
}
|
| ︙ | ︙ | |||
3758 3759 3760 3761 3762 3763 3764 |
*/
static int
ObjVars_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 |
*/
static int
ObjVars_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Obj *resultObj;
Tcl_Size i;
if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
| ︙ | ︙ | |||
3796 3797 3798 3799 3800 3801 3802 |
}
static int
ObjVars_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | > | > > > > > > > > > > > > | 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 |
}
static int
ObjVars_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Size varc, i;
Tcl_Obj **varv;
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv,
"variableList");
return TCL_ERROR;
} else if (oPtr == NULL) {
return TCL_ERROR;
}
objv += Tcl_ObjectContextSkippedArgs(context);
if (TclListObjGetElements(interp, objv[0], &varc, &varv) != TCL_OK) {
return TCL_ERROR;
}
for (i = 0; i < varc; i++) {
const char *varName = TclGetString(varv[i]);
if (strstr(varName, "::") != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"invalid declared variable name \"%s\": must not %s",
varName, "contain namespace separators"));
OO_ERROR(interp, BAD_DECLVAR);
return TCL_ERROR;
}
if (Tcl_StringMatch(varName, "*(*)")) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"invalid declared variable name \"%s\": must not %s",
varName, "refer to an array element"));
OO_ERROR(interp, BAD_DECLVAR);
return TCL_ERROR;
}
}
if (IsPrivateDefine(interp)) {
InstallPrivateVariableMapping(&oPtr->privateVariables, varc, varv,
oPtr->creationEpoch);
|
| ︙ | ︙ | |||
3847 3848 3849 3850 3851 3852 3853 |
*/
static int
Slot_ResolveClass(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | | 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 |
*/
static int
Slot_ResolveClass(
TCL_UNUSED(void *),
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.
*/
|
| ︙ | ︙ | |||
3900 3901 3902 3903 3904 3905 3906 |
*/
static int
Configurable_ClassReadableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 |
*/
static int
Configurable_ClassReadableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
if (clsPtr == NULL) {
return TCL_ERROR;
} else if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
| ︙ | ︙ | |||
3922 3923 3924 3925 3926 3927 3928 |
}
static int
Configurable_ClassReadableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 |
}
static int
Configurable_ClassReadableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Size varc;
Tcl_Obj **varv;
if (clsPtr == NULL) {
|
| ︙ | ︙ | |||
3952 3953 3954 3955 3956 3957 3958 |
}
static int
Configurable_ObjectReadableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 |
}
static int
Configurable_ObjectReadableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
} else if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
| ︙ | ︙ | |||
3974 3975 3976 3977 3978 3979 3980 |
}
static int
Configurable_ObjectReadableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 |
}
static int
Configurable_ObjectReadableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Size varc;
Tcl_Obj **varv;
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
|
| ︙ | ︙ | |||
4016 4017 4018 4019 4020 4021 4022 |
*/
static int
Configurable_ClassWritableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 |
*/
static int
Configurable_ClassWritableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
if (clsPtr == NULL) {
return TCL_ERROR;
} else if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
| ︙ | ︙ | |||
4038 4039 4040 4041 4042 4043 4044 |
}
static int
Configurable_ClassWritableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 |
}
static int
Configurable_ClassWritableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Class *clsPtr = TclOOGetClassDefineCmdContext(interp);
Tcl_Size varc;
Tcl_Obj **varv;
if (clsPtr == NULL) {
|
| ︙ | ︙ | |||
4068 4069 4070 4071 4072 4073 4074 |
}
static int
Configurable_ObjectWritableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 |
}
static int
Configurable_ObjectWritableProps_Get(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
if (oPtr == NULL) {
return TCL_ERROR;
} else if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
| ︙ | ︙ | |||
4090 4091 4092 4093 4094 4095 4096 |
}
static int
Configurable_ObjectWritableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
| | | 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 |
}
static int
Configurable_ObjectWritableProps_Set(
TCL_UNUSED(void *),
Tcl_Interp *interp,
Tcl_ObjectContext context,
int objc,
Tcl_Obj *const *objv)
{
Object *oPtr = (Object *) TclOOGetDefineCmdContext(interp);
Tcl_Size varc;
Tcl_Obj **varv;
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
|
| ︙ | ︙ | |||
4131 4132 4133 4134 4135 4136 4137 | * * Helper for the helpers. Scans a property list and does the filtering * or adding of the property to add or remove * * ---------------------------------------------------------------------- */ | | | | < | | | | | | 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 |
*
* Helper for the helpers. Scans a property list and does the filtering
* or adding of the property to add or remove
*
* ----------------------------------------------------------------------
*/
static int
BuildPropertyList(
PropertyList *propsList, /* Property list to scan. */
Tcl_Obj *propName, /* Property to add/remove. */
int addingProp, /* True if we're adding, false if removing. */
Tcl_Obj *listObj) /* The list of property names we're building */
{
int present = 0, changed = 0, i;
Tcl_Obj *other;
Tcl_SetListObj(listObj, 0, NULL);
FOREACH(other, *propsList) {
if (!TclStringCmp(propName, other, 1, 0, TCL_INDEX_NONE)) {
present = 1;
if (!addingProp) {
changed = 1;
continue;
}
}
Tcl_ListObjAppendElement(NULL, listObj, other);
}
if (!present && addingProp) {
Tcl_ListObjAppendElement(NULL, listObj, propName);
changed = 1;
}
return changed;
}
void
TclOORegisterInstanceProperty(
Object *oPtr, /* Object that owns the property slots. */
Tcl_Obj *propName, /* Property to add/remove. Must include the
* hyphen if one is desired; this is the value
* that is actually placed in the slot. */
int registerReader, /* True if we're adding the property name to
* the readable property slot. False if we're
* removing the property name from the slot. */
int registerWriter) /* True if we're adding the property name to
* the writable property slot. False if we're
* removing the property name from the slot. */
{
Tcl_Obj *listObj = Tcl_NewObj(); /* Working buffer. */
Tcl_Obj **objv;
Tcl_Size count;
|
| ︙ | ︙ | |||
4197 4198 4199 4200 4201 4202 4203 |
void
TclOORegisterProperty(
Class *clsPtr, /* Class that owns the property slots. */
Tcl_Obj *propName, /* Property to add/remove. Must include the
* hyphen if one is desired; this is the value
* that is actually placed in the slot. */
| | | | | | | 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 |
void
TclOORegisterProperty(
Class *clsPtr, /* Class that owns the property slots. */
Tcl_Obj *propName, /* Property to add/remove. Must include the
* hyphen if one is desired; this is the value
* that is actually placed in the slot. */
int registerReader, /* True if we're adding the property name to
* the readable property slot. False if we're
* removing the property name from the slot. */
int registerWriter) /* True if we're adding the property name to
* the writable property slot. False if we're
* removing the property name from the slot. */
{
Tcl_Obj *listObj = Tcl_NewObj(); /* Working buffer. */
Tcl_Obj **objv;
Tcl_Size count;
int changed = 0;
if (BuildPropertyList(&clsPtr->properties.readable, propName,
registerReader, listObj)) {
TclListObjGetElements(NULL, listObj, &count, &objv);
TclOOInstallReadableProperties(&clsPtr->properties, count, objv);
changed = 1;
}
if (BuildPropertyList(&clsPtr->properties.writable, propName,
registerWriter, listObj)) {
TclListObjGetElements(NULL, listObj, &count, &objv);
TclOOInstallWritableProperties(&clsPtr->properties, count, objv);
changed = 1;
}
Tcl_BounceRefCount(listObj);
if (changed) {
BumpGlobalEpoch(clsPtr->thisPtr->fPtr->interp, clsPtr);
}
}
|
| ︙ | ︙ |
Changes to generic/tclOOInfo.c.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "tclInt.h" #include "tclOOInt.h" | | | | | < | | | | | | | | | | | | | | | | > | | | | | | > | | > | > | | | < | < < | | < < < < < | < < < < < < < < < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tclInt.h"
#include "tclOOInt.h"
static Tcl_ObjCmdProc InfoObjectCallCmd;
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;
static Tcl_ObjCmdProc InfoObjectMixinsCmd;
static Tcl_ObjCmdProc InfoObjectNsCmd;
static Tcl_ObjCmdProc InfoObjectVarsCmd;
static Tcl_ObjCmdProc InfoObjectVariablesCmd;
static Tcl_ObjCmdProc InfoClassCallCmd;
static Tcl_ObjCmdProc InfoClassConstrCmd;
static Tcl_ObjCmdProc InfoClassDefnCmd;
static Tcl_ObjCmdProc InfoClassDefnNsCmd;
static Tcl_ObjCmdProc InfoClassDestrCmd;
static Tcl_ObjCmdProc InfoClassFiltersCmd;
static Tcl_ObjCmdProc InfoClassForwardCmd;
static Tcl_ObjCmdProc InfoClassInstancesCmd;
static Tcl_ObjCmdProc InfoClassMethodsCmd;
static Tcl_ObjCmdProc InfoClassMethodTypeCmd;
static Tcl_ObjCmdProc InfoClassMixinsCmd;
static Tcl_ObjCmdProc InfoClassSubsCmd;
static Tcl_ObjCmdProc InfoClassSupersCmd;
static Tcl_ObjCmdProc InfoClassVariablesCmd;
/*
* List of commands that are used to implement the [info object] subcommands.
*/
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},
{"isa", InfoObjectIsACmd, TclCompileInfoObjectIsACmd, NULL, NULL, 0},
{"methods", InfoObjectMethodsCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0},
{"methodtype", InfoObjectMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"mixins", InfoObjectMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"namespace", InfoObjectNsCmd, TclCompileInfoObjectNamespaceCmd, NULL, NULL, 0},
{"properties", TclOOInfoObjectPropCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0},
{"variables", InfoObjectVariablesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"vars", InfoObjectVarsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
/*
* List of commands that are used to implement the [info class] subcommands.
*/
static const EnsembleImplMap infoClassCmds[] = {
{"call", InfoClassCallCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"constructor", InfoClassConstrCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"definition", InfoClassDefnCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"definitionnamespace", InfoClassDefnNsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"destructor", InfoClassDestrCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"filters", InfoClassFiltersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"forward", InfoClassForwardCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"instances", InfoClassInstancesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"methods", InfoClassMethodsCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0},
{"methodtype", InfoClassMethodTypeCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"mixins", InfoClassMixinsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"properties", TclOOInfoClassPropCmd, TclCompileBasicMin1ArgCmd, NULL, NULL, 0},
{"subclasses", InfoClassSubsCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"superclasses", InfoClassSupersCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"variables", InfoClassVariablesCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
/*
* ----------------------------------------------------------------------
*
* LocalVarName --
*
* Get the name of a local variable (especially a method argument) as a
* Tcl value.
*
* ----------------------------------------------------------------------
*/
static inline Tcl_Obj *
LocalVarName(
CompiledLocal *localPtr)
{
return Tcl_NewStringObj(localPtr->name, TCL_AUTO_LENGTH);
}
/*
* ----------------------------------------------------------------------
*
* TclOOInitInfo --
*
|
| ︙ | ︙ | |||
139 140 141 142 143 144 145 |
Tcl_Command infoCmd;
Tcl_Obj *mapDict;
/*
* Build the ensembles used to implement [info object] and [info class].
*/
| | | < < < | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
Tcl_Command infoCmd;
Tcl_Obj *mapDict;
/*
* Build the ensembles used to implement [info object] and [info class].
*/
TclMakeEnsemble(interp, "::oo::InfoObject", infoObjectCmds);
TclMakeEnsemble(interp, "::oo::InfoClass", infoClassCmds);
/*
* Install into the [info] ensemble.
*/
infoCmd = Tcl_FindCommand(interp, "info", NULL, TCL_GLOBAL_ONLY);
if (infoCmd) {
Tcl_GetEnsembleMappingDict(NULL, infoCmd, &mapDict);
TclDictPutString(NULL, mapDict, "object", "::oo::InfoObject");
TclDictPutString(NULL, mapDict, "class", "::oo::InfoClass");
|
| ︙ | ︙ | |||
192 193 194 195 196 197 198 |
}
return oPtr->classPtr;
}
/*
* ----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
}
return oPtr->classPtr;
}
/*
* ----------------------------------------------------------------------
*
* InfoObjectClassCmd --
*
* Implements [info object class $objName ?$className?]
*
* ----------------------------------------------------------------------
*/
static int
InfoObjectClassCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
if (objc != 2 && objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "objName ?className?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
394 395 396 397 398 399 400 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectDefnCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | > > > > | | | | < > | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectDefnCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
Tcl_HashEntry *hPtr;
Proc *procPtr;
CompiledLocal *localPtr;
Tcl_Obj *resultObjs[2];
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "objName methodName");
return TCL_ERROR;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!oPtr->methodsPtr) {
goto unknownMethod;
}
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, objv[2]);
if (hPtr == NULL) {
goto unknownMethod;
}
procPtr = TclOOGetProcFromMethod((Method *) Tcl_GetHashValue(hPtr));
if (procPtr == NULL) {
goto wrongType;
}
/*
* We now have the method to describe the definition of.
*/
TclNewObj(resultObjs[0]);
for (localPtr=procPtr->firstLocalPtr; localPtr!=NULL;
localPtr=localPtr->nextPtr) {
if (TclIsVarArgument(localPtr)) {
Tcl_Obj *argObj;
TclNewObj(argObj);
Tcl_ListObjAppendElement(NULL, argObj, LocalVarName(localPtr));
if (localPtr->defValuePtr != NULL) {
Tcl_ListObjAppendElement(NULL, argObj, localPtr->defValuePtr);
}
Tcl_ListObjAppendElement(NULL, resultObjs[0], argObj);
}
}
resultObjs[1] = TclOOGetMethodBody((Method *) Tcl_GetHashValue(hPtr));
Tcl_SetObjResult(interp, Tcl_NewListObj(2, resultObjs));
return TCL_OK;
/*
* Errors...
*/
unknownMethod:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unknown method \"%s\"", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
wrongType:
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"definition not available for this kind of method",
TCL_AUTO_LENGTH));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
/*
* ----------------------------------------------------------------------
*
* InfoObjectFiltersCmd --
*
* Implements [info object filters $objName]
*
* ----------------------------------------------------------------------
*/
static int
InfoObjectFiltersCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Size i;
Tcl_Obj *filterObj, *resultObj;
Object *oPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "objName");
|
| ︙ | ︙ | |||
484 485 486 487 488 489 490 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectForwardCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | > > > > | | | < > > > > > > > > > > > > > > > > > > > > | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectForwardCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
Tcl_HashEntry *hPtr;
Tcl_Obj *prefixObj;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "objName methodName");
return TCL_ERROR;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!oPtr->methodsPtr) {
goto unknownMethod;
}
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, objv[2]);
if (hPtr == NULL) {
goto unknownMethod;
}
prefixObj = TclOOGetFwdFromMethod((Method *) Tcl_GetHashValue(hPtr));
if (prefixObj == NULL) {
goto wrongType;
}
/*
* Describe the valid forward method.
*/
Tcl_SetObjResult(interp, prefixObj);
return TCL_OK;
/*
* Errors...
*/
unknownMethod:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unknown method \"%s\"", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
wrongType:
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"prefix argument list not available for this kind of method",
TCL_AUTO_LENGTH));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
/*
* ----------------------------------------------------------------------
*
* InfoObjectIsACmd --
*
* Implements [info object isa $category $objName ...]
*
* ----------------------------------------------------------------------
*/
static int
InfoObjectIsACmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const categories[] = {
"class", "metaclass", "mixin", "object", "typeof", NULL
};
enum IsACats {
IsClass, IsMetaclass, IsMixin, IsObject, IsType
} idx;
|
| ︙ | ︙ | |||
655 656 657 658 659 660 661 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectMethodsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | < > > | | | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectMethodsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const options[] = {
"-all", "-localprivate", "-private", "-scope", NULL
};
enum Options {
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE, OPT_SCOPE
} idx;
static const char *const scopes[] = {
"private", "public", "unexported"
};
enum Scopes {
SCOPE_PRIVATE, SCOPE_PUBLIC, SCOPE_UNEXPORTED,
SCOPE_LOCALPRIVATE,
SCOPE_DEFAULT = -1
};
Object *oPtr;
int flag = PUBLIC_METHOD, recurse = 0, scope = SCOPE_DEFAULT;
FOREACH_HASH_DECLS;
Tcl_Obj *namePtr, *resultObj;
Method *mPtr;
/*
* Parse arguments.
*/
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "objName ?-option value ...?");
return TCL_ERROR;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (objc != 2) {
int i;
for (i=2 ; i<objc ; i++) {
if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0,
&idx) != TCL_OK) {
return TCL_ERROR;
}
switch (idx) {
case OPT_ALL:
recurse = 1;
break;
case OPT_LOCALPRIVATE:
flag = PRIVATE_METHOD;
break;
case OPT_PRIVATE:
flag = 0;
break;
|
| ︙ | ︙ | |||
726 727 728 729 730 731 732 |
break;
default:
TCL_UNREACHABLE();
}
}
}
if (scope != SCOPE_DEFAULT) {
| | | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 |
break;
default:
TCL_UNREACHABLE();
}
}
}
if (scope != SCOPE_DEFAULT) {
recurse = 0;
switch (scope) {
case SCOPE_PRIVATE:
flag = TRUE_PRIVATE_METHOD;
break;
case SCOPE_PUBLIC:
flag = PUBLIC_METHOD;
break;
|
| ︙ | ︙ | |||
749 750 751 752 753 754 755 |
/*
* List matching methods.
*/
TclNewObj(resultObj);
if (recurse) {
| | | > > | > > | | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 |
/*
* List matching methods.
*/
TclNewObj(resultObj);
if (recurse) {
const char **names;
int i, numNames = TclOOGetSortedMethodList(oPtr, NULL, NULL, flag,
&names);
for (i=0 ; i<numNames ; i++) {
Tcl_ListObjAppendElement(NULL, resultObj,
Tcl_NewStringObj(names[i], TCL_AUTO_LENGTH));
}
if (numNames > 0) {
Tcl_Free((void *)names);
}
} else if (oPtr->methodsPtr) {
if (scope == SCOPE_DEFAULT) {
/*
* Handle legacy-mode matching. [Bug 36e5517a6850]
*/
int scopeFilter = flag | TRUE_PRIVATE_METHOD;
FOREACH_HASH(namePtr, mPtr, oPtr->methodsPtr) {
if (mPtr->typePtr && (mPtr->flags & scopeFilter) == flag) {
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
}
}
} else {
FOREACH_HASH(namePtr, mPtr, oPtr->methodsPtr) {
if (mPtr->typePtr && (mPtr->flags & SCOPE_FLAGS) == flag) {
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
}
}
}
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
|
| ︙ | ︙ | |||
794 795 796 797 798 799 800 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectMethodTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > | > > > > | > > > > > > > > | > | > > > > > > > | | | 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectMethodTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
Tcl_HashEntry *hPtr;
Method *mPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "objName methodName");
return TCL_ERROR;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
if (oPtr == NULL) {
return TCL_ERROR;
}
if (!oPtr->methodsPtr) {
goto unknownMethod;
}
hPtr = Tcl_FindHashEntry(oPtr->methodsPtr, objv[2]);
if (hPtr == NULL) {
goto unknownMethod;
}
mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (mPtr->typePtr == NULL) {
/*
* Special entry for visibility control: pretend the method doesnt
* exist.
*/
goto unknownMethod;
}
Tcl_SetObjResult(interp,
Tcl_NewStringObj(mPtr->typePtr->name, TCL_AUTO_LENGTH));
return TCL_OK;
unknownMethod:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unknown method \"%s\"", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
/*
* ----------------------------------------------------------------------
*
* InfoObjectMixinsCmd --
*
* Implements [info object mixins $objName]
*
* ----------------------------------------------------------------------
*/
static int
InfoObjectMixinsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Class *mixinPtr;
Object *oPtr;
Tcl_Obj *resultObj;
Tcl_Size i;
if (objc != 2) {
|
| ︙ | ︙ | |||
876 877 878 879 880 881 882 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectIdCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectIdCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "objName");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
908 909 910 911 912 913 914 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectNsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectNsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "objName");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
940 941 942 943 944 945 946 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectVariablesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectVariablesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
Tcl_Obj *resultObj;
Tcl_Size i;
int isPrivate = 0;
if (objc != 2 && objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "objName ?-private?");
return TCL_ERROR;
}
if (objc == 3) {
if (strcmp("-private", TclGetString(objv[2])) != 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"option \"%s\" is not exactly \"-private\"",
TclGetString(objv[2])));
OO_ERROR(interp, BAD_ARG);
return TCL_ERROR;
}
isPrivate = 1;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
if (oPtr == NULL) {
return TCL_ERROR;
}
TclNewObj(resultObj);
|
| ︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectVarsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectVarsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
const char *pattern = NULL;
FOREACH_HASH_DECLS;
VarInHash *vihPtr;
Tcl_Obj *nameObj, *resultObj;
|
| ︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 |
* ----------------------------------------------------------------------
*/
static int
InfoClassConstrCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > | > > > > | > > > > > > > > > > > > > | | | > | | > > > > | > > > > > | > > > > > > > > > > > > > | | | | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 |
* ----------------------------------------------------------------------
*/
static int
InfoClassConstrCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Proc *procPtr;
CompiledLocal *localPtr;
Tcl_Obj *resultObjs[2];
Class *clsPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className");
return TCL_ERROR;
}
clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
if (clsPtr->constructorPtr == NULL) {
return TCL_OK;
}
procPtr = TclOOGetProcFromMethod(clsPtr->constructorPtr);
if (procPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"definition not available for this kind of method",
TCL_AUTO_LENGTH));
OO_ERROR(interp, METHOD_TYPE);
return TCL_ERROR;
}
TclNewObj(resultObjs[0]);
for (localPtr=procPtr->firstLocalPtr; localPtr!=NULL;
localPtr=localPtr->nextPtr) {
if (TclIsVarArgument(localPtr)) {
Tcl_Obj *argObj;
TclNewObj(argObj);
Tcl_ListObjAppendElement(NULL, argObj, LocalVarName(localPtr));
if (localPtr->defValuePtr != NULL) {
Tcl_ListObjAppendElement(NULL, argObj, localPtr->defValuePtr);
}
Tcl_ListObjAppendElement(NULL, resultObjs[0], argObj);
}
}
resultObjs[1] = TclOOGetMethodBody(clsPtr->constructorPtr);
Tcl_SetObjResult(interp, Tcl_NewListObj(2, resultObjs));
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* InfoClassDefnCmd --
*
* Implements [info class definition $clsName $methodName]
*
* ----------------------------------------------------------------------
*/
static int
InfoClassDefnCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_HashEntry *hPtr;
Proc *procPtr;
CompiledLocal *localPtr;
Tcl_Obj *resultObjs[2];
Class *clsPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "className methodName");
return TCL_ERROR;
}
clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
hPtr = Tcl_FindHashEntry(&clsPtr->classMethods, objv[2]);
if (hPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unknown method \"%s\"", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
procPtr = TclOOGetProcFromMethod((Method *) Tcl_GetHashValue(hPtr));
if (procPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"definition not available for this kind of method",
TCL_AUTO_LENGTH));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
TclNewObj(resultObjs[0]);
for (localPtr=procPtr->firstLocalPtr; localPtr!=NULL;
localPtr=localPtr->nextPtr) {
if (TclIsVarArgument(localPtr)) {
Tcl_Obj *argObj;
TclNewObj(argObj);
Tcl_ListObjAppendElement(NULL, argObj, LocalVarName(localPtr));
if (localPtr->defValuePtr != NULL) {
Tcl_ListObjAppendElement(NULL, argObj, localPtr->defValuePtr);
}
Tcl_ListObjAppendElement(NULL, resultObjs[0], argObj);
}
}
resultObjs[1] = TclOOGetMethodBody((Method *) Tcl_GetHashValue(hPtr));
Tcl_SetObjResult(interp, Tcl_NewListObj(2, resultObjs));
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* InfoClassDefnNsCmd --
*
* Implements [info class definitionnamespace $clsName ?$kind?]
*
* ----------------------------------------------------------------------
*/
static int
InfoClassDefnNsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const kindList[] = {
"-class",
"-instance",
NULL
};
int kind = 0;
|
| ︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 |
* ----------------------------------------------------------------------
*/
static int
InfoClassDestrCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | > > > > | 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 |
* ----------------------------------------------------------------------
*/
static int
InfoClassDestrCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Proc *procPtr;
Class *clsPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className");
return TCL_ERROR;
}
clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
if (clsPtr->destructorPtr == NULL) {
return TCL_OK;
}
procPtr = TclOOGetProcFromMethod(clsPtr->destructorPtr);
if (procPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"definition not available for this kind of method",
TCL_AUTO_LENGTH));
OO_ERROR(interp, METHOD_TYPE);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, TclOOGetMethodBody(clsPtr->destructorPtr));
return TCL_OK;
}
|
| ︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 |
* ----------------------------------------------------------------------
*/
static int
InfoClassFiltersCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 |
* ----------------------------------------------------------------------
*/
static int
InfoClassFiltersCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Size i;
Tcl_Obj *filterObj, *resultObj;
Class *clsPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className");
|
| ︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 |
* ----------------------------------------------------------------------
*/
static int
InfoClassForwardCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | > > > > | > > > > > | 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 |
* ----------------------------------------------------------------------
*/
static int
InfoClassForwardCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_HashEntry *hPtr;
Tcl_Obj *prefixObj;
Class *clsPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "className methodName");
return TCL_ERROR;
}
clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
hPtr = Tcl_FindHashEntry(&clsPtr->classMethods, objv[2]);
if (hPtr == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unknown method \"%s\"", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
prefixObj = TclOOGetFwdFromMethod((Method *) Tcl_GetHashValue(hPtr));
if (prefixObj == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"prefix argument list not available for this kind of method",
TCL_AUTO_LENGTH));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, prefixObj);
return TCL_OK;
}
|
| ︙ | ︙ | |||
1319 1320 1321 1322 1323 1324 1325 |
* ----------------------------------------------------------------------
*/
static int
InfoClassInstancesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 |
* ----------------------------------------------------------------------
*/
static int
InfoClassInstancesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
Class *clsPtr;
Tcl_Size i;
const char *pattern = NULL;
Tcl_Obj *resultObj;
|
| ︙ | ︙ | |||
1367 1368 1369 1370 1371 1372 1373 |
* ----------------------------------------------------------------------
*/
static int
InfoClassMethodsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | < > > | | | 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 |
* ----------------------------------------------------------------------
*/
static int
InfoClassMethodsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const options[] = {
"-all", "-localprivate", "-private", "-scope", NULL
};
enum Options {
OPT_ALL, OPT_LOCALPRIVATE, OPT_PRIVATE, OPT_SCOPE
} idx;
static const char *const scopes[] = {
"private", "public", "unexported"
};
enum Scopes {
SCOPE_PRIVATE, SCOPE_PUBLIC, SCOPE_UNEXPORTED,
SCOPE_DEFAULT = -1
};
int flag = PUBLIC_METHOD, recurse = 0, scope = SCOPE_DEFAULT;
Tcl_Obj *namePtr, *resultObj;
Method *mPtr;
Class *clsPtr;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className ?-option value ...?");
return TCL_ERROR;
}
clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
if (objc != 2) {
int i;
for (i=2 ; i<objc ; i++) {
if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0,
&idx) != TCL_OK) {
return TCL_ERROR;
}
switch (idx) {
case OPT_ALL:
recurse = 1;
break;
case OPT_LOCALPRIVATE:
flag = PRIVATE_METHOD;
break;
case OPT_PRIVATE:
flag = 0;
break;
|
| ︙ | ︙ | |||
1432 1433 1434 1435 1436 1437 1438 |
break;
default:
TCL_UNREACHABLE();
}
}
}
if (scope != SCOPE_DEFAULT) {
| | | | > | > > | | | 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 |
break;
default:
TCL_UNREACHABLE();
}
}
}
if (scope != SCOPE_DEFAULT) {
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;
default:
TCL_UNREACHABLE();
}
}
TclNewObj(resultObj);
if (recurse) {
const char **names;
Tcl_Size i, numNames = TclOOGetSortedClassMethodList(clsPtr, flag, &names);
for (i=0 ; i<numNames ; i++) {
Tcl_ListObjAppendElement(NULL, resultObj,
Tcl_NewStringObj(names[i], TCL_AUTO_LENGTH));
}
if (numNames > 0) {
Tcl_Free((void *)names);
}
} else {
FOREACH_HASH_DECLS;
if (scope == SCOPE_DEFAULT) {
/*
* Handle legacy-mode matching. [Bug 36e5517a6850]
*/
int scopeFilter = flag | TRUE_PRIVATE_METHOD;
FOREACH_HASH(namePtr, mPtr, &clsPtr->classMethods) {
if (mPtr->typePtr && (mPtr->flags & scopeFilter) == flag) {
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
}
}
} else {
FOREACH_HASH(namePtr, mPtr, &clsPtr->classMethods) {
if (mPtr->typePtr && (mPtr->flags & SCOPE_FLAGS) == flag) {
Tcl_ListObjAppendElement(NULL, resultObj, namePtr);
}
}
}
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
|
| ︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 |
* ----------------------------------------------------------------------
*/
static int
InfoClassMethodTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | > | | > > > > > > > > | > | > > > > > > > | | | 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 |
* ----------------------------------------------------------------------
*/
static int
InfoClassMethodTypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_HashEntry *hPtr;
Method *mPtr;
Class *clsPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "className methodName");
return TCL_ERROR;
}
clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
hPtr = Tcl_FindHashEntry(&clsPtr->classMethods, objv[2]);
if (hPtr == NULL) {
goto unknownMethod;
}
mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (mPtr->typePtr == NULL) {
/*
* Special entry for visibility control: pretend the method doesnt
* exist.
*/
goto unknownMethod;
}
Tcl_SetObjResult(interp,
Tcl_NewStringObj(mPtr->typePtr->name, TCL_AUTO_LENGTH));
return TCL_OK;
unknownMethod:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unknown method \"%s\"", TclGetString(objv[2])));
Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "METHOD",
TclGetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
/*
* ----------------------------------------------------------------------
*
* InfoClassMixinsCmd --
*
* Implements [info class mixins $clsName]
*
* ----------------------------------------------------------------------
*/
static int
InfoClassMixinsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Class *clsPtr, *mixinPtr;
Tcl_Obj *resultObj;
Tcl_Size i;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className");
|
| ︙ | ︙ | |||
1577 1578 1579 1580 1581 1582 1583 |
* ----------------------------------------------------------------------
*/
static int
InfoClassSubsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 |
* ----------------------------------------------------------------------
*/
static int
InfoClassSubsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Class *clsPtr, *subclassPtr;
Tcl_Obj *resultObj;
Tcl_Size i;
const char *pattern = NULL;
if (objc != 2 && objc != 3) {
|
| ︙ | ︙ | |||
1632 1633 1634 1635 1636 1637 1638 |
* ----------------------------------------------------------------------
*/
static int
InfoClassSupersCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 |
* ----------------------------------------------------------------------
*/
static int
InfoClassSupersCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Class *clsPtr, *superPtr;
Tcl_Obj *resultObj;
Tcl_Size i;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className");
|
| ︙ | ︙ | |||
1671 1672 1673 1674 1675 1676 1677 |
* ----------------------------------------------------------------------
*/
static int
InfoClassVariablesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | | 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 |
* ----------------------------------------------------------------------
*/
static int
InfoClassVariablesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Class *clsPtr;
Tcl_Obj *resultObj;
Tcl_Size i;
int isPrivate = 0;
if (objc != 2 && objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "className ?-private?");
return TCL_ERROR;
}
if (objc == 3) {
if (strcmp("-private", TclGetString(objv[2])) != 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"option \"%s\" is not exactly \"-private\"",
TclGetString(objv[2])));
OO_ERROR(interp, BAD_ARG);
return TCL_ERROR;
}
isPrivate = 1;
}
clsPtr = TclOOGetClassFromObj(interp, objv[1]);
if (clsPtr == NULL) {
return TCL_ERROR;
}
TclNewObj(resultObj);
|
| ︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectCallCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 |
* ----------------------------------------------------------------------
*/
static int
InfoObjectCallCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
CallContext *contextPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "objName methodName");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1777 1778 1779 1780 1781 1782 1783 |
* ----------------------------------------------------------------------
*/
static int
InfoClassCallCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 |
* ----------------------------------------------------------------------
*/
static int
InfoClassCallCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Class *clsPtr;
CallChain *callPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "className methodName");
return TCL_ERROR;
|
| ︙ | ︙ |
Changes to generic/tclOOInt.h.
1 2 3 4 5 6 | /* * tclOOInt.h -- * * This file contains the structure definitions and some of the function * declarations for the object-system (NB: not Tcl_Obj, but ::oo). * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * tclOOInt.h -- * * This file contains the structure definitions and some of the function * declarations for the object-system (NB: not Tcl_Obj, but ::oo). * * Copyright (c) 2006-2012 by Donal K. Fellows * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef TCL_OO_INTERNAL_H #define TCL_OO_INTERNAL_H 1 |
| ︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
typedef struct Method Method;
typedef struct MInvoke MInvoke;
typedef struct Object Object;
typedef struct PrivateVariableMapping PrivateVariableMapping;
typedef struct ProcedureMethod ProcedureMethod;
typedef struct PropertyStorage PropertyStorage;
/*
* The data that needs to be stored per method. This record is used to collect
* information about all sorts of methods, including forwards, constructors
* and destructors.
*/
struct Method {
union {
| > > > > > < | > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
typedef struct Method Method;
typedef struct MInvoke MInvoke;
typedef struct Object Object;
typedef struct PrivateVariableMapping PrivateVariableMapping;
typedef struct ProcedureMethod ProcedureMethod;
typedef struct PropertyStorage PropertyStorage;
#if (TCL_MAJOR_VERSION < 9) && !defined(Tcl_Size)
# define Tcl_Size int
# define _TCLSIZEHANDLED
# endif
/*
* The data that needs to be stored per method. This record is used to collect
* information about all sorts of methods, including forwards, constructors
* and destructors.
*/
struct Method {
union {
const Tcl_MethodType *typePtr;
#if TCL_MAJOR_VERSION > 8
const Tcl_MethodType2 *type2Ptr;
#endif
}; /* The type of method. If NULL, this is a
* special flag record which is just used for
* the setting of the flags field. Note that
* this is a union of two pointer types that
* have the same layout at least as far as the
* internal version field. */
Tcl_Size refCount;
|
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
* exposed by this object or class (in its
* stereotypical instancs). Contains a sorted
* unique list if not NULL. */
Tcl_Obj *allWritableCache; /* The cache of all writable properties
* exposed by this object or class (in its
* stereotypical instances). Contains a sorted
* unique list if not NULL. */
| | | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
* exposed by this object or class (in its
* stereotypical instancs). Contains a sorted
* unique list if not NULL. */
Tcl_Obj *allWritableCache; /* The cache of all writable properties
* exposed by this object or class (in its
* stereotypical instances). Contains a sorted
* unique list if not NULL. */
int epoch; /* The epoch that the caches are valid for. */
};
/*
* Now, the definition of what an object actually is.
*/
struct Object {
|
| ︙ | ︙ | |||
258 259 260 261 262 263 264 |
* properties that this object *claims* to
* support. */
Tcl_Obj *linkedCmdsList; /* List of names of linked commands. */
};
enum ObjectFlags {
OBJECT_DESTRUCTING = 1, /* Indicates that an object is being or has
| | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
* properties that this object *claims* to
* support. */
Tcl_Obj *linkedCmdsList; /* List of names of linked commands. */
};
enum ObjectFlags {
OBJECT_DESTRUCTING = 1, /* Indicates that an object is being or has
* been destroyed */
DESTRUCTOR_CALLED = 2, /* Indicates that evaluation of destructor
* script for the object has began */
ROOT_OBJECT = 0x1000, /* Flag to say that this object is the root of
* the class hierarchy and should be treated
* specially during teardown. */
FILTER_HANDLING = 0x2000, /* Flag set when the object is processing a
* filter; when set, filters are *not*
|
| ︙ | ︙ | |||
314 315 316 317 318 319 320 |
ClassList mixins; /* List of mixin classes, used for generation
* of method call chains. */
VarClassList mixinSubs; /* List of classes that this class is mixed
* into, used to ensure deletion of dependent
* entities happens properly when the class
* itself is deleted. */
Tcl_HashTable classMethods; /* Hash table of all methods. Hash maps from
| | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
ClassList mixins; /* List of mixin classes, used for generation
* of method call chains. */
VarClassList mixinSubs; /* List of classes that this class is mixed
* into, used to ensure deletion of dependent
* entities happens properly when the class
* itself is deleted. */
Tcl_HashTable classMethods; /* Hash table of all methods. Hash maps from
* the (Tcl_Obj*) method name to the (Method*)
* method record. */
Method *constructorPtr; /* Method record of the class constructor (if
* any). */
Method *destructorPtr; /* Method record of the class destructor (if
* any). */
Tcl_HashTable *metadataPtr; /* Mapping from pointers to metadata type to
* the void *values that are the values
|
| ︙ | ︙ | |||
360 361 362 363 364 365 366 |
* [oo::objdefine]/[self] call time if this
* namespace is defined but doesn't exist; we
* also check at setting time but don't check
* between times. */
PropertyStorage properties; /* Information relating to the lists of
* properties that this class *claims* to
* support. */
| < < < < < < < | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
* [oo::objdefine]/[self] call time if this
* namespace is defined but doesn't exist; we
* also check at setting time but don't check
* between times. */
PropertyStorage properties; /* Information relating to the lists of
* properties that this class *claims* to
* support. */
};
/*
* Master epoch counter for making unique IDs for objects that can be compared
* cheaply.
*/
typedef struct ThreadLocalData {
|
| ︙ | ︙ | |||
493 494 495 496 497 498 499 |
#define SCOPE_FLAGS (PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD)
/*
* Structure containing definition information about basic class methods.
*/
struct DeclaredClassMethod {
const char *name; /* Name of the method in question. */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | < | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 |
#define SCOPE_FLAGS (PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD)
/*
* Structure containing definition information about basic class methods.
*/
struct DeclaredClassMethod {
const char *name; /* Name of the method in question. */
int isPublic; /* Whether the method is public by default. */
Tcl_MethodType definition; /* How to call the method. */
};
/*
*----------------------------------------------------------------
* Commands relating to OO support.
*----------------------------------------------------------------
*/
MODULE_SCOPE int TclOOInit(Tcl_Interp *interp);
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOObjDefObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineClassMethodObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineConstructorObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineDefnNsObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineDeleteMethodObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineDestructorObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineExportObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineForwardObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineInitialiseObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineMethodObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineRenameMethodObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineUnexportObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineClassObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineSelfObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefineObjSelfObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefinePrivateObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODefinePropertyCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOUnknownDefinition;
MODULE_SCOPE Tcl_ObjCmdProc TclOOCallbackObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOClassVariableObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOCopyObjectCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOODelegateNameObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOLinkObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOONextObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOONextToObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOSelfObjCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOInfoObjectPropCmd;
MODULE_SCOPE Tcl_ObjCmdProc TclOOInfoClassPropCmd;
/*
* Method implementations (in tclOOBasic.c).
*/
MODULE_SCOPE Tcl_MethodCallProc TclOO_Class_Cloned;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Class_Constructor;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Class_Create;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Class_CreateNs;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Class_New;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Object_Cloned;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Object_Destroy;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Object_Eval;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Object_LinkVar;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Object_Unknown;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Object_VarName;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Configurable_Configure;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Configurable_Constructor;
MODULE_SCOPE Tcl_MethodCallProc TclOO_Singleton_New;
MODULE_SCOPE Tcl_MethodCallProc TclOO_SingletonInstance_Cloned;
MODULE_SCOPE Tcl_MethodCallProc TclOO_SingletonInstance_Destroy;
/*
* Private definitions, some of which perhaps ought to be exposed properly or
* maybe just put in the internal stubs table.
*/
MODULE_SCOPE void TclOOAddToInstances(Object *oPtr, Class *clsPtr);
MODULE_SCOPE void TclOOAddToMixinSubs(Class *subPtr, Class *mixinPtr);
MODULE_SCOPE void TclOOAddToSubclasses(Class *subPtr, Class *superPtr);
MODULE_SCOPE Class * TclOOAllocClass(Tcl_Interp *interp,
Object *useThisObj);
MODULE_SCOPE int TclMethodIsType(Tcl_Method method,
const Tcl_MethodType *typePtr,
void **clientDataPtr);
MODULE_SCOPE Tcl_Method TclNewInstanceMethod(Tcl_Interp *interp,
Tcl_Object object, Tcl_Obj *nameObj,
int flags, const Tcl_MethodType *typePtr,
void *clientData);
MODULE_SCOPE Tcl_Method TclNewMethod(Tcl_Class cls,
Tcl_Obj *nameObj, int flags,
const Tcl_MethodType *typePtr,
void *clientData);
MODULE_SCOPE int TclNRNewObjectInstance(Tcl_Interp *interp,
Tcl_Class cls, const char *nameStr,
const char *nsNameStr, Tcl_Size objc,
Tcl_Obj *const *objv, Tcl_Size skip,
Tcl_Object *objectPtr);
MODULE_SCOPE Object * TclNewObjectInstanceCommon(Tcl_Interp *interp,
Class *classPtr,
const char *nameStr,
const char *nsNameStr);
MODULE_SCOPE int TclOODecrRefCount(Object *oPtr);
MODULE_SCOPE int TclOOObjectDestroyed(Object *oPtr);
MODULE_SCOPE int TclOODefineSlots(Foundation *fPtr);
MODULE_SCOPE void TclOODeleteChain(CallChain *callPtr);
MODULE_SCOPE void TclOODeleteChainCache(Tcl_HashTable *tablePtr);
MODULE_SCOPE void TclOODeleteContext(CallContext *contextPtr);
MODULE_SCOPE void TclOODeleteDescendants(Tcl_Interp *interp,
Object *oPtr);
MODULE_SCOPE void TclOODelMethodRef(Method *method);
MODULE_SCOPE int TclOOExportMethods(Class *clsPtr, ...);
MODULE_SCOPE CallContext *TclOOGetCallContext(Object *oPtr,
Tcl_Obj *methodNameObj, int flags,
Object *contextObjPtr, Class *contextClsPtr,
Tcl_Obj *cacheInThisObj);
MODULE_SCOPE Class * TclOOGetClassDefineCmdContext(Tcl_Interp *interp);
MODULE_SCOPE Class * TclOOGetClassFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr);
MODULE_SCOPE Tcl_Namespace *TclOOGetDefineContextNamespace(
Tcl_Interp *interp, Object *oPtr, int forClass);
MODULE_SCOPE CallChain *TclOOGetStereotypeCallChain(Class *clsPtr,
Tcl_Obj *methodNameObj, int flags);
MODULE_SCOPE Foundation *TclOOGetFoundation(Tcl_Interp *interp);
MODULE_SCOPE Tcl_Obj * TclOOGetFwdFromMethod(Method *mPtr);
MODULE_SCOPE Proc * TclOOGetProcFromMethod(Method *mPtr);
MODULE_SCOPE Tcl_Obj * TclOOGetMethodBody(Method *mPtr);
MODULE_SCOPE size_t TclOOGetSortedClassMethodList(Class *clsPtr,
int flags, const char ***stringsPtr);
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);
MODULE_SCOPE int TclOOInvokeContext(void *clientData,
Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[]);
MODULE_SCOPE Tcl_Var TclOOLookupObjectVar(Tcl_Interp *interp,
Tcl_Object object, Tcl_Obj *varName,
Tcl_Var *aryPtr);
MODULE_SCOPE int TclNRObjectContextInvokeNext(Tcl_Interp *interp,
Tcl_ObjectContext context, Tcl_Size objc,
Tcl_Obj *const *objv, Tcl_Size skip);
MODULE_SCOPE void TclOODefineBasicMethods(Class *clsPtr,
const DeclaredClassMethod *dcm);
MODULE_SCOPE Tcl_Obj * TclOOObjectName(Tcl_Interp *interp, Object *oPtr);
MODULE_SCOPE Tcl_Obj * TclOOObjectMyName(Tcl_Interp *interp, Object *oPtr);
MODULE_SCOPE void TclOOReleaseClassContents(Tcl_Interp *interp,
Object *oPtr);
MODULE_SCOPE int TclOORemoveFromInstances(Object *oPtr, Class *clsPtr);
MODULE_SCOPE int TclOORemoveFromMixins(Class *mixinPtr, Object *oPtr);
MODULE_SCOPE int TclOORemoveFromMixinSubs(Class *subPtr,
Class *mixinPtr);
MODULE_SCOPE int TclOORemoveFromSubclasses(Class *subPtr,
Class *superPtr);
MODULE_SCOPE Tcl_Obj * TclOORenderCallChain(Tcl_Interp *interp,
CallChain *callPtr);
MODULE_SCOPE void TclOOSetSuperclasses(Class *clsPtr, Tcl_Size superc,
Class **superclasses);
MODULE_SCOPE void TclOOStashContext(Tcl_Obj *objPtr,
CallContext *contextPtr);
MODULE_SCOPE void TclOOSetupVariableResolver(Tcl_Namespace *nsPtr);
MODULE_SCOPE int TclOOUnexportMethods(Class *clsPtr, ...);
MODULE_SCOPE Tcl_Obj * TclOOGetPropertyList(PropertyList *propList);
MODULE_SCOPE void TclOOReleasePropertyStorage(PropertyStorage *propsPtr);
MODULE_SCOPE void TclOOInstallReadableProperties(PropertyStorage *props,
Tcl_Size objc, Tcl_Obj *const objv[]);
MODULE_SCOPE void TclOOInstallWritableProperties(PropertyStorage *props,
Tcl_Size objc, Tcl_Obj *const objv[]);
MODULE_SCOPE void TclOORegisterProperty(Class *clsPtr,
Tcl_Obj *propName, int mayRead, int mayWrite);
MODULE_SCOPE void TclOORegisterInstanceProperty(Object *oPtr,
Tcl_Obj *propName, int mayRead, int mayWrite);
/*
* Include all the private API, generated from tclOO.decls.
*/
#include "tclOOIntDecls.h" /* IWYU pragma: export */
/*
* Alternatives to Tcl_Preserve/Tcl_EventuallyFree/Tcl_Release.
*/
#define AddRef(ptr) ((ptr)->refCount++)
/*
* A convenience macro for iterating through the lists used in the internal
* memory management of objects.
* REQUIRES DECLARATION: Tcl_Size i;
*/
#define FOREACH(var,ary) \
for(i=0 ; i<(ary).num; i++) if ((ary).list[i] == NULL) { \
continue; \
} else if ((var) = (ary).list[i], 1)
/*
* A variation where the array is an array of structs. There's no issue with
* possible NULLs; every element of the array will be iterated over and the
* variable set to a pointer to each of those elements in turn.
* REQUIRES DECLARATION: Tcl_Size i; See [96551aca55] for more FOREACH_STRUCT details.
*/
#define FOREACH_STRUCT(var,ary) \
if (i=0, (ary).num>0) for(; 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_KEY and FOREACH_HASH_VALUE are
* restricted versions that only iterate over keys or values respectively.
* REQUIRES DECLARATION: FOREACH_HASH_DECLS;
*/
#define FOREACH_HASH_DECLS \
Tcl_HashEntry *hPtr;Tcl_HashSearch search
#define FOREACH_HASH(key, val, tablePtr) \
for(hPtr = Tcl_FirstHashEntry((tablePtr), &search); hPtr != NULL ? \
(*(void **)&(key) = Tcl_GetHashKey((tablePtr), hPtr), \
*(void **)&(val) = Tcl_GetHashValue(hPtr), 1) : 0; \
hPtr = Tcl_NextHashEntry(&search))
#define FOREACH_HASH_KEY(key, tablePtr) \
for(hPtr = Tcl_FirstHashEntry((tablePtr), &search); hPtr != NULL ? \
(*(void **)&(key) = Tcl_GetHashKey((tablePtr), hPtr), 1) : 0; \
hPtr = Tcl_NextHashEntry(&search))
#define FOREACH_HASH_VALUE(val, tablePtr) \
for(hPtr = Tcl_FirstHashEntry((tablePtr), &search); hPtr != NULL ? \
(*(void **)&(val) = Tcl_GetHashValue(hPtr), 1) : 0; \
hPtr = Tcl_NextHashEntry(&search))
/*
* Convenience macro for duplicating a list. Needs no external declaration,
* but all arguments are used multiple times and so must have no side effects.
*/
|
| ︙ | ︙ | |||
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 |
} while(0)
/*
* Convenience macro for generating error codes.
*/
#define OO_ERROR(interp, code) \
Tcl_SetErrorCode((interp), "TCL", "OO", #code, (char *)NULL)
#endif /* TCL_OO_INTERNAL_H */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
| > > > > > | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 |
} while(0)
/*
* Convenience macro for generating error codes.
*/
#define OO_ERROR(interp, code) \
Tcl_SetErrorCode((interp), "TCL", "OO", #code, (char *)NULL)
#ifdef _TCLSIZEHANDLED
# undef _TCLSIZEHANDLED
# undef Tcl_Size
#endif
#endif /* TCL_OO_INTERNAL_H */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclOOIntDecls.h.
1 2 3 4 5 6 7 | /* * This file is (mostly) automatically generated from tclOO.decls. */ #ifndef _TCLOOINTDECLS #define _TCLOOINTDECLS | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/*
* This file is (mostly) automatically generated from tclOO.decls.
*/
#ifndef _TCLOOINTDECLS
#define _TCLOOINTDECLS
#if TCL_MAJOR_VERSION < 9
# define Tcl_MethodType2 void
#endif
/* !BEGIN!: Do not edit below this line. */
#ifdef __cplusplus
extern "C" {
#endif
|
| ︙ | ︙ | |||
182 183 184 185 186 187 188 | #define TclOOMakeProcMethod2 \ (tclOOIntStubsPtr->tclOOMakeProcMethod2) /* 17 */ #endif /* defined(USE_TCLOO_STUBS) */ /* !END!: Do not edit above this line. */ | | | < < < < < < < < < < < < < | < < < | < < < < < < < < < < < | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #define TclOOMakeProcMethod2 \ (tclOOIntStubsPtr->tclOOMakeProcMethod2) /* 17 */ #endif /* defined(USE_TCLOO_STUBS) */ /* !END!: Do not edit above this line. */ #if TCL_MAJOR_VERSION < 9 #undef Tcl_MethodType2 #undef TclOOMakeProcInstanceMethod2 #undef TclOOMakeProcMethod2 #endif #endif /* _TCLOOINTDECLS */ |
Changes to generic/tclOOMethod.c.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 |
* on-the-ground resolvers used when working with resolved compiled variables.
*/
typedef struct OOResVarInfo {
Tcl_ResolvedVarInfo info; /* "Type" information so that the compiled
* variable can be linked to the namespace
* variable at the right time. */
Tcl_Var cachedObjectVar; /* TODO: When to flush this cache? Can class
* variables be cached? */
| > < < | | | | | | | | | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
* on-the-ground resolvers used when working with resolved compiled variables.
*/
typedef struct OOResVarInfo {
Tcl_ResolvedVarInfo info; /* "Type" information so that the compiled
* variable can be linked to the namespace
* variable at the right time. */
Tcl_Obj *variableObj; /* The name of the variable. */
Tcl_Var cachedObjectVar; /* TODO: When to flush this cache? Can class
* variables be cached? */
} OOResVarInfo;
/*
* Function declarations for things defined in this file.
*/
static Tcl_Obj ** InitEnsembleRewrite(Tcl_Interp *interp, int objc,
Tcl_Obj *const *objv, int toRewrite,
int rewriteLength, Tcl_Obj *const *rewriteObjs,
int *lengthPtr);
static int InvokeProcedureMethod(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static Tcl_NRPostProc FinalizeForwardCall;
static Tcl_NRPostProc FinalizePMCall;
static int PushMethodCallFrame(Tcl_Interp *interp,
CallContext *contextPtr, ProcedureMethod *pmPtr,
int objc, Tcl_Obj *const *objv,
PMFrameData *fdPtr);
static void DeleteProcedureMethodRecord(ProcedureMethod *pmPtr);
static void DeleteProcedureMethod(void *clientData);
static int CloneProcedureMethod(Tcl_Interp *interp,
void *clientData, void **newClientData);
static ProcErrorProc MethodErrorHandler;
static ProcErrorProc ConstructorErrorHandler;
static ProcErrorProc DestructorErrorHandler;
static Tcl_Obj * RenderMethodName(void *clientData);
static Tcl_Obj * RenderDeclarerName(void *clientData);
static int InvokeForwardMethod(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static void DeleteForwardMethod(void *clientData);
static int CloneForwardMethod(Tcl_Interp *interp,
void *clientData, void **newClientData);
static Tcl_ResolveVarProc ProcedureMethodVarResolver;
static Tcl_ResolveCompiledVarProc ProcedureMethodCompiledVarResolver;
/*
* The types of methods defined by the core OO system.
*/
static const Tcl_MethodType procMethodType = {
TCL_OO_METHOD_VERSION_CURRENT, "method",
InvokeProcedureMethod, DeleteProcedureMethod, CloneProcedureMethod
};
static const Tcl_MethodType fwdMethodType = {
TCL_OO_METHOD_VERSION_CURRENT, "forward",
InvokeForwardMethod, DeleteForwardMethod, CloneForwardMethod
};
/*
* Helper macros (derived from things private to tclVar.c)
*/
|
| ︙ | ︙ | |||
139 140 141 142 143 144 145 |
TCL_UNUSED(Tcl_Interp *),
Tcl_Object object, /* The object that has the method attached to
* it. */
Tcl_Obj *nameObj, /* The name of the method. May be NULL; if so,
* up to caller to manage storage (e.g., when
* it is a constructor or destructor). */
int flags, /* Whether this is a public method. */
| | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
TCL_UNUSED(Tcl_Interp *),
Tcl_Object object, /* The object that has the method attached to
* it. */
Tcl_Obj *nameObj, /* The name of the method. May be NULL; if so,
* up to caller to manage storage (e.g., when
* it is a constructor or destructor). */
int flags, /* Whether this is a public method. */
const Tcl_MethodType *typePtr,
/* The type of method this is, which defines
* how to invoke, delete and clone the
* method. */
void *clientData) /* Some data associated with the particular
* method to be created. */
{
Object *oPtr = (Object *) object;
|
| ︙ | ︙ | |||
171 172 173 174 175 176 177 |
mPtr = (Method *) Tcl_Alloc(sizeof(Method));
mPtr->namePtr = nameObj;
mPtr->refCount = 1;
Tcl_IncrRefCount(nameObj);
Tcl_SetHashValue(hPtr, mPtr);
} else {
mPtr = (Method *) Tcl_GetHashValue(hPtr);
| | | | < < < | | < < | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
mPtr = (Method *) Tcl_Alloc(sizeof(Method));
mPtr->namePtr = nameObj;
mPtr->refCount = 1;
Tcl_IncrRefCount(nameObj);
Tcl_SetHashValue(hPtr, mPtr);
} else {
mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) {
mPtr->typePtr->deleteProc(mPtr->clientData);
}
}
populate:
mPtr->typePtr = typePtr;
mPtr->clientData = clientData;
mPtr->flags = 0;
mPtr->declaringObjectPtr = oPtr;
mPtr->declaringClassPtr = NULL;
if (flags) {
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;
}
Tcl_Method
Tcl_NewInstanceMethod(
TCL_UNUSED(Tcl_Interp *),
Tcl_Object object, /* The object that has the method attached to
* it. */
Tcl_Obj *nameObj, /* The name of the method. May be NULL; if so,
* up to caller to manage storage (e.g., when
* it is a constructor or destructor). */
int flags, /* Whether this is a public method. */
const Tcl_MethodType *typePtr,
/* The type of method this is, which defines
* how to invoke, delete and clone the
* method. */
void *clientData) /* Some data associated with the particular
* method to be created. */
{
if (typePtr->version > TCL_OO_METHOD_VERSION_1) {
Tcl_Panic("%s: Wrong version in typePtr->version, should be %s",
"Tcl_NewInstanceMethod", "TCL_OO_METHOD_VERSION_1");
}
return TclNewInstanceMethod(NULL, object, nameObj, flags, typePtr,
clientData);
}
Tcl_Method
Tcl_NewInstanceMethod2(
TCL_UNUSED(Tcl_Interp *),
Tcl_Object object, /* The object that has the method attached to
* it. */
Tcl_Obj *nameObj, /* The name of the method. May be NULL; if so,
* up to caller to manage storage (e.g., when
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 |
* method to be created. */
{
if (typePtr->version < TCL_OO_METHOD_VERSION_2) {
Tcl_Panic("%s: Wrong version in typePtr->version, should be %s",
"Tcl_NewInstanceMethod2", "TCL_OO_METHOD_VERSION_2");
}
return TclNewInstanceMethod(NULL, object, nameObj, flags,
| | | | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
* method to be created. */
{
if (typePtr->version < TCL_OO_METHOD_VERSION_2) {
Tcl_Panic("%s: Wrong version in typePtr->version, should be %s",
"Tcl_NewInstanceMethod2", "TCL_OO_METHOD_VERSION_2");
}
return TclNewInstanceMethod(NULL, object, nameObj, flags,
(const Tcl_MethodType *) typePtr, clientData);
}
/*
* ----------------------------------------------------------------------
*
* Tcl_NewMethod --
*
* Attach a method to a class.
*
* ----------------------------------------------------------------------
*/
Tcl_Method
TclNewMethod(
Tcl_Class cls, /* The class to attach the method to. */
Tcl_Obj *nameObj, /* The name of the object. May be NULL (e.g.,
* for constructors or destructors); if so, up
* to caller to manage storage. */
int flags, /* Whether this is a public method. */
const Tcl_MethodType *typePtr,
/* The type of method this is, which defines
* how to invoke, delete and clone the
* method. */
void *clientData) /* Some data associated with the particular
* method to be created. */
{
Class *clsPtr = (Class *) cls;
|
| ︙ | ︙ | |||
288 289 290 291 292 293 294 |
mPtr = (Method *) Tcl_Alloc(sizeof(Method));
mPtr->refCount = 1;
mPtr->namePtr = nameObj;
Tcl_IncrRefCount(nameObj);
Tcl_SetHashValue(hPtr, mPtr);
} else {
mPtr = (Method *) Tcl_GetHashValue(hPtr);
| | | | < < | < < | > | | | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
mPtr = (Method *) Tcl_Alloc(sizeof(Method));
mPtr->refCount = 1;
mPtr->namePtr = nameObj;
Tcl_IncrRefCount(nameObj);
Tcl_SetHashValue(hPtr, mPtr);
} else {
mPtr = (Method *) Tcl_GetHashValue(hPtr);
if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) {
mPtr->typePtr->deleteProc(mPtr->clientData);
}
}
populate:
clsPtr->thisPtr->fPtr->epoch++;
mPtr->typePtr = typePtr;
mPtr->clientData = clientData;
mPtr->flags = 0;
mPtr->declaringObjectPtr = NULL;
mPtr->declaringClassPtr = clsPtr;
if (flags) {
mPtr->flags |= flags &
(PUBLIC_METHOD | PRIVATE_METHOD | TRUE_PRIVATE_METHOD);
if (flags & TRUE_PRIVATE_METHOD) {
clsPtr->flags |= HAS_PRIVATE_METHODS;
}
}
return (Tcl_Method) mPtr;
}
Tcl_Method
Tcl_NewMethod(
TCL_UNUSED(Tcl_Interp *),
Tcl_Class cls, /* The class to attach the method to. */
Tcl_Obj *nameObj, /* The name of the object. May be NULL (e.g.,
* for constructors or destructors); if so, up
* to caller to manage storage. */
int flags, /* Whether this is a public method. */
const Tcl_MethodType *typePtr,
/* The type of method this is, which defines
* how to invoke, delete and clone the
* method. */
void *clientData) /* Some data associated with the particular
* method to be created. */
{
if (typePtr->version > TCL_OO_METHOD_VERSION_1) {
Tcl_Panic("%s: Wrong version in typePtr->version, should be %s",
"Tcl_NewMethod", "TCL_OO_METHOD_VERSION_1");
}
return TclNewMethod(cls, nameObj, flags, typePtr, clientData);
}
Tcl_Method
Tcl_NewMethod2(
TCL_UNUSED(Tcl_Interp *),
Tcl_Class cls, /* The class to attach the method to. */
Tcl_Obj *nameObj, /* The name of the object. May be NULL (e.g.,
* for constructors or destructors); if so, up
* to caller to manage storage. */
int flags, /* Whether this is a public method. */
const Tcl_MethodType2 *typePtr,
/* The type of method this is, which defines
* how to invoke, delete and clone the
* method. */
void *clientData) /* Some data associated with the particular
* method to be created. */
{
if (typePtr->version < TCL_OO_METHOD_VERSION_2) {
Tcl_Panic("%s: Wrong version in typePtr->version, should be %s",
"Tcl_NewMethod2", "TCL_OO_METHOD_VERSION_2");
}
return TclNewMethod(cls, nameObj, flags,
(const Tcl_MethodType *) typePtr, clientData);
}
/*
* ----------------------------------------------------------------------
*
* TclOODelMethodRef --
*
* How to delete a method.
*
* ----------------------------------------------------------------------
*/
void
TclOODelMethodRef(
Method *mPtr)
{
if ((mPtr != NULL) && (mPtr->refCount-- <= 1)) {
if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) {
mPtr->typePtr->deleteProc(mPtr->clientData);
}
if (mPtr->namePtr != NULL) {
Tcl_DecrRefCount(mPtr->namePtr);
}
Tcl_Free(mPtr);
}
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 |
void
TclOODefineBasicMethods(
Class *clsPtr, /* Class to attach the methods to. */
const DeclaredClassMethod *dcmAry)
/* Static table of method definitions. */
{
| > | > | | > | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
void
TclOODefineBasicMethods(
Class *clsPtr, /* Class to attach the methods to. */
const DeclaredClassMethod *dcmAry)
/* Static table of method definitions. */
{
int i;
for (i = 0 ; dcmAry[i].name ; i++) {
Tcl_Obj *namePtr = Tcl_NewStringObj(dcmAry[i].name, TCL_AUTO_LENGTH);
TclNewMethod((Tcl_Class) clsPtr, namePtr,
(dcmAry[i].isPublic ? PUBLIC_METHOD : 0),
&dcmAry[i].definition, NULL);
Tcl_BounceRefCount(namePtr);
}
}
/*
* ----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
445 446 447 448 449 450 451 |
ProcedureMethod *pmPtr;
Tcl_Method method;
if (TclListObjLength(interp, argsObj, &argsLen) != TCL_OK) {
return NULL;
}
pmPtr = AllocProcedureMethodRecord(flags);
| | | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
ProcedureMethod *pmPtr;
Tcl_Method method;
if (TclListObjLength(interp, argsObj, &argsLen) != TCL_OK) {
return NULL;
}
pmPtr = AllocProcedureMethodRecord(flags);
method = TclOOMakeProcInstanceMethod(interp, oPtr, flags, nameObj,
argsObj, bodyObj, &procMethodType, pmPtr, &pmPtr->procPtr);
if (method == NULL) {
Tcl_Free(pmPtr);
} else if (pmPtrPtr != NULL) {
*pmPtrPtr = pmPtr;
}
return (Method *) method;
|
| ︙ | ︙ | |||
501 502 503 504 505 506 507 |
} else if (TclListObjLength(interp, argsObj, &argsLen) != TCL_OK) {
return NULL;
} else {
procName = (nameObj==NULL ? "<constructor>" : TclGetString(nameObj));
}
pmPtr = AllocProcedureMethodRecord(flags);
| | | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
} else if (TclListObjLength(interp, argsObj, &argsLen) != TCL_OK) {
return NULL;
} else {
procName = (nameObj==NULL ? "<constructor>" : TclGetString(nameObj));
}
pmPtr = AllocProcedureMethodRecord(flags);
method = TclOOMakeProcMethod(interp, clsPtr, flags, nameObj, procName,
argsObj, bodyObj, &procMethodType, pmPtr, &pmPtr->procPtr);
if (argsLen == TCL_INDEX_NONE) {
Tcl_DecrRefCount(argsObj);
}
if (method == NULL) {
Tcl_Free(pmPtr);
|
| ︙ | ︙ | |||
566 567 568 569 570 571 572 573 574 575 576 577 |
* is NOT a fixed count of arguments in because of the alternate
* form of [oo::define]/[oo::objdefine].
* (FIXME: check that this is sane and correct!)
*/
if (context.line && context.nline > 1
&& (context.line[context.nline - 1] >= 0)) {
CmdFrame *cfPtr = (CmdFrame *) Tcl_Alloc(sizeof(CmdFrame));
Tcl_HashEntry *hPtr;
cfPtr->level = -1;
cfPtr->type = context.type;
| > | | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
* is NOT a fixed count of arguments in because of the alternate
* form of [oo::define]/[oo::objdefine].
* (FIXME: check that this is sane and correct!)
*/
if (context.line && context.nline > 1
&& (context.line[context.nline - 1] >= 0)) {
int isNew;
CmdFrame *cfPtr = (CmdFrame *) Tcl_Alloc(sizeof(CmdFrame));
Tcl_HashEntry *hPtr;
cfPtr->level = -1;
cfPtr->type = context.type;
cfPtr->line = (Tcl_Size *) Tcl_Alloc(sizeof(Tcl_Size));
cfPtr->line[0] = context.line[context.nline - 1];
cfPtr->nline = 1;
cfPtr->framePtr = NULL;
cfPtr->nextPtr = NULL;
cfPtr->data.eval.path = context.data.eval.path;
Tcl_IncrRefCount(cfPtr->data.eval.path);
cfPtr->cmd = NULL;
cfPtr->len = 0;
hPtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr,
procPtr, &isNew);
Tcl_SetHashValue(hPtr, cfPtr);
}
/*
* 'context' is going out of scope; account for the reference that
* it's holding to the path name.
*/
|
| ︙ | ︙ | |||
612 613 614 615 616 617 618 | * Split apart so that it is easier for other extensions to reuse (in * particular, it frees them from having to pry so deeply into Tcl's * guts). * * ---------------------------------------------------------------------- */ | < < | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 |
* Split apart so that it is easier for other extensions to reuse (in
* particular, it frees them from having to pry so deeply into Tcl's
* guts).
*
* ----------------------------------------------------------------------
*/
Tcl_Method
TclOOMakeProcInstanceMethod(
Tcl_Interp *interp, /* The interpreter containing the object. */
Object *oPtr, /* The object to modify. */
int flags, /* Whether this is a public method. */
Tcl_Obj *nameObj, /* The name of the method, which _must not_ be
* NULL. */
|
| ︙ | ︙ | |||
650 651 652 653 654 655 656 |
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
return TclNewInstanceMethod(interp, (Tcl_Object) oPtr, nameObj, flags,
| | < | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
return TclNewInstanceMethod(interp, (Tcl_Object) oPtr, nameObj, flags,
typePtr, clientData);
}
Tcl_Method
TclOOMakeProcInstanceMethod2(
Tcl_Interp *interp, /* The interpreter containing the object. */
Object *oPtr, /* The object to modify. */
int flags, /* Whether this is a public method. */
Tcl_Obj *nameObj, /* The name of the method, which _must not_ be
|
| ︙ | ︙ | |||
690 691 692 693 694 695 696 |
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
return TclNewInstanceMethod(interp, (Tcl_Object) oPtr, nameObj, flags,
| | < < | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
return TclNewInstanceMethod(interp, (Tcl_Object) oPtr, nameObj, flags,
(const Tcl_MethodType *)typePtr, clientData);
}
/*
* ----------------------------------------------------------------------
*
* TclOOMakeProcMethod --
*
* The guts of the code to make a procedure-like method for a class.
* Split apart so that it is easier for other extensions to reuse (in
* particular, it frees them from having to pry so deeply into Tcl's
* guts).
*
* ----------------------------------------------------------------------
*/
Tcl_Method
TclOOMakeProcMethod(
Tcl_Interp *interp, /* The interpreter containing the class. */
Class *clsPtr, /* The class to modify. */
int flags, /* Whether this is a public method. */
Tcl_Obj *nameObj, /* The name of the method, which may be NULL;
* if so, up to caller to manage storage
|
| ︙ | ︙ | |||
748 749 750 751 752 753 754 |
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
return TclNewMethod(
| | < | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 |
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
return TclNewMethod(
(Tcl_Class) clsPtr, nameObj, flags, typePtr, clientData);
}
Tcl_Method
TclOOMakeProcMethod2(
Tcl_Interp *interp, /* The interpreter containing the class. */
Class *clsPtr, /* The class to modify. */
int flags, /* Whether this is a public method. */
Tcl_Obj *nameObj, /* The name of the method, which may be NULL;
|
| ︙ | ︙ | |||
791 792 793 794 795 796 797 |
return NULL;
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
| | | | | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
return NULL;
}
procPtr = *procPtrPtr;
procPtr->cmdPtr = NULL;
InitCmdFrame(iPtr, procPtr);
return TclNewMethod(
(Tcl_Class) clsPtr, nameObj, flags, (const Tcl_MethodType *)typePtr, clientData);
}
/*
* ----------------------------------------------------------------------
*
* InvokeProcedureMethod, FinalizePMCall, PushMethodCallFrame --
*
* How to invoke a procedure-like method.
*
* ----------------------------------------------------------------------
*/
static int
InvokeProcedureMethod(
void *clientData, /* Pointer to the per-method record. */
Tcl_Interp *interp,
Tcl_ObjectContext context, /* The method calling context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments as actually seen. */
{
ProcedureMethod *pmPtr = (ProcedureMethod *) clientData;
int result;
PMFrameData *fdPtr; /* Important data that has to have a lifetime
* matched by this function (or rather, by the
* call frame's lifetime). */
|
| ︙ | ︙ | |||
949 950 951 952 953 954 955 |
static int
PushMethodCallFrame(
Tcl_Interp *interp, /* Current interpreter. */
CallContext *contextPtr, /* Current method call context. */
ProcedureMethod *pmPtr, /* Information about this procedure-like
* method. */
| | | 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 |
static int
PushMethodCallFrame(
Tcl_Interp *interp, /* Current interpreter. */
CallContext *contextPtr, /* Current method call context. */
ProcedureMethod *pmPtr, /* Information about this procedure-like
* method. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv, /* Array of arguments. */
PMFrameData *fdPtr) /* Place to store information about the call
* frame. */
{
Namespace *nsPtr = (Namespace *) contextPtr->oPtr->namespacePtr;
int result;
CallFrame **framePtrPtr = &fdPtr->framePtr;
|
| ︙ | ︙ | |||
1053 1054 1055 1056 1057 1058 1059 |
TclOOSetupVariableResolver(
Tcl_Namespace *nsPtr)
{
Tcl_ResolverInfo info;
Tcl_GetNamespaceResolvers(nsPtr, &info);
if (info.compiledVarResProc == NULL) {
| | < < | < > | < < < < < < < < < < < < < < < < < < < < < | | < | | > | < < < < < | > | | < < < < | < < | | < < < < < < < < < < | < | < < < < | < < < < < < < < < | < < < > | < | < < | < < < < | < < < < > > > > > > > > > | < > > > > > > > > > | > > > > > > > > > > > > > > > | | > > > > | < > > > | > > > > > | > > > | | > | | | > | < | | < < < < | < < < | < | > < < < < < < < < | < < | < | < < | | < < < < < < < < | < | < > | 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
TclOOSetupVariableResolver(
Tcl_Namespace *nsPtr)
{
Tcl_ResolverInfo info;
Tcl_GetNamespaceResolvers(nsPtr, &info);
if (info.compiledVarResProc == NULL) {
Tcl_SetNamespaceResolvers(nsPtr, NULL, ProcedureMethodVarResolver,
ProcedureMethodCompiledVarResolver);
}
}
static int
ProcedureMethodVarResolver(
Tcl_Interp *interp,
const char *varName,
Tcl_Namespace *contextNs,
TCL_UNUSED(int) /*flags*/, // Ignoring variable access flags (???)
Tcl_Var *varPtr)
{
int result;
Tcl_ResolvedVarInfo *rPtr = NULL;
result = ProcedureMethodCompiledVarResolver(interp, varName,
strlen(varName), contextNs, &rPtr);
if (result != TCL_OK) {
return result;
}
*varPtr = rPtr->fetchProc(interp, rPtr);
/*
* Must not retain reference to resolved information. [Bug 3105999]
*/
rPtr->deleteProc(rPtr);
return (*varPtr ? TCL_OK : TCL_CONTINUE);
}
static Tcl_Var
ProcedureMethodCompiledVarConnect(
Tcl_Interp *interp,
Tcl_ResolvedVarInfo *rPtr)
{
OOResVarInfo *infoPtr = (OOResVarInfo *) rPtr;
Interp *iPtr = (Interp *) interp;
CallFrame *framePtr = iPtr->varFramePtr;
CallContext *contextPtr;
Tcl_Obj *variableObj;
PrivateVariableMapping *privateVar;
Tcl_HashEntry *hPtr;
int isNew, cacheIt;
Tcl_Size i, varLen, len;
const char *match, *varName;
/*
* Check that the variable is being requested in a context that is also a
* method call; if not (i.e. we're evaluating in the object's namespace or
* in a procedure of that namespace) then we do nothing.
*/
if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
return NULL;
}
contextPtr = (CallContext *) framePtr->clientData;
/*
* If we've done the work before (in a comparable context) then reuse that
* rather than performing resolution ourselves.
*/
if (infoPtr->cachedObjectVar) {
return infoPtr->cachedObjectVar;
}
/*
* Check if the variable is one we want to resolve at all (i.e. whether it
* is in the list provided by the user). If not, we mustn't do anything
* either.
*/
varName = Tcl_GetStringFromObj(infoPtr->variableObj, &varLen);
if (contextPtr->callPtr->chain[contextPtr->index]
.mPtr->declaringClassPtr != NULL) {
FOREACH_STRUCT(privateVar, contextPtr->callPtr->chain[contextPtr->index]
.mPtr->declaringClassPtr->privateVariables) {
match = Tcl_GetStringFromObj(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 = Tcl_GetStringFromObj(variableObj, &len);
if ((len == varLen) && !memcmp(match, varName, len)) {
cacheIt = 0;
goto gotMatch;
}
}
} else {
FOREACH_STRUCT(privateVar, contextPtr->oPtr->privateVariables) {
match = Tcl_GetStringFromObj(privateVar->variableObj, &len);
if ((len == varLen) && !memcmp(match, varName, len)) {
variableObj = privateVar->fullNameObj;
cacheIt = 1;
goto gotMatch;
}
}
FOREACH(variableObj, contextPtr->oPtr->variables) {
match = Tcl_GetStringFromObj(variableObj, &len);
if ((len == varLen) && !memcmp(match, varName, len)) {
cacheIt = 1;
goto gotMatch;
}
}
}
return NULL;
/*
* It is a variable we want to resolve, so resolve it.
*/
gotMatch:
hPtr = Tcl_CreateHashEntry(TclVarTable(contextPtr->oPtr->namespacePtr),
variableObj, &isNew);
if (isNew) {
TclSetVarNamespaceVar((Var *) TclVarHashGetValue(hPtr));
}
if (cacheIt) {
infoPtr->cachedObjectVar = TclVarHashGetValue(hPtr);
/*
* We must keep a reference to the variable so everything will
* continue to work correctly even if it is unset; being unset does
* not end the life of the variable at this level. [Bug 3185009]
*/
VarHashRefCount(infoPtr->cachedObjectVar)++;
}
return TclVarHashGetValue(hPtr);
}
static void
ProcedureMethodCompiledVarDelete(
Tcl_ResolvedVarInfo *rPtr)
{
OOResVarInfo *infoPtr = (OOResVarInfo *) rPtr;
/*
* Release the reference to the variable if we were holding it.
*/
if (infoPtr->cachedObjectVar) {
VarHashRefCount(infoPtr->cachedObjectVar)--;
TclCleanupVar((Var *) infoPtr->cachedObjectVar, NULL);
}
Tcl_DecrRefCount(infoPtr->variableObj);
Tcl_Free(infoPtr);
}
static int
ProcedureMethodCompiledVarResolver(
TCL_UNUSED(Tcl_Interp *),
const char *varName,
Tcl_Size length,
TCL_UNUSED(Tcl_Namespace *),
Tcl_ResolvedVarInfo **rPtrPtr)
{
OOResVarInfo *infoPtr;
Tcl_Obj *variableObj = Tcl_NewStringObj(varName, length);
/*
* Do not create resolvers for cases that contain namespace separators or
* which look like array accesses. Both will lead us astray.
*/
if (strstr(TclGetString(variableObj), "::") != NULL ||
Tcl_StringMatch(TclGetString(variableObj), "*(*)")) {
Tcl_DecrRefCount(variableObj);
return TCL_CONTINUE;
}
infoPtr = (OOResVarInfo *) Tcl_Alloc(sizeof(OOResVarInfo));
infoPtr->info.fetchProc = ProcedureMethodCompiledVarConnect;
infoPtr->info.deleteProc = ProcedureMethodCompiledVarDelete;
infoPtr->cachedObjectVar = NULL;
infoPtr->variableObj = variableObj;
Tcl_IncrRefCount(variableObj);
*rPtrPtr = &infoPtr->info;
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1318 1319 1320 1321 1322 1323 1324 |
return TclOOGetFoundation(pmPtr->interp)->constructorName;
} else if (pmPtr->callSiteFlags & DESTRUCTOR) {
return TclOOGetFoundation(pmPtr->interp)->destructorName;
} else {
return Tcl_MethodName(pmPtr->method);
}
}
| | | 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
return TclOOGetFoundation(pmPtr->interp)->constructorName;
} else if (pmPtr->callSiteFlags & DESTRUCTOR) {
return TclOOGetFoundation(pmPtr->interp)->destructorName;
} else {
return Tcl_MethodName(pmPtr->method);
}
}
/*
* ----------------------------------------------------------------------
*
* RenderDeclarerName --
*
* Returns the name of the entity (object or class) which declared a
* method. Used for producing information for [info frame] in such a way
|
| ︙ | ︙ | |||
1630 1631 1632 1633 1634 1635 1636 |
*/
static int
InvokeForwardMethod(
void *clientData, /* Pointer to some per-method context. */
Tcl_Interp *interp,
Tcl_ObjectContext context, /* The method calling context. */
| | | | 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 |
*/
static int
InvokeForwardMethod(
void *clientData, /* Pointer to some per-method context. */
Tcl_Interp *interp,
Tcl_ObjectContext context, /* The method calling context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments as actually seen. */
{
CallContext *contextPtr = (CallContext *) context;
ForwardMethod *fmPtr = (ForwardMethod *) clientData;
Tcl_Obj **argObjs, **prefixObjs;
Tcl_Size numPrefixes, skip = contextPtr->skip;
int len;
/*
* Build the real list of arguments to use. Note that we know that the
* prefixObj field of the ForwardMethod structure holds a reference to a
* non-empty list, so there's a whole class of failures ("not a list") we
* can ignore here.
*/
|
| ︙ | ︙ | |||
1722 1723 1724 1725 1726 1727 1728 |
* ----------------------------------------------------------------------
*/
Proc *
TclOOGetProcFromMethod(
Method *mPtr)
{
| | | | | | | | | | | | | | | | | | | 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 |
* ----------------------------------------------------------------------
*/
Proc *
TclOOGetProcFromMethod(
Method *mPtr)
{
if (mPtr->typePtr == &procMethodType) {
ProcedureMethod *pmPtr = (ProcedureMethod *) mPtr->clientData;
return pmPtr->procPtr;
}
return NULL;
}
Tcl_Obj *
TclOOGetMethodBody(
Method *mPtr)
{
if (mPtr->typePtr == &procMethodType) {
ProcedureMethod *pmPtr = (ProcedureMethod *) mPtr->clientData;
(void) TclGetString(pmPtr->procPtr->bodyPtr);
return pmPtr->procPtr->bodyPtr;
}
return NULL;
}
Tcl_Obj *
TclOOGetFwdFromMethod(
Method *mPtr)
{
if (mPtr->typePtr == &fwdMethodType) {
ForwardMethod *fwPtr = (ForwardMethod *) mPtr->clientData;
return fwPtr->prefixObj;
}
return NULL;
}
/*
* ----------------------------------------------------------------------
*
* InitEnsembleRewrite --
*
* Utility function that wraps up a lot of the complexity involved in
* doing ensemble-like command forwarding. Here is a picture of memory
* management plan:
*
* <-----------------objc---------------------->
* objv: |=============|===============================|
* <-toRewrite-> |
* \
* <-rewriteLength-> \
* rewriteObjs: |=================| \
* | |
* V V
* argObjs: |=================|===============================|
* <------------------*lengthPtr------------------->
*
* ----------------------------------------------------------------------
*/
static Tcl_Obj **
InitEnsembleRewrite(
Tcl_Interp *interp, /* Place to log the rewrite info. */
int objc, /* Number of real arguments. */
Tcl_Obj *const *objv, /* The real arguments. */
int toRewrite, /* Number of real arguments to replace. */
int rewriteLength, /* Number of arguments to insert instead. */
Tcl_Obj *const *rewriteObjs,/* Arguments to insert instead. */
int *lengthPtr) /* Where to write the resulting length of the
* array of rewritten arguments. */
{
size_t len = rewriteLength + objc - toRewrite;
Tcl_Obj **argObjs = (Tcl_Obj **)
TclStackAlloc(interp, sizeof(Tcl_Obj *) * len);
memcpy(argObjs, rewriteObjs, rewriteLength * sizeof(Tcl_Obj *));
|
| ︙ | ︙ | |||
1844 1845 1846 1847 1848 1849 1850 |
{
return ((Method *) method)->namePtr;
}
int
TclMethodIsType(
Tcl_Method method,
| | | < < | < | | | | 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 |
{
return ((Method *) method)->namePtr;
}
int
TclMethodIsType(
Tcl_Method method,
const Tcl_MethodType *typePtr,
void **clientDataPtr)
{
Method *mPtr = (Method *) method;
if (mPtr->typePtr == typePtr) {
if (clientDataPtr != NULL) {
*clientDataPtr = mPtr->clientData;
}
return 1;
}
return 0;
}
int
Tcl_MethodIsType(
Tcl_Method method,
const Tcl_MethodType *typePtr,
void **clientDataPtr)
{
Method *mPtr = (Method *) method;
if (typePtr->version > TCL_OO_METHOD_VERSION_1) {
Tcl_Panic("%s: Wrong version in typePtr->version, should be %s",
"Tcl_MethodIsType", "TCL_OO_METHOD_VERSION_1");
}
if (mPtr->typePtr == typePtr) {
if (clientDataPtr != NULL) {
*clientDataPtr = mPtr->clientData;
}
return 1;
}
return 0;
}
int
Tcl_MethodIsType2(
Tcl_Method method,
const Tcl_MethodType2 *typePtr,
void **clientDataPtr)
{
Method *mPtr = (Method *) method;
if (typePtr->version < TCL_OO_METHOD_VERSION_2) {
Tcl_Panic("%s: Wrong version in typePtr->version, should be %s",
"Tcl_MethodIsType2", "TCL_OO_METHOD_VERSION_2");
}
if (mPtr->typePtr == (const Tcl_MethodType *) typePtr) {
if (clientDataPtr != NULL) {
*clientDataPtr = mPtr->clientData;
}
return 1;
}
return 0;
}
int
Tcl_MethodIsPublic(
Tcl_Method method)
{
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.
*/
Tcl_Method
|
| ︙ | ︙ |
Changes to generic/tclOOProp.c.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 | /* * Forward declarations. */ static int Configurable_Getter(void *clientData, Tcl_Interp *interp, Tcl_ObjectContext context, | | | | | | | | < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | > > > | | > | < | < | < < | | > | < | < | < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
/*
* Forward declarations.
*/
static int Configurable_Getter(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static int Configurable_Setter(void *clientData,
Tcl_Interp *interp, Tcl_ObjectContext context,
int objc, Tcl_Obj *const *objv);
static void DetailsDeleter(void *clientData);
static int DetailsCloner(Tcl_Interp *, void *oldClientData,
void **newClientData);
static Tcl_Obj *GetAllObjectProperties(Object *oPtr,
int writable);
static void ImplementObjectProperty(Tcl_Object targetObject,
Tcl_Obj *propNamePtr, int installGetter,
int installSetter);
static void ImplementClassProperty(Tcl_Class targetObject,
Tcl_Obj *propNamePtr, int installGetter,
int installSetter);
/*
* Method descriptors
*/
static const Tcl_MethodType GetterType = {
TCL_OO_METHOD_VERSION_1,
"PropertyGetter",
Configurable_Getter,
DetailsDeleter,
DetailsCloner
};
static const Tcl_MethodType SetterType = {
TCL_OO_METHOD_VERSION_1,
"PropertySetter",
Configurable_Setter,
DetailsDeleter,
DetailsCloner
};
/*
* ----------------------------------------------------------------------
*
* TclOO_Configurable_Configure --
*
* Implementation of the oo::configurable->configure method.
*
* ----------------------------------------------------------------------
*/
/*
* Ugly thunks to read and write a property by calling the right method in
* the right way. Note that we MUST be correct in holding references to Tcl_Obj
* values, as this is potentially a call into user code.
*/
static inline int
ReadProperty(
Tcl_Interp *interp,
Object *oPtr,
const char *propName)
{
Tcl_Obj *args[] = {
oPtr->fPtr->myName,
Tcl_ObjPrintf("<ReadProp%s>", propName)
};
int code;
Tcl_IncrRefCount(args[0]);
Tcl_IncrRefCount(args[1]);
code = TclOOPrivateObjectCmd(oPtr, interp, 2, args);
Tcl_DecrRefCount(args[0]);
Tcl_DecrRefCount(args[1]);
switch (code) {
case TCL_BREAK:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"property getter for %s did a break", propName));
return TCL_ERROR;
case TCL_CONTINUE:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"property getter for %s did a continue", propName));
return TCL_ERROR;
default:
return code;
}
}
static inline int
WriteProperty(
Tcl_Interp *interp,
Object *oPtr,
const char *propName,
Tcl_Obj *valueObj)
{
Tcl_Obj *args[] = {
oPtr->fPtr->myName,
Tcl_ObjPrintf("<WriteProp%s>", propName),
valueObj
};
int code;
Tcl_IncrRefCount(args[0]);
Tcl_IncrRefCount(args[1]);
Tcl_IncrRefCount(args[2]);
code = TclOOPrivateObjectCmd(oPtr, interp, 3, args);
Tcl_DecrRefCount(args[0]);
Tcl_DecrRefCount(args[1]);
Tcl_DecrRefCount(args[2]);
switch (code) {
case TCL_BREAK:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"property setter for %s did a break", propName));
return TCL_ERROR;
case TCL_CONTINUE:
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"property setter for %s did a continue", propName));
return TCL_ERROR;
default:
return code;
}
}
/* Look up a property full name. */
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 |
Tcl_Obj *namePtr, /* The name supplied by the user. */
GPNCache **cachePtr) /* Where to cache the table, if the caller
* wants that. The contents are to be freed
* with Tcl_Free if the cache is used. */
{
Tcl_Size objc, index, i;
Tcl_Obj *listPtr = GetAllObjectProperties(
| | | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
Tcl_Obj *namePtr, /* The name supplied by the user. */
GPNCache **cachePtr) /* Where to cache the table, if the caller
* wants that. The contents are to be freed
* with Tcl_Free if the cache is used. */
{
Tcl_Size objc, index, i;
Tcl_Obj *listPtr = GetAllObjectProperties(
oPtr, flags & GPN_WRITABLE);
Tcl_Obj **objv;
GPNCache *tablePtr;
(void) Tcl_ListObjGetElements(NULL, listPtr, &objc, &objv);
if (cachePtr && *cachePtr) {
tablePtr = *cachePtr;
} else {
tablePtr = (GPNCache *) TclStackAlloc(interp,
offsetof(GPNCache, names) + sizeof(char *) * (objc + 1));
for (i = 0; i < objc; i++) {
tablePtr->names[i] = TclGetString(objv[i]);
}
tablePtr->names[objc] = NULL;
if (cachePtr) {
/*
|
| ︙ | ︙ | |||
362 363 364 365 366 367 368 |
int
TclOO_Configurable_Configure(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter used for the result, error
* reporting, etc. */
Tcl_ObjectContext context, /* The object/call context. */
| | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
int
TclOO_Configurable_Configure(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter used for the result, error
* reporting, etc. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Object *oPtr = (Object *) Tcl_ObjectContextObject(context);
Tcl_Size skip = Tcl_ObjectContextSkippedArgs(context);
Tcl_Obj *namePtr;
Tcl_Size i, namec;
int code = TCL_OK;
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 |
objv += skip;
if (objc == 0) {
/*
* Read all properties.
*/
| | | | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
objv += skip;
if (objc == 0) {
/*
* Read all properties.
*/
Tcl_Obj *listPtr = GetAllObjectProperties(oPtr, 0);
Tcl_Obj *resultPtr = Tcl_NewObj(), **namev;
Tcl_IncrRefCount(listPtr);
ListObjGetElements(listPtr, namec, namev);
for (i = 0; i < namec; ) {
code = ReadProperty(interp, oPtr, TclGetString(namev[i]));
if (code != TCL_OK) {
Tcl_DecrRefCount(resultPtr);
break;
}
Tcl_DictObjPut(NULL, resultPtr, namev[i],
Tcl_GetObjResult(interp));
if (++i >= namec) {
|
| ︙ | ︙ | |||
418 419 420 421 422 423 424 |
* Read a single named property.
*/
namePtr = GetPropertyName(interp, oPtr, 0, objv[0], NULL);
if (namePtr == NULL) {
return TCL_ERROR;
}
| | | | > | | | | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
* Read a single named property.
*/
namePtr = GetPropertyName(interp, oPtr, 0, objv[0], NULL);
if (namePtr == NULL) {
return TCL_ERROR;
}
return ReadProperty(interp, oPtr, TclGetString(namePtr));
} else if (objc == 2) {
/*
* Special case for writing to one property. Saves fiddling with the
* cache in this common case.
*/
namePtr = GetPropertyName(interp, oPtr, GPN_WRITABLE, objv[0], NULL);
if (namePtr == NULL) {
return TCL_ERROR;
}
code = WriteProperty(interp, oPtr, TclGetString(namePtr), objv[1]);
if (code == TCL_OK) {
Tcl_ResetResult(interp);
}
return code;
} else {
/*
* Write properties. Slightly tricky because we want to cache the
* table of property names.
*/
GPNCache *cache = NULL;
code = TCL_OK;
for (i = 0; i < objc; i += 2) {
namePtr = GetPropertyName(interp, oPtr, GPN_WRITABLE, objv[i],
&cache);
if (namePtr == NULL) {
code = TCL_ERROR;
break;
}
code = WriteProperty(interp, oPtr, TclGetString(namePtr),
objv[i + 1]);
if (code != TCL_OK) {
break;
}
}
if (code == TCL_OK) {
Tcl_ResetResult(interp);
}
ReleasePropertyNameCache(interp, &cache);
return code;
}
}
/*
* ----------------------------------------------------------------------
*
* Configurable_Getter, Configurable_Setter --
*
* Standard property implementation. The clientData is a simple Tcl_Obj*
* that contains the name of the property.
*
* ----------------------------------------------------------------------
*/
static int
Configurable_Getter(
void *clientData, /* Which property to read. Actually a Tcl_Obj*
* reference that is the name of the variable
* in the cpntext object. */
Tcl_Interp *interp, /* Interpreter used for the result, error
* reporting, etc. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Tcl_Obj *propNamePtr = (Tcl_Obj *) clientData;
Tcl_Var varPtr, aryVar;
Tcl_Obj *valuePtr;
if (Tcl_ObjectContextSkippedArgs(context) != objc) {
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 |
}
Tcl_SetObjResult(interp, valuePtr);
return TCL_OK;
}
static int
Configurable_Setter(
| | | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 |
}
Tcl_SetObjResult(interp, valuePtr);
return TCL_OK;
}
static int
Configurable_Setter(
void *clientData, /* Which property to write. Actually a Tcl_Obj*
* reference that is the name of the variable
* in the cpntext object. */
Tcl_Interp *interp, /* Interpreter used for the result, error
* reporting, etc. */
Tcl_ObjectContext context, /* The object/call context. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The actual arguments. */
{
Tcl_Obj *propNamePtr = (Tcl_Obj *) clientData;
Tcl_Var varPtr, aryVar;
if (Tcl_ObjectContextSkippedArgs(context) + 1 != objc) {
Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context),
|
| ︙ | ︙ | |||
581 582 583 584 585 586 587 |
* ----------------------------------------------------------------------
*/
void
ImplementObjectProperty(
Tcl_Object targetObject, /* What to install into. */
Tcl_Obj *propNamePtr, /* Property name. */
| | | | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
* ----------------------------------------------------------------------
*/
void
ImplementObjectProperty(
Tcl_Object targetObject, /* What to install into. */
Tcl_Obj *propNamePtr, /* Property name. */
int installGetter, /* Whether to install a standard getter. */
int installSetter) /* Whether to install a standard setter. */
{
const char *propName = TclGetString(propNamePtr);
while (propName[0] == '-') {
propName++;
}
if (installGetter) {
|
| ︙ | ︙ | |||
609 610 611 612 613 614 615 |
}
}
void
ImplementClassProperty(
Tcl_Class targetClass, /* What to install into. */
Tcl_Obj *propNamePtr, /* Property name. */
| | | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 |
}
}
void
ImplementClassProperty(
Tcl_Class targetClass, /* What to install into. */
Tcl_Obj *propNamePtr, /* Property name. */
int installGetter, /* Whether to install a standard getter. */
int installSetter) /* Whether to install a standard setter. */
{
const char *propName = TclGetString(propNamePtr);
while (propName[0] == '-') {
propName++;
}
if (installGetter) {
|
| ︙ | ︙ | |||
642 643 644 645 646 647 648 649 650 651 |
*
* Discover the properties known to a class and its superclasses.
* The property names become the keys in the accumulator hash table
* (which is used as a set).
*
* ----------------------------------------------------------------------
*/
static void
FindClassProps(
Class *clsPtr, /* The object to inspect. Must exist. */
| > | | | | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
*
* Discover the properties known to a class and its superclasses.
* The property names become the keys in the accumulator hash table
* (which is used as a set).
*
* ----------------------------------------------------------------------
*/
static void
FindClassProps(
Class *clsPtr, /* The object to inspect. Must exist. */
int writable, /* Whether we're after the readable or writable
* property set. */
Tcl_HashTable *accumulator) /* Where to gather the names. */
{
int i, dummy;
Tcl_Obj *propName;
Class *mixin, *sup;
tailRecurse:
if (writable) {
FOREACH(propName, clsPtr->properties.writable) {
Tcl_CreateHashEntry(accumulator, propName, &dummy);
}
} else {
FOREACH(propName, clsPtr->properties.readable) {
Tcl_CreateHashEntry(accumulator, propName, &dummy);
}
}
if (clsPtr->thisPtr->flags & ROOT_OBJECT) {
/*
* We do *not* traverse upwards from the root!
*/
return;
|
| ︙ | ︙ | |||
692 693 694 695 696 697 698 699 700 701 |
*
* Discover the properties known to an object and all its classes.
* The property names become the keys in the accumulator hash table
* (which is used as a set).
*
* ----------------------------------------------------------------------
*/
static void
FindObjectProps(
Object *oPtr, /* The object to inspect. Must exist. */
| > | | | | > | 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 |
*
* Discover the properties known to an object and all its classes.
* The property names become the keys in the accumulator hash table
* (which is used as a set).
*
* ----------------------------------------------------------------------
*/
static void
FindObjectProps(
Object *oPtr, /* The object to inspect. Must exist. */
int writable, /* Whether we're after the readable or writable
* property set. */
Tcl_HashTable *accumulator) /* Where to gather the names. */
{
int i, dummy;
Tcl_Obj *propName;
Class *mixin;
if (writable) {
FOREACH(propName, oPtr->properties.writable) {
Tcl_CreateHashEntry(accumulator, propName, &dummy);
}
} else {
FOREACH(propName, oPtr->properties.readable) {
Tcl_CreateHashEntry(accumulator, propName, &dummy);
}
}
FOREACH(mixin, oPtr->mixins) {
FindClassProps(mixin, writable, accumulator);
}
FindClassProps(oPtr->selfCls, writable, accumulator);
}
/*
* ----------------------------------------------------------------------
*
* GetAllClassProperties --
*
* Get the list of all properties known to a class, including to its
* superclasses. Manages a cache so this operation is usually cheap.
* The order of properties in the resulting list is undefined.
*
* ----------------------------------------------------------------------
*/
static Tcl_Obj *
GetAllClassProperties(
Class *clsPtr, /* The class to inspect. Must exist. */
bool writable, /* Whether to get writable properties. If
* false, readable properties will be returned
* instead. */
bool *allocated) /* Address of variable to set to true if a
|
| ︙ | ︙ | |||
802 803 804 805 806 807 808 |
return result;
}
/*
* ----------------------------------------------------------------------
*
* SortPropList --
| < | 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
return result;
}
/*
* ----------------------------------------------------------------------
*
* SortPropList --
* Sort a list of names of properties. Simple support function. Assumes
* that the list Tcl_Obj is unshared and doesn't have a string
* representation.
*
* ----------------------------------------------------------------------
*/
|
| ︙ | ︙ | |||
833 834 835 836 837 838 839 |
Tcl_Obj **ev;
if (Tcl_IsShared(list)) {
Tcl_Panic("shared property list cannot be sorted");
}
Tcl_ListObjGetElements(NULL, list, &ec, &ev);
TclInvalidateStringRep(list);
| | | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 |
Tcl_Obj **ev;
if (Tcl_IsShared(list)) {
Tcl_Panic("shared property list cannot be sorted");
}
Tcl_ListObjGetElements(NULL, list, &ec, &ev);
TclInvalidateStringRep(list);
qsort(ev, ec, sizeof(Tcl_Obj *), PropNameCompare);
}
/*
* ----------------------------------------------------------------------
*
* GetAllObjectProperties --
*
* Get the sorted list of all properties known to an object, including to
* its classes. Manages a cache so this operation is usually cheap.
*
* ----------------------------------------------------------------------
*/
Tcl_Obj *
GetAllObjectProperties(
Object *oPtr, /* The object to inspect. Must exist. */
int writable) /* Whether to get writable properties. If
* false, readable properties will be returned
* instead. */
{
Tcl_HashTable hashTable;
FOREACH_HASH_DECLS;
Tcl_Obj *propName, *result;
|
| ︙ | ︙ | |||
925 926 927 928 929 930 931 |
* ----------------------------------------------------------------------
*/
static inline void
SetPropertyList(
PropertyList *propList, /* The property list to write. Replaces the
* property list's contents. */
Tcl_Size objc, /* Number of property names. */
| | | | | | | | | | 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 |
* ----------------------------------------------------------------------
*/
static inline void
SetPropertyList(
PropertyList *propList, /* The property list to write. Replaces the
* property list's contents. */
Tcl_Size objc, /* Number of property names. */
Tcl_Obj *const objv[]) /* Property names. */
{
Tcl_Size i, n;
Tcl_Obj *propObj;
int created;
Tcl_HashTable uniqueTable;
for (i=0 ; i<objc ; i++) {
Tcl_IncrRefCount(objv[i]);
}
FOREACH(propObj, *propList) {
Tcl_DecrRefCount(propObj);
}
if (i != objc) {
if (objc == 0) {
Tcl_Free(propList->list);
} else if (i) {
propList->list = (Tcl_Obj **)
Tcl_Realloc(propList->list, sizeof(Tcl_Obj *) * objc);
} else {
propList->list = (Tcl_Obj **)
Tcl_Alloc(sizeof(Tcl_Obj *) * objc);
}
}
propList->num = 0;
if (objc > 0) {
Tcl_InitObjHashTable(&uniqueTable);
for (i=n=0 ; i<objc ; i++) {
Tcl_CreateHashEntry(&uniqueTable, objv[i], &created);
if (created) {
propList->list[n++] = objv[i];
} else {
Tcl_DecrRefCount(objv[i]);
}
}
propList->num = n;
/*
* Shouldn't be necessary, but maintain num/list invariant.
*/
if (n != objc) {
propList->list = (Tcl_Obj **)
Tcl_Realloc(propList->list, sizeof(Tcl_Obj *) * n);
}
Tcl_DeleteHashTable(&uniqueTable);
}
}
/*
* ----------------------------------------------------------------------
*
* TclOOInstallReadableProperties --
*
* Helper for writing the readable property list (which is actually a set)
* that includes flushing the name cache.
*
* ----------------------------------------------------------------------
*/
void
TclOOInstallReadableProperties(
PropertyStorage *props, /* Which property list to install into. */
Tcl_Size objc, /* Number of property names. */
Tcl_Obj *const objv[]) /* Property names. */
{
if (props->allReadableCache) {
Tcl_DecrRefCount(props->allReadableCache);
props->allReadableCache = NULL;
}
SetPropertyList(&props->readable, objc, objv);
|
| ︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 |
*
* ----------------------------------------------------------------------
*/
void
TclOOInstallWritableProperties(
PropertyStorage *props, /* Which property list to install into. */
Tcl_Size objc, /* Number of property names. */
| | | 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
*
* ----------------------------------------------------------------------
*/
void
TclOOInstallWritableProperties(
PropertyStorage *props, /* Which property list to install into. */
Tcl_Size objc, /* Number of property names. */
Tcl_Obj *const objv[]) /* Property names. */
{
if (props->allWritableCache) {
Tcl_DecrRefCount(props->allWritableCache);
props->allWritableCache = NULL;
}
SetPropertyList(&props->writable, objc, objv);
|
| ︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 |
* ----------------------------------------------------------------------
*/
static int
InstallStdPropertyImpls(
void *useInstance,
Tcl_Interp *interp,
Tcl_Obj *propName,
| | | | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 |
* ----------------------------------------------------------------------
*/
static int
InstallStdPropertyImpls(
void *useInstance,
Tcl_Interp *interp,
Tcl_Obj *propName,
int readable,
int writable)
{
const char *name, *reason;
Tcl_Size len;
char flag = TCL_DONT_QUOTE_HASH;
/*
* Validate the property name. Note that just calling TclScanElement() is
|
| ︙ | ︙ | |||
1134 1135 1136 1137 1138 1139 1140 |
* ----------------------------------------------------------------------
*/
int
TclOODefinePropertyCmd(
void *useInstance, /* NULL for class, non-NULL for object. */
Tcl_Interp *interp, /* For error reporting and lookup. */
| | | | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 |
* ----------------------------------------------------------------------
*/
int
TclOODefinePropertyCmd(
void *useInstance, /* NULL for class, non-NULL for object. */
Tcl_Interp *interp, /* For error reporting and lookup. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
int i;
static const char *const options[] = {
"-get", "-kind", "-set", NULL
};
enum Options {
OPT_GET, OPT_KIND, OPT_SET
};
static const char *const kinds[] = {
|
| ︙ | ︙ | |||
1299 1300 1301 1302 1303 1304 1305 |
* ----------------------------------------------------------------------
*/
int
TclOOInfoClassPropCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 |
* ----------------------------------------------------------------------
*/
int
TclOOInfoClassPropCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Class *clsPtr;
int i;
int idx;
bool all = false, writable = false, allocated = false;
Tcl_Obj *result;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "className ?options...?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
1361 1362 1363 1364 1365 1366 1367 |
return TCL_OK;
}
int
TclOOInfoObjectPropCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 |
return TCL_OK;
}
int
TclOOInfoObjectPropCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Object *oPtr;
int i;
bool all = false, writable = false;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "objName ?options...?");
return TCL_ERROR;
}
oPtr = (Object *) Tcl_GetObjectFromObj(interp, objv[1]);
|
| ︙ | ︙ |
Changes to generic/tclOOStubInit.c.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 | MODULE_SCOPE const TclOOStubs tclOOStubs; #ifdef __GNUC__ #pragma GCC dependency "tclOO.decls" #endif | < < < < < < < < < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
MODULE_SCOPE const TclOOStubs tclOOStubs;
#ifdef __GNUC__
#pragma GCC dependency "tclOO.decls"
#endif
/* !BEGIN!: Do not edit below this line. */
static const TclOOIntStubs tclOOIntStubs = {
TCL_STUB_MAGIC,
0,
TclOOGetDefineCmdContext, /* 0 */
TclOOMakeProcInstanceMethod, /* 1 */
|
| ︙ | ︙ |
Changes to generic/tclOOStubLib.c.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 | const TclOOStubs *tclOOStubsPtr = NULL; const TclOOIntStubs *tclOOIntStubsPtr = NULL; /* *---------------------------------------------------------------------- * * TclOOInitializeStubs -- | < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | const TclOOStubs *tclOOStubsPtr = NULL; const TclOOIntStubs *tclOOIntStubsPtr = NULL; /* *---------------------------------------------------------------------- * * TclOOInitializeStubs -- * Load the tclOO package, initialize stub table pointer. Do not call * this function directly, use Tcl_OOInitStubs() macro instead. * * Results: * The actual version of the package that satisfies the request, or NULL * to indicate that an error occurred. * |
| ︙ | ︙ |
Changes to generic/tclObj.c.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 |
* one instance of this structure for each thread.
*
* Notice that different structures with the same name appear in other files.
* The structure defined below is used in this file only.
*/
typedef struct {
| | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
* one instance of this structure for each thread.
*
* Notice that different structures with the same name appear in other files.
* The structure defined below is used in this file only.
*/
typedef struct {
Tcl_HashTable *lineCLPtr; /* This table remembers for each Tcl_Obj
* generated by a call to the function
* TclSubstTokens() from a literal text
* where bs+nl sequences occurred in it, if
* any. I.e. this table keeps track of
* invisible and stripped continuation lines.
* Its keys are Tcl_Obj pointers, the values
* are ContLineLoc pointers. See the file
* tclCompile.h for the definition of this
* structure, and for references to all
* related places in the core. */
#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. */
#endif /* TCL_MEM_DEBUG && TCL_THREADS */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
static void TclThreadFinalizeContLines(void *clientData);
static ThreadSpecificData *TclGetContLineTable(void);
/*
* Nested Tcl_Obj deletion management support
*
* All context references used in the object freeing code are pointers to this
* structure; every thread will have its own structure instance. The purpose
|
| ︙ | ︙ | |||
140 141 142 143 144 145 146 | * These are separated out so that some semantic content is attached * to them. */ #define ObjDeletionLock(contextPtr) ((contextPtr)->deletionCount++) #define ObjDeletionUnlock(contextPtr) ((contextPtr)->deletionCount--) #define ObjDeletePending(contextPtr) ((contextPtr)->deletionCount > 0) #define ObjOnStack(contextPtr) ((contextPtr)->deletionStack != NULL) | | | | | | | | | | | | | | | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
* These are separated out so that some semantic content is attached
* to them.
*/
#define ObjDeletionLock(contextPtr) ((contextPtr)->deletionCount++)
#define ObjDeletionUnlock(contextPtr) ((contextPtr)->deletionCount--)
#define ObjDeletePending(contextPtr) ((contextPtr)->deletionCount > 0)
#define ObjOnStack(contextPtr) ((contextPtr)->deletionStack != NULL)
#define PushObjToDelete(contextPtr,objPtr) \
/* The string rep is already invalidated so we can use the bytes value \
* for our pointer chain: push onto the head of the stack. */ \
(objPtr)->bytes = (char *) ((contextPtr)->deletionStack); \
(contextPtr)->deletionStack = (objPtr)
#define PopObjToDelete(contextPtr,objPtrVar) \
(objPtrVar) = (contextPtr)->deletionStack; \
(contextPtr)->deletionStack = (Tcl_Obj *) (objPtrVar)->bytes
/*
* Macro to set up the local reference to the deletion context.
*/
#if !TCL_THREADS
static PendingObjData pendingObjData;
#define ObjInitDeletionContext(contextPtr) \
PendingObjData *const contextPtr = &pendingObjData
#elif defined(HAVE_FAST_TSD)
static __thread PendingObjData pendingObjData;
#define ObjInitDeletionContext(contextPtr) \
PendingObjData *const contextPtr = &pendingObjData
#else
static Tcl_ThreadDataKey pendingObjDataKey;
#define ObjInitDeletionContext(contextPtr) \
PendingObjData *const contextPtr = \
(PendingObjData *)Tcl_GetThreadData(&pendingObjDataKey, sizeof(PendingObjData))
#endif
/*
* Macros to pack/unpack a bignum's fields in a Tcl_Obj internal rep
*/
#define PACK_BIGNUM(bignum, objPtr) \
if ((bignum).used > 0x7FFF) { \
mp_int *temp = (mp_int *)Tcl_Alloc(sizeof(mp_int)); \
*temp = bignum; \
(objPtr)->internalRep.twoPtrValue.ptr1 = temp; \
(objPtr)->internalRep.twoPtrValue.ptr2 = INT2PTR(-1); \
} else if (((bignum).alloc <= 0x7FFF) || (mp_shrink(&(bignum))) == MP_OKAY) { \
(objPtr)->internalRep.twoPtrValue.ptr1 = (bignum).dp; \
(objPtr)->internalRep.twoPtrValue.ptr2 = INT2PTR(((bignum).sign << 30) \
| ((bignum).alloc << 15) | ((bignum).used)); \
}
/*
* Prototypes for functions defined later in this file:
*/
static int ParseBoolean(Tcl_Obj *objPtr);
|
| ︙ | ︙ | |||
221 222 223 224 225 226 227 |
* The structures below defines the Tcl object types defined in this file by
* means of functions that can be invoked by generic object code. See also
* tclStringObj.c, tclListObj.c, tclByteCode.c for other type manager
* implementations.
*/
const Tcl_ObjType tclBooleanType= {
| | | | | | | | | | | | | | | | | | | | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
* The structures below defines the Tcl object types defined in this file by
* means of functions that can be invoked by generic object code. See also
* tclStringObj.c, tclListObj.c, tclByteCode.c for other type manager
* implementations.
*/
const Tcl_ObjType tclBooleanType= {
"boolean", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
TclSetBooleanFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V1(TclLengthOne)
};
const Tcl_ObjType tclDoubleType= {
"double", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
UpdateStringOfDouble, /* updateStringProc */
SetDoubleFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V1(TclLengthOne)
};
const Tcl_ObjType tclIntType = {
"int", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
UpdateStringOfInt, /* updateStringProc */
SetIntFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V1(TclLengthOne)
};
const Tcl_ObjType tclBignumType = {
"bignum", /* name */
FreeBignum, /* freeIntRepProc */
DupBignum, /* dupIntRepProc */
UpdateStringOfBignum, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V1(TclLengthOne)
};
/*
* The structure below defines the Tcl obj hash key type.
*/
|
| ︙ | ︙ | |||
290 291 292 293 294 295 296 |
* is fragile but useful given their somewhat-OO style. Because of this, this
* structure MUST NOT be const so that the C compiler puts the data in
* writable memory. [Bug 2558422] [Bug 07d13d99b0a9]
* TODO: Provide a better API for those extensions so that they can coexist...
*/
Tcl_ObjType tclCmdNameType = {
| | | | | | | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
* is fragile but useful given their somewhat-OO style. Because of this, this
* structure MUST NOT be const so that the C compiler puts the data in
* writable memory. [Bug 2558422] [Bug 07d13d99b0a9]
* TODO: Provide a better API for those extensions so that they can coexist...
*/
Tcl_ObjType tclCmdNameType = {
"cmdName", /* name */
FreeCmdNameInternalRep, /* freeIntRepProc */
DupCmdNameInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
SetCmdNameFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
/*
* Structure containing a cached pointer to a command that is the result of
* resolving the command's name in some namespace. It is the internal
* representation for a cmdName object. It contains the pointer along with
|
| ︙ | ︙ | |||
482 483 484 485 486 487 488 | /* *---------------------------------------------------------------------- * * TclGetContLineTable -- * * This procedure is a helper which returns the thread-specific * hash-table used to track continuation line information associated with | | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | /* *---------------------------------------------------------------------- * * TclGetContLineTable -- * * This procedure is a helper which returns the thread-specific * hash-table used to track continuation line information associated with * Tcl_Obj*, and the objThreadMap, etc. * * Results: * A reference to the thread-data. * * Side effects: * May allocate memory for the thread-data. * |
| ︙ | ︙ | |||
521 522 523 524 525 526 527 | /* *---------------------------------------------------------------------- * * TclContinuationsEnter -- * * This procedure is a helper which saves the continuation line | | | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | /* *---------------------------------------------------------------------- * * TclContinuationsEnter -- * * This procedure is a helper which saves the continuation line * information associated with a Tcl_Obj*. * * Results: * A reference to the newly created continuation line location table. * * Side effects: * Allocates memory for the table of continuation line locations. * |
| ︙ | ︙ | |||
543 544 545 546 547 548 549 |
Tcl_Size num,
Tcl_Size *loc)
{
int newEntry;
ThreadSpecificData *tsdPtr = TclGetContLineTable();
Tcl_HashEntry *hPtr =
Tcl_CreateHashEntry(tsdPtr->lineCLPtr, objPtr, &newEntry);
| | < | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 |
Tcl_Size num,
Tcl_Size *loc)
{
int newEntry;
ThreadSpecificData *tsdPtr = TclGetContLineTable();
Tcl_HashEntry *hPtr =
Tcl_CreateHashEntry(tsdPtr->lineCLPtr, objPtr, &newEntry);
ContLineLoc *clLocPtr = (ContLineLoc *)Tcl_Alloc(offsetof(ContLineLoc, loc) + (num + 1U) *sizeof(Tcl_Size));
if (!newEntry) {
/*
* We're entering ContLineLoc data for the same value more than one
* time. Taking care not to leak the old entry.
*
* This can happen when literals in a proc body are shared. See for
|
| ︙ | ︙ | |||
573 574 575 576 577 578 579 |
*/
Tcl_Free(Tcl_GetHashValue(hPtr));
}
clLocPtr->num = num;
memcpy(&clLocPtr->loc, loc, num*sizeof(Tcl_Size));
| | | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
*/
Tcl_Free(Tcl_GetHashValue(hPtr));
}
clLocPtr->num = num;
memcpy(&clLocPtr->loc, loc, num*sizeof(Tcl_Size));
clLocPtr->loc[num] = CLL_END; /* Sentinel */
Tcl_SetHashValue(hPtr, clLocPtr);
return clLocPtr;
}
/*
*----------------------------------------------------------------------
*
* TclContinuationsEnterDerived --
*
* This procedure is a helper which computes the continuation line
* information associated with a Tcl_Obj* cut from the middle of a
* script.
*
* Results:
* None.
*
* Side effects:
* Allocates memory for the table of continuation line locations.
|
| ︙ | ︙ | |||
633 634 635 636 637 638 639 |
/*
* First compute the range of the word within the script. (Is there a
* better way which doesn't shimmer?)
*/
(void)TclGetStringFromObj(objPtr, &length);
| | | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 |
/*
* First compute the range of the word within the script. (Is there a
* better way which doesn't shimmer?)
*/
(void)TclGetStringFromObj(objPtr, &length);
end = start + length; /* First char after the word */
/*
* Then compute the table slice covering the range of the word.
*/
while (*wordCLLast >= 0 && *wordCLLast < end) {
wordCLLast++;
|
| ︙ | ︙ | |||
678 679 680 681 682 683 684 | /* *---------------------------------------------------------------------- * * TclContinuationsCopy -- * * This procedure is a helper which copies the continuation line | | | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 | /* *---------------------------------------------------------------------- * * TclContinuationsCopy -- * * This procedure is a helper which copies the continuation line * information associated with a Tcl_Obj* to another Tcl_Obj*. It is * assumed that both contain the same string/script. Use this when a * script is duplicated because it was shared. * * Results: * None. * * Side effects: |
| ︙ | ︙ | |||
714 715 716 717 718 719 720 | /* *---------------------------------------------------------------------- * * TclContinuationsGet -- * * This procedure is a helper which retrieves the continuation line | | | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 | /* *---------------------------------------------------------------------- * * TclContinuationsGet -- * * This procedure is a helper which retrieves the continuation line * information associated with a Tcl_Obj*, if it has any. * * Results: * A reference to the continuation line location table, or NULL if the * Tcl_Obj* has no such information associated with it. * * Side effects: * None. * * TIP #280 *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
806 807 808 809 810 811 812 813 814 |
void
Tcl_RegisterObjType(
const Tcl_ObjType *typePtr) /* Information about object type; storage must
* be statically allocated (must live
* forever). */
{
Tcl_MutexLock(&tableMutex);
Tcl_SetHashValue(
| > > | | 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 |
void
Tcl_RegisterObjType(
const Tcl_ObjType *typePtr) /* Information about object type; storage must
* be statically allocated (must live
* forever). */
{
int isNew;
Tcl_MutexLock(&tableMutex);
Tcl_SetHashValue(
Tcl_CreateHashEntry(&typeTable, typePtr->name, &isNew), typePtr);
Tcl_MutexUnlock(&tableMutex);
}
/*
*----------------------------------------------------------------------
*
* Tcl_AppendAllObjTypes --
|
| ︙ | ︙ | |||
1028 1029 1030 1031 1032 1033 1034 |
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
void
TclDbInitNewObj(
Tcl_Obj *objPtr,
| | | > | | | < < < < | < | 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 |
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
void
TclDbInitNewObj(
Tcl_Obj *objPtr,
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
{
objPtr->refCount = 0;
objPtr->typePtr = NULL;
TclInitEmptyStringRep(objPtr);
#if TCL_THREADS
/*
* Add entry to a thread local map used to check if a Tcl_Obj was
* allocated by the currently executing thread.
*/
if (!TclInExit()) {
Tcl_HashEntry *hPtr;
Tcl_HashTable *tablePtr;
int isNew;
ObjData *objData;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (tsdPtr->objThreadMap == NULL) {
tsdPtr->objThreadMap = (Tcl_HashTable *)Tcl_Alloc(sizeof(Tcl_HashTable));
Tcl_InitHashTable(tsdPtr->objThreadMap, TCL_ONE_WORD_KEYS);
}
tablePtr = tsdPtr->objThreadMap;
hPtr = Tcl_CreateHashEntry(tablePtr, objPtr, &isNew);
if (!isNew) {
Tcl_Panic("expected to create new entry for object map");
}
/*
* Record the debugging information.
*/
objData = (ObjData *)Tcl_Alloc(sizeof(ObjData));
objData->objPtr = objPtr;
objData->file = file;
objData->line = line;
Tcl_SetHashValue(hPtr, objData);
}
#endif /* TCL_THREADS */
}
#endif /* TCL_MEM_DEBUG */
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewObj( | | | | 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 |
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
Tcl_Obj *
Tcl_DbNewObj(
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
{
Tcl_Obj *objPtr;
/*
* Use the macro defined in tclInt.h - it will use the correct allocator.
*/
|
| ︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 | * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG void TclFreeObj( | | | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 |
*
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
void
TclFreeObj(
Tcl_Obj *objPtr) /* The object to be freed. */
{
const Tcl_ObjType *typePtr = objPtr->typePtr;
/*
* This macro declares a variable, so must come here...
*/
|
| ︙ | ︙ | |||
1291 1292 1293 1294 1295 1296 1297 |
if (!TclInExit()) {
Tcl_HashTable *tablePtr;
Tcl_HashEntry *hPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tablePtr = tsdPtr->objThreadMap;
if (!tablePtr) {
| | | 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 |
if (!TclInExit()) {
Tcl_HashTable *tablePtr;
Tcl_HashEntry *hPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tablePtr = tsdPtr->objThreadMap;
if (!tablePtr) {
Tcl_Panic("TclFreeObj: object table not initialized");
}
hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
if (hPtr) {
/*
* As the Tcl_Obj is going to be deleted we remove the entry.
*/
|
| ︙ | ︙ | |||
1392 1393 1394 1395 1396 1397 1398 |
}
}
}
#else /* TCL_MEM_DEBUG */
void
TclFreeObj(
| | | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 |
}
}
}
#else /* TCL_MEM_DEBUG */
void
TclFreeObj(
Tcl_Obj *objPtr) /* The object to be freed. */
{
/*
* Invalidate the string rep first so we can use the bytes value for our
* pointer chain, and signal an obj deletion (as opposed to shimmering)
* with 'length == -1'.
*/
|
| ︙ | ︙ | |||
1503 1504 1505 1506 1507 1508 1509 |
*----------------------------------------------------------------------
*/
int
TclObjBeingDeleted(
Tcl_Obj *objPtr)
{
| | | 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 |
*----------------------------------------------------------------------
*/
int
TclObjBeingDeleted(
Tcl_Obj *objPtr)
{
return (objPtr->length == TCL_INDEX_NONE);
}
/*
*----------------------------------------------------------------------
*
* Tcl_DuplicateObj --
*
|
| ︙ | ︙ | |||
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 |
TclFreeInternalRep(dupPtr);
SetDuplicateObj(dupPtr, objPtr);
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetStringFromObj/TclGetStringFromObj --
*
* Returns the string representation's byte array pointer and length for
* an object.
*
* Results:
* Returns a pointer to the string representation of objPtr. If lengthPtr
* isn't NULL, the length of the string representation is stored at
* *lengthPtr. The byte array referenced by the returned pointer must not
* be modified by the caller. Furthermore, the caller must copy the bytes
* if they need to retain them since the object's string rep can change
* as a result of other operations.
*
* Side effects:
* May call the object's updateStringProc to update the string
* representation from the internal representation.
*
*----------------------------------------------------------------------
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 |
TclFreeInternalRep(dupPtr);
SetDuplicateObj(dupPtr, objPtr);
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetString --
*
* Returns the string representation byte array pointer for an object.
*
* Results:
* Returns a pointer to the string representation of objPtr. The byte
* array referenced by the returned pointer must not be modified by the
* caller. Furthermore, the caller must copy the bytes if they need to
* retain them since the object's string rep can change as a result of
* other operations.
*
* Side effects:
* May call the object's updateStringProc to update the string
* representation from the internal representation.
*
*----------------------------------------------------------------------
*/
#undef Tcl_GetString
char *
Tcl_GetString(
Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
* be returned. */
{
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 == TCL_INDEX_NONE
|| objPtr->bytes[objPtr->length] != '\0') {
Tcl_Panic("UpdateStringProc for type '%s' "
"failed to create a valid string rep",
objPtr->typePtr->name);
}
}
return objPtr->bytes;
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetStringFromObj/TclGetStringFromObj --
*
* Returns the string representation's byte array pointer and length for
* an object.
*
* Results:
* Returns a pointer to the string representation of objPtr. If lengthPtr
* isn't NULL, the length of the string representation is stored at
* *lengthPtr. The byte array referenced by the returned pointer must not
* be modified by the caller. Furthermore, the caller must copy the bytes
* if they need to retain them since the object's string rep can change
* as a result of other operations.
*
* Side effects:
* May call the object's updateStringProc to update the string
* representation from the internal representation.
*
*----------------------------------------------------------------------
*/
#if !defined(TCL_NO_DEPRECATED)
#undef TclGetStringFromObj
char *
TclGetStringFromObj(
Tcl_Obj *objPtr, /* Object whose string rep byte pointer should
* be returned. */
void *lengthPtr) /* If non-NULL, the location where the string
* rep's byte array length should * be stored.
* If NULL, no length is stored. */
{
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
|
| ︙ | ︙ | |||
1645 1646 1647 1648 1649 1650 1651 |
Tcl_Panic("Tcl_GetStringFromObj with 'int' lengthPtr"
" cannot handle such long strings. Please use 'Tcl_Size'");
}
*(int *)lengthPtr = (int)objPtr->length;
}
return objPtr->bytes;
}
| | | | 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 |
Tcl_Panic("Tcl_GetStringFromObj with 'int' lengthPtr"
" cannot handle such long strings. Please use 'Tcl_Size'");
}
*(int *)lengthPtr = (int)objPtr->length;
}
return objPtr->bytes;
}
#endif /* !defined(TCL_NO_DEPRECATED) */
#undef Tcl_GetStringFromObj
char *
Tcl_GetStringFromObj(
Tcl_Obj *objPtr, /* Object whose string rep byte pointer should
* be returned. */
Tcl_Size *lengthPtr) /* If non-NULL, the location where the string
* rep's byte array length should * be stored.
* If NULL, no length is stored. */
{
if (objPtr->bytes == NULL) {
/*
|
| ︙ | ︙ | |||
1733 1734 1735 1736 1737 1738 1739 | * As described above. * *---------------------------------------------------------------------- */ char * Tcl_InitStringRep( | | | 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 |
* As described above.
*
*----------------------------------------------------------------------
*/
char *
Tcl_InitStringRep(
Tcl_Obj *objPtr, /* Object whose string rep is to be set */
const char *bytes,
size_t numBytes)
{
assert(objPtr->bytes == NULL || bytes == NULL);
if (objPtr->bytes == NULL) {
/* Start with no string rep */
|
| ︙ | ︙ | |||
1804 1805 1806 1807 1808 1809 1810 | * the string representation NULL to mark it invalid. * *---------------------------------------------------------------------- */ void Tcl_InvalidateStringRep( | | | | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 |
* the string representation NULL to mark it invalid.
*
*----------------------------------------------------------------------
*/
void
Tcl_InvalidateStringRep(
Tcl_Obj *objPtr) /* Object whose string rep byte pointer should
* be freed. */
{
TclInvalidateStringRep(objPtr);
}
/*
*----------------------------------------------------------------------
*
* Tcl_HasStringRep --
*
* This function reports whether object has a string representation.
*
* Results:
* Boolean.
*----------------------------------------------------------------------
*/
int
Tcl_HasStringRep(
Tcl_Obj *objPtr) /* Object to test */
{
return TclHasStringRep(objPtr);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1916 1917 1918 1919 1920 1921 1922 | * Sets typePtr field to NULL. * *---------------------------------------------------------------------- */ void Tcl_FreeInternalRep( | | | 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 |
* Sets typePtr field to NULL.
*
*----------------------------------------------------------------------
*/
void
Tcl_FreeInternalRep(
Tcl_Obj *objPtr) /* Object whose internal rep should be freed. */
{
TclFreeInternalRep(objPtr);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1943 1944 1945 1946 1947 1948 1949 | * *---------------------------------------------------------------------- */ #undef Tcl_GetBoolFromObj int Tcl_GetBoolFromObj( | | | | | | < | < | 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 |
*
*----------------------------------------------------------------------
*/
#undef Tcl_GetBoolFromObj
int
Tcl_GetBoolFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get boolean. */
int flags,
char *charPtr) /* Place to store resulting boolean. */
{
int result;
if ((flags & TCL_NULL_OK) && (objPtr == NULL || Tcl_GetString(objPtr)[0] == '\0')) {
result = -1;
goto boolEnd;
} else if (objPtr == NULL) {
if (interp) {
TclNewObj(objPtr);
TclParseNumber(interp, objPtr, (flags & TCL_NULL_OK)
? "boolean value or \"\"" : "boolean value", NULL, TCL_INDEX_NONE, NULL, 0);
Tcl_DecrRefCount(objPtr);
}
return TCL_ERROR;
}
do {
if (TclHasInternalRep(objPtr, &tclIntType) || TclHasInternalRep(objPtr, &tclBooleanType)) {
result = (objPtr->internalRep.wideValue != 0);
goto boolEnd;
}
if (TclHasInternalRep(objPtr, &tclDoubleType)) {
/*
* Caution: Don't be tempted to check directly for the "double"
* Tcl_ObjType and then compare the internalrep to 0.0. This isn't
|
| ︙ | ︙ | |||
1996 1997 1998 1999 2000 2001 2002 |
if (charPtr != NULL) {
flags &= (TCL_NULL_OK-2);
if (flags) {
if (flags == (int)sizeof(int)) {
*(int *)charPtr = result;
return TCL_OK;
} else if (flags == (int)sizeof(short)) {
| | | | | | | < | | 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 |
if (charPtr != NULL) {
flags &= (TCL_NULL_OK-2);
if (flags) {
if (flags == (int)sizeof(int)) {
*(int *)charPtr = result;
return TCL_OK;
} else if (flags == (int)sizeof(short)) {
*(short *)charPtr = result;
return TCL_OK;
} else {
Tcl_Panic("Wrong bool var for %s", "Tcl_GetBoolFromObj");
}
}
*charPtr = result;
}
return TCL_OK;
}
} while ((ParseBoolean(objPtr) == TCL_OK) || (TCL_OK ==
TclParseNumber(interp, objPtr, (flags & TCL_NULL_OK)
? "boolean value or \"\"" : "boolean value", NULL,-1,NULL,0)));
return TCL_ERROR;
}
#undef Tcl_GetBooleanFromObj
int
Tcl_GetBooleanFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get boolean. */
int *intPtr) /* Place to store resulting boolean. */
{
return Tcl_GetBoolFromObj(interp, objPtr, (TCL_NULL_OK-2)&(int)sizeof(int), (char *)(void *)intPtr);
}
/*
*----------------------------------------------------------------------
*
* TclSetBooleanFromAny --
*
* Attempt to generate a boolean internal form for the Tcl object
* "objPtr".
|
| ︙ | ︙ | |||
2046 2047 2048 2049 2050 2051 2052 |
*
*----------------------------------------------------------------------
*/
int
TclSetBooleanFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
| | | 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 |
*
*----------------------------------------------------------------------
*/
int
TclSetBooleanFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
{
if (ParseBoolean(objPtr) == TCL_OK) {
return TCL_OK;
}
if (interp != NULL) {
Tcl_Obj *msg;
|
| ︙ | ︙ | |||
2078 2079 2080 2081 2082 2083 2084 |
Tcl_SetErrorCode(interp, "TCL", "VALUE", "BOOLEAN", (char *)NULL);
}
return TCL_ERROR;
}
static int
ParseBoolean(
| | | 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 |
Tcl_SetErrorCode(interp, "TCL", "VALUE", "BOOLEAN", (char *)NULL);
}
return TCL_ERROR;
}
static int
ParseBoolean(
Tcl_Obj *objPtr) /* The object to parse/convert. */
{
int newBool;
char lowerCase[6];
Tcl_Size i, length;
const char *str;
/*
|
| ︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 |
if ((Tcl_WideUInt)objPtr->internalRep.wideValue < 2) {
return TCL_OK;
}
return TCL_ERROR;
}
if (TclHasInternalRep(objPtr, &tclBignumType)) {
| | | | 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 |
if ((Tcl_WideUInt)objPtr->internalRep.wideValue < 2) {
return TCL_OK;
}
return TCL_ERROR;
}
if (TclHasInternalRep(objPtr, &tclBignumType)) {
return TCL_ERROR;
}
if (TclHasInternalRep(objPtr, &tclDoubleType)) {
return TCL_ERROR;
}
/* Handle dict separately, because it doesn't have a lengthProc */
if (TclHasInternalRep(objPtr, &tclDictType)) {
Tcl_DictObjSize(NULL, objPtr, &length);
if (length > 0) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2255 2256 2257 2258 2259 2260 2261 | */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewDoubleObj Tcl_Obj * Tcl_NewDoubleObj( | | | | 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 |
*/
#ifdef TCL_MEM_DEBUG
#undef Tcl_NewDoubleObj
Tcl_Obj *
Tcl_NewDoubleObj(
double dblValue) /* Double used to initialize the object. */
{
return Tcl_DbNewDoubleObj(dblValue, "unknown", 0);
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_NewDoubleObj(
double dblValue) /* Double used to initialize the object. */
{
Tcl_Obj *objPtr;
TclNewDoubleObj(objPtr, dblValue);
return objPtr;
}
#endif /* if TCL_MEM_DEBUG */
|
| ︙ | ︙ | |||
2303 2304 2305 2306 2307 2308 2309 | *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewDoubleObj( | | | | 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 |
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
Tcl_Obj *
Tcl_DbNewDoubleObj(
double dblValue, /* Double used to initialize the object. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
{
Tcl_Obj *objPtr;
TclDbNewObj(objPtr, file, line);
/* Optimized TclInvalidateStringRep() */
objPtr->bytes = NULL;
objPtr->internalRep.doubleValue = dblValue;
objPtr->typePtr = &tclDoubleType;
return objPtr;
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_DbNewDoubleObj(
double dblValue, /* Double used to initialize the object. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
{
return Tcl_NewDoubleObj(dblValue);
}
#endif /* TCL_MEM_DEBUG */
|
| ︙ | ︙ | |||
2352 2353 2354 2355 2356 2357 2358 | * rep is freed. * *---------------------------------------------------------------------- */ void Tcl_SetDoubleObj( | | | | 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 |
* rep is freed.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetDoubleObj(
Tcl_Obj *objPtr, /* Object whose internal rep to init. */
double dblValue) /* Double used to set the object's value. */
{
if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetDoubleObj");
}
TclSetDoubleObj(objPtr, dblValue);
}
|
| ︙ | ︙ | |||
2384 2385 2386 2387 2388 2389 2390 | * old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetDoubleFromObj( | | | | | 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 |
* old internal representation.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetDoubleFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get a double. */
double *dblPtr) /* Place to store resulting double. */
{
do {
if (TclHasInternalRep(objPtr, &tclDoubleType)) {
if (isnan(objPtr->internalRep.doubleValue)) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"floating point value is Not a Number", -1));
|
| ︙ | ︙ | |||
2440 2441 2442 2443 2444 2445 2446 |
*
*----------------------------------------------------------------------
*/
static int
SetDoubleFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
| | | 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 |
*
*----------------------------------------------------------------------
*/
static int
SetDoubleFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
{
return TclParseNumber(interp, objPtr, "floating-point number", NULL, -1,
NULL, 0);
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
2468 2469 2470 2471 2472 2473 2474 | * double-to-string conversion. * *---------------------------------------------------------------------- */ static void UpdateStringOfDouble( | | | 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 |
* double-to-string conversion.
*
*----------------------------------------------------------------------
*/
static void
UpdateStringOfDouble(
Tcl_Obj *objPtr) /* Double obj with string rep to update. */
{
char *dst = Tcl_InitStringRep(objPtr, NULL, TCL_DOUBLE_SPACE);
TclOOM(dst, TCL_DOUBLE_SPACE + 1);
Tcl_PrintDouble(NULL, objPtr->internalRep.doubleValue, dst);
(void) Tcl_InitStringRep(objPtr, NULL, strlen(dst));
|
| ︙ | ︙ | |||
2509 2510 2511 2512 2513 2514 2515 | * representation. * *---------------------------------------------------------------------- */ int Tcl_GetIntFromObj( | | | | | 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 |
* representation.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetIntFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get a int. */
int *intPtr) /* Place to store resulting int. */
{
#if (LONG_MAX == INT_MAX)
return TclGetLongFromObj(interp, objPtr, (long *) intPtr);
#else
long l;
if (TclGetLongFromObj(interp, objPtr, &l) != TCL_OK) {
|
| ︙ | ︙ | |||
2581 2582 2583 2584 2585 2586 2587 | * int-to-string conversion. * *---------------------------------------------------------------------- */ static void UpdateStringOfInt( | | | 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 |
* int-to-string conversion.
*
*----------------------------------------------------------------------
*/
static void
UpdateStringOfInt(
Tcl_Obj *objPtr) /* Int object whose string rep to update. */
{
char *dst = Tcl_InitStringRep( objPtr, NULL, TCL_INTEGER_SPACE);
TclOOM(dst, TCL_INTEGER_SPACE + 1);
(void) Tcl_InitStringRep(objPtr, NULL,
TclFormatInt(dst, objPtr->internalRep.wideValue));
}
|
| ︙ | ︙ | |||
2613 2614 2615 2616 2617 2618 2619 | * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetLongFromObj( | | | | | 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 |
* any old internal representation.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetLongFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get a long. */
long *longPtr) /* Place to store resulting long. */
{
do {
#ifdef TCL_WIDE_INT_IS_LONG
if (TclHasInternalRep(objPtr, &tclIntType)) {
*longPtr = objPtr->internalRep.wideValue;
return TCL_OK;
}
|
| ︙ | ︙ | |||
2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 |
/*
* Must check for those bignum values that can fit in a long, even
* when auto-narrowing is enabled. Only those values in the signed
* long range get auto-narrowed to tclIntType, while all the
* values in the unsigned long range will fit in a long.
*/
mp_int big;
unsigned long scratch, value = 0;
unsigned char *bytes = (unsigned char *) &scratch;
size_t numBytes;
TclUnpackBignum(objPtr, big);
if (mp_to_ubin(&big, bytes, sizeof(long), &numBytes) == MP_OKAY) {
while (numBytes-- > 0) {
| > | > > | > > > > > > > > > < < < < < < < < < < | 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 |
/*
* Must check for those bignum values that can fit in a long, even
* when auto-narrowing is enabled. Only those values in the signed
* long range get auto-narrowed to tclIntType, while all the
* values in the unsigned long range will fit in a long.
*/
{
mp_int big;
unsigned long scratch, value = 0;
unsigned char *bytes = (unsigned char *) &scratch;
size_t numBytes;
TclUnpackBignum(objPtr, big);
if (mp_to_ubin(&big, bytes, sizeof(long), &numBytes) == MP_OKAY) {
while (numBytes-- > 0) {
value = (value << CHAR_BIT) | *bytes++;
}
if (big.sign) {
if (value <= 1 + (unsigned long)LONG_MAX) {
*longPtr = (long)(-value);
return TCL_OK;
}
} else {
if (value <= (unsigned long)ULONG_MAX) {
*longPtr = (long)value;
return TCL_OK;
}
}
}
}
#ifndef TCL_WIDE_INT_IS_LONG
tooLarge:
#endif
if (interp != NULL) {
const char *s = "integer value too large to represent";
Tcl_Obj *msg = Tcl_NewStringObj(s, -1);
Tcl_SetObjResult(interp, msg);
Tcl_SetErrorCode(interp, "ARITH", "IOVERFLOW", s, (char *)NULL);
}
return TCL_ERROR;
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* Tcl_NewWideIntObj --
|
| ︙ | ︙ | |||
2729 2730 2731 2732 2733 2734 2735 | */ #ifdef TCL_MEM_DEBUG #undef Tcl_NewWideIntObj Tcl_Obj * Tcl_NewWideIntObj( | > | > | | 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 |
*/
#ifdef TCL_MEM_DEBUG
#undef Tcl_NewWideIntObj
Tcl_Obj *
Tcl_NewWideIntObj(
Tcl_WideInt wideValue)
/* Wide integer used to initialize the new
* object. */
{
return Tcl_DbNewWideIntObj(wideValue, "unknown", 0);
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_NewWideIntObj(
Tcl_WideInt wideValue)
/* Wide integer used to initialize the new
* object. */
{
Tcl_Obj *objPtr;
TclNewObj(objPtr);
TclSetIntObj(objPtr, wideValue);
return objPtr;
|
| ︙ | ︙ | |||
2767 2768 2769 2770 2771 2772 2773 | * None. * *---------------------------------------------------------------------- */ Tcl_Obj * Tcl_NewWideUIntObj( | | > | | 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 |
* None.
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
Tcl_NewWideUIntObj(
Tcl_WideUInt uwideValue)
/* Wide integer used to initialize the new
* object. */
{
Tcl_Obj *objPtr;
TclNewUIntObj(objPtr, uwideValue);
return objPtr;
}
/*
*----------------------------------------------------------------------
*
* Tcl_DbNewWideIntObj --
*
* If a client is compiled with TCL_MEM_DEBUG defined, calls to
* Tcl_NewWideIntObj to create new wide integer end up calling the
|
| ︙ | ︙ | |||
2812 2813 2814 2815 2816 2817 2818 | *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG Tcl_Obj * Tcl_DbNewWideIntObj( | > | < | < > | | 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 |
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
Tcl_Obj *
Tcl_DbNewWideIntObj(
Tcl_WideInt wideValue,
/* Wide integer used to initialize the new
* object. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
{
Tcl_Obj *objPtr;
TclDbNewObj(objPtr, file, line);
TclSetIntObj(objPtr, wideValue);
return objPtr;
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_DbNewWideIntObj(
Tcl_WideInt wideValue,
/* Long integer used to initialize the new
* object. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
{
return Tcl_NewWideIntObj(wideValue);
}
#endif /* TCL_MEM_DEBUG */
|
| ︙ | ︙ | |||
2861 2862 2863 2864 2865 2866 2867 | * rep is freed. * *---------------------------------------------------------------------- */ void Tcl_SetWideIntObj( | | | > | | | > | 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 |
* rep is freed.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetWideIntObj(
Tcl_Obj *objPtr, /* Object w. internal rep to init. */
Tcl_WideInt wideValue)
/* Wide integer used to initialize the
* object's value. */
{
if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetWideIntObj");
}
TclSetIntObj(objPtr, wideValue);
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetWideUIntObj --
*
* Modify an object to be a wide integer object or a bignum object
* and to have the specified unsigned wide integer value.
*
* Results:
* None.
*
* Side effects:
* The object's old string rep, if any, is freed. Also, any old internal
* rep is freed.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetWideUIntObj(
Tcl_Obj *objPtr, /* Object w. internal rep to init. */
Tcl_WideUInt uwideValue)
/* Wide integer used to initialize the
* object's value. */
{
if (Tcl_IsShared(objPtr)) {
Tcl_Panic("%s called with shared object", "Tcl_SetWideUIntObj");
}
if (uwideValue > WIDE_MAX) {
|
| ︙ | ︙ | |||
2934 2935 2936 2937 2938 2939 2940 | * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetWideIntFromObj( | | | | > | 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 |
* any old internal representation.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetWideIntFromObj(
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 long. */
{
do {
if (TclHasInternalRep(objPtr, &tclIntType)) {
*wideIntPtr = objPtr->internalRep.wideValue;
return TCL_OK;
}
if (TclHasInternalRep(objPtr, &tclDoubleType)) {
|
| ︙ | ︙ | |||
3018 3019 3020 3021 3022 3023 3024 | * any old internal representation. * *---------------------------------------------------------------------- */ int Tcl_GetWideUIntFromObj( | | | | > | 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 |
* any old internal representation.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetWideUIntFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* Object from which to get a wide int. */
Tcl_WideUInt *wideUIntPtr)
/* Place to store resulting long. */
{
do {
if (TclHasInternalRep(objPtr, &tclIntType)) {
if (objPtr->internalRep.wideValue < 0) {
wideUIntOutOfRange:
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
| ︙ | ︙ | |||
3077 3078 3079 3080 3081 3082 3083 |
}
return TCL_ERROR;
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
return TCL_ERROR;
}
| | | 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 |
}
return TCL_ERROR;
}
} while (TclParseNumber(interp, objPtr, "integer", NULL, -1, NULL,
TCL_PARSE_INTEGER_ONLY)==TCL_OK);
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
|
| ︙ | ︙ | |||
3102 3103 3104 3105 3106 3107 3108 | * conversion will free any old internal representation. * *---------------------------------------------------------------------- */ int TclGetWideBitsFromObj( | | | | | 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 |
* 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 (TclHasInternalRep(objPtr, &tclIntType)) {
*wideIntPtr = objPtr->internalRep.wideValue;
return TCL_OK;
}
if (TclHasInternalRep(objPtr, &tclDoubleType)) {
|
| ︙ | ︙ | |||
3156 3157 3158 3159 3160 3161 3162 | *---------------------------------------------------------------------- * * Tcl_GetSizeIntFromObj -- * * Attempt to return a Tcl_Size from the Tcl object "objPtr". * * Results: | | | | | | | 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 |
*----------------------------------------------------------------------
*
* Tcl_GetSizeIntFromObj --
*
* Attempt to return a Tcl_Size from the Tcl object "objPtr".
*
* Results:
* TCL_OK - the converted Tcl_Size value is stored in *sizePtr
* TCL_ERROR - the error message is stored in interp
*
* Side effects:
* The function may free up any existing internal representation.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetSizeIntFromObj(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr, /* The object from which to get a int. */
Tcl_Size *sizePtr) /* Place to store resulting int. */
{
if (sizeof(Tcl_Size) == sizeof(int)) {
return TclGetIntFromObj(interp, objPtr, (int *)sizePtr);
} else {
Tcl_WideInt wide;
if (TclGetWideIntFromObj(interp, objPtr, &wide) != TCL_OK) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
3478 3479 3480 3481 3482 3483 3484 |
*----------------------------------------------------------------------
*/
int
Tcl_GetBignumFromObj(
Tcl_Interp *interp, /* Tcl interpreter for error reporting */
Tcl_Obj *objPtr, /* Object to read */
| | | 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 |
*----------------------------------------------------------------------
*/
int
Tcl_GetBignumFromObj(
Tcl_Interp *interp, /* Tcl interpreter for error reporting */
Tcl_Obj *objPtr, /* Object to read */
void *bignumValue) /* Returned bignum value. */
{
return GetBignumFromObj(interp, objPtr, 1, (mp_int *)bignumValue);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
3513 3514 3515 3516 3517 3518 3519 |
*----------------------------------------------------------------------
*/
int
Tcl_TakeBignumFromObj(
Tcl_Interp *interp, /* Tcl interpreter for error reporting */
Tcl_Obj *objPtr, /* Object to read */
| | | 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 |
*----------------------------------------------------------------------
*/
int
Tcl_TakeBignumFromObj(
Tcl_Interp *interp, /* Tcl interpreter for error reporting */
Tcl_Obj *objPtr, /* Object to read */
void *bignumValue) /* Returned bignum value. */
{
return GetBignumFromObj(interp, objPtr, 0, (mp_int *)bignumValue);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
3538 3539 3540 3541 3542 3543 3544 |
*
*----------------------------------------------------------------------
*/
void
Tcl_SetBignumObj(
Tcl_Obj *objPtr, /* Object to set */
| | | 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 |
*
*----------------------------------------------------------------------
*/
void
Tcl_SetBignumObj(
Tcl_Obj *objPtr, /* Object to set */
void *big) /* Value to store */
{
Tcl_WideUInt value = 0;
size_t numBytes;
Tcl_WideUInt scratch;
unsigned char *bytes = (unsigned char *) &scratch;
mp_int *bignumValue = (mp_int *) big;
|
| ︙ | ︙ | |||
3615 3616 3617 3618 3619 3620 3621 | } /* *---------------------------------------------------------------------- * * Tcl_GetNumberFromObj -- * | | | | | | | | | 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 |
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetNumberFromObj --
*
* Extracts a number (of any possible numeric type) from an object.
*
* Results:
* Whether the extraction worked. The type is stored in the variable
* referred to by the typePtr argument, and a pointer to the
* representation is stored in the variable referred to by the
* clientDataPtr.
*
* Side effects:
* Can allocate thread-specific data for handling the copy-out space for
* bignums; this space is shared within a thread.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetNumberFromObj(
Tcl_Interp *interp,
|
| ︙ | ︙ | |||
3711 3712 3713 3714 3715 3716 3717 | * *---------------------------------------------------------------------- */ #undef Tcl_IncrRefCount void Tcl_IncrRefCount( | | | | 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 |
*
*----------------------------------------------------------------------
*/
#undef Tcl_IncrRefCount
void
Tcl_IncrRefCount(
Tcl_Obj *objPtr) /* The object we are registering a reference to. */
{
++(objPtr)->refCount;
}
/*
*----------------------------------------------------------------------
*
* Tcl_DecrRefCount --
*
* Decrements the reference count of the object.
*
* Results:
* The storage for objPtr may be freed.
*
*----------------------------------------------------------------------
*/
#undef Tcl_DecrRefCount
void
Tcl_DecrRefCount(
Tcl_Obj *objPtr) /* The object we are releasing a reference to. */
{
if (objPtr->refCount-- <= 1) {
TclFreeObj(objPtr);
}
}
/*
|
| ︙ | ︙ | |||
3754 3755 3756 3757 3758 3759 3760 | * possibly with a refCount of 0. The caller must have previously * incremented the refCount. * *---------------------------------------------------------------------- */ void TclUndoRefCount( | | | 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 |
* possibly with a refCount of 0. The caller must have previously
* incremented the refCount.
*
*----------------------------------------------------------------------
*/
void
TclUndoRefCount(
Tcl_Obj *objPtr) /* The object we are releasing a reference to. */
{
if (objPtr->refCount > 0) {
--objPtr->refCount;
}
}
/*
|
| ︙ | ︙ | |||
3777 3778 3779 3780 3781 3782 3783 | * *---------------------------------------------------------------------- */ #undef Tcl_IsShared int Tcl_IsShared( | | | | 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 |
*
*----------------------------------------------------------------------
*/
#undef Tcl_IsShared
int
Tcl_IsShared(
Tcl_Obj *objPtr) /* The object to test for being shared. */
{
return ((objPtr)->refCount > 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_DbIncrRefCount --
*
|
| ︙ | ︙ | |||
3806 3807 3808 3809 3810 3811 3812 | * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG void Tcl_DbIncrRefCount( | | | 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 |
*
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
void
Tcl_DbIncrRefCount(
Tcl_Obj *objPtr, /* The object we are registering a reference
* to. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
{
if (objPtr->refCount == FREEDREFCOUNTFILLER) {
|
| ︙ | ︙ | |||
3832 3833 3834 3835 3836 3837 3838 |
if (!TclInExit()) {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
Tcl_HashEntry *hPtr;
if (!tablePtr) {
| | | | | | 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 |
if (!TclInExit()) {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
Tcl_HashEntry *hPtr;
if (!tablePtr) {
Tcl_Panic("object table not initialized");
}
hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
if (!hPtr) {
Tcl_Panic("Trying to %s of Tcl_Obj allocated in another thread",
"incr ref count");
}
}
# endif /* TCL_THREADS */
++(objPtr)->refCount;
}
#else /* !TCL_MEM_DEBUG */
void
Tcl_DbIncrRefCount(
Tcl_Obj *objPtr, /* The object we are registering a reference
* to. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
{
++(objPtr)->refCount;
}
#endif /* TCL_MEM_DEBUG */
|
| ︙ | ︙ | |||
3879 3880 3881 3882 3883 3884 3885 | * *---------------------------------------------------------------------- */ #ifdef TCL_MEM_DEBUG void Tcl_DbDecrRefCount( | | | 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 |
*
*----------------------------------------------------------------------
*/
#ifdef TCL_MEM_DEBUG
void
Tcl_DbDecrRefCount(
Tcl_Obj *objPtr, /* The object we are releasing a reference
* to. */
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
{
if (objPtr->refCount == FREEDREFCOUNTFILLER) {
|
| ︙ | ︙ | |||
3905 3906 3907 3908 3909 3910 3911 |
if (!TclInExit()) {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
Tcl_HashEntry *hPtr;
if (!tablePtr) {
| | | | | | 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 |
if (!TclInExit()) {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
Tcl_HashEntry *hPtr;
if (!tablePtr) {
Tcl_Panic("object table not initialized");
}
hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
if (!hPtr) {
Tcl_Panic("Trying to %s of Tcl_Obj allocated in another thread",
"decr ref count");
}
}
# endif /* TCL_THREADS */
if (objPtr->refCount-- <= 1) {
TclFreeObj(objPtr);
}
}
#else /* !TCL_MEM_DEBUG */
void
Tcl_DbDecrRefCount(
Tcl_Obj *objPtr, /* The object we are releasing a reference
* to. */
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
{
if (objPtr->refCount-- <= 1) {
TclFreeObj(objPtr);
}
|
| ︙ | ︙ | |||
3956 3957 3958 3959 3960 3961 3962 | * None. * *---------------------------------------------------------------------- */ int Tcl_DbIsShared( | | | | < | 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 |
* None.
*
*----------------------------------------------------------------------
*/
int
Tcl_DbIsShared(
Tcl_Obj *objPtr, /* The object to test for being shared. */
#ifdef TCL_MEM_DEBUG
const char *file, /* The name of the source file calling this
* function; used for debugging. */
int line) /* Line number in the source file; used for
* debugging. */
#else
TCL_UNUSED(const char *) /*file*/,
TCL_UNUSED(int) /*line*/)
#endif
{
#ifdef TCL_MEM_DEBUG
if (objPtr->refCount == FREEDREFCOUNTFILLER) {
fprintf(stderr, "file = %s, line = %d\n", file, line);
fflush(stderr);
Tcl_Panic("checking whether previously disposed object is shared");
}
|
| ︙ | ︙ | |||
3988 3989 3990 3991 3992 3993 3994 |
if (!TclInExit()) {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
Tcl_HashEntry *hPtr;
if (!tablePtr) {
| | | | | | 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 |
if (!TclInExit()) {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_HashTable *tablePtr = tsdPtr->objThreadMap;
Tcl_HashEntry *hPtr;
if (!tablePtr) {
Tcl_Panic("object table not initialized");
}
hPtr = Tcl_FindHashEntry(tablePtr, objPtr);
if (!hPtr) {
Tcl_Panic("Trying to %s of Tcl_Obj allocated in another thread",
"check shared status");
}
}
# endif /* TCL_THREADS */
#endif /* TCL_MEM_DEBUG */
#ifdef TCL_COMPILE_STATS
Tcl_MutexLock(&tclObjMutex);
if ((objPtr)->refCount <= 1) {
tclObjsShared[1]++;
} else if ((objPtr)->refCount < TCL_MAX_SHARED_OBJ_STATS) {
tclObjsShared[(objPtr)->refCount]++;
} else {
tclObjsShared[0]++;
}
Tcl_MutexUnlock(&tclObjMutex);
#endif /* TCL_COMPILE_STATS */
return ((objPtr)->refCount > 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_InitObjHashTable --
*
|
| ︙ | ︙ | |||
4034 4035 4036 4037 4038 4039 4040 | * Tcl_CreateHashEntry. * *---------------------------------------------------------------------- */ void Tcl_InitObjHashTable( | > | | 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 |
* Tcl_CreateHashEntry.
*
*----------------------------------------------------------------------
*/
void
Tcl_InitObjHashTable(
Tcl_HashTable *tablePtr)
/* Pointer to table record, which is supplied
* by the caller. */
{
Tcl_InitCustomHashTable(tablePtr, TCL_CUSTOM_PTR_KEYS,
&tclObjHashKeyType);
}
/*
|
| ︙ | ︙ | |||
4063 4064 4065 4066 4067 4068 4069 |
static Tcl_HashEntry *
AllocObjEntry(
TCL_UNUSED(Tcl_HashTable *),
void *keyPtr) /* Key to store in the hash table entry. */
{
Tcl_Obj *objPtr = (Tcl_Obj *)keyPtr;
| | < | | | < | 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 |
static Tcl_HashEntry *
AllocObjEntry(
TCL_UNUSED(Tcl_HashTable *),
void *keyPtr) /* Key to store in the hash table entry. */
{
Tcl_Obj *objPtr = (Tcl_Obj *)keyPtr;
Tcl_HashEntry *hPtr = (Tcl_HashEntry *)Tcl_Alloc(sizeof(Tcl_HashEntry));
hPtr->key.objPtr = objPtr;
Tcl_IncrRefCount(objPtr);
hPtr->clientData = NULL;
return hPtr;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4105 4106 4107 4108 4109 4110 4111 |
const char *p1, *p2;
size_t l1, l2;
/*
* If the object pointers are the same then they match.
* OPT: this comparison was moved to the caller
| | | | | | 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 |
const char *p1, *p2;
size_t l1, l2;
/*
* If the object pointers are the same then they match.
* OPT: this comparison was moved to the caller
if (objPtr1 == objPtr2) {
return 1;
}
*/
/*
* Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being
* in a register.
*/
p1 = TclGetString(objPtr1);
|
| ︙ | ︙ | |||
4258 4259 4260 4261 4262 4263 4264 |
*----------------------------------------------------------------------
*/
Tcl_Command
Tcl_GetCommandFromObj(
Tcl_Interp *interp, /* The interpreter in which to resolve the
* command and to report errors. */
| | | 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 |
*----------------------------------------------------------------------
*/
Tcl_Command
Tcl_GetCommandFromObj(
Tcl_Interp *interp, /* The interpreter in which to resolve the
* command and to report errors. */
Tcl_Obj *objPtr) /* The object containing the command's name.
* If the name starts with "::", will be
* looked up in global namespace. Else, looked
* up first in the current namespace, then in
* global namespace. */
{
ResolvedCmdName *resPtr;
|
| ︙ | ︙ | |||
4394 4395 4396 4397 4398 4399 4400 |
}
}
void
TclSetCmdNameObj(
Tcl_Interp *interp, /* Points to interpreter containing command
* that should be cached in objPtr. */
| | | 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 |
}
}
void
TclSetCmdNameObj(
Tcl_Interp *interp, /* Points to interpreter containing command
* that should be cached in objPtr. */
Tcl_Obj *objPtr, /* Points to Tcl object to be changed to a
* CmdName object. */
Command *cmdPtr) /* Points to Command structure that the
* CmdName object should refer to. */
{
ResolvedCmdName *resPtr;
if (TclHasInternalRep(objPtr, &tclCmdNameType)) {
|
| ︙ | ︙ | |||
4434 4435 4436 4437 4438 4439 4440 | * ResolvedSymbol, which may free the Command structure. * *---------------------------------------------------------------------- */ static void FreeCmdNameInternalRep( | | | 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 |
* ResolvedSymbol, which may free the Command structure.
*
*----------------------------------------------------------------------
*/
static void
FreeCmdNameInternalRep(
Tcl_Obj *objPtr) /* CmdName object with internal
* representation to free. */
{
ResolvedCmdName *resPtr = (ResolvedCmdName *)objPtr->internalRep.twoPtrValue.ptr1;
/*
* Decrement the reference count of the ResolvedCmdName structure. If
* there are no more uses, free the ResolvedCmdName structure.
|
| ︙ | ︙ | |||
4482 4483 4484 4485 4486 4487 4488 |
*
*----------------------------------------------------------------------
*/
static void
DupCmdNameInternalRep(
Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
| | | 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 |
*
*----------------------------------------------------------------------
*/
static void
DupCmdNameInternalRep(
Tcl_Obj *srcPtr, /* Object with internal rep to copy. */
Tcl_Obj *copyPtr) /* Object with internal rep to set. */
{
ResolvedCmdName *resPtr = (ResolvedCmdName *)srcPtr->internalRep.twoPtrValue.ptr1;
copyPtr->internalRep.twoPtrValue.ptr1 = resPtr;
copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
resPtr->refCount++;
copyPtr->typePtr = &tclCmdNameType;
|
| ︙ | ︙ | |||
4516 4517 4518 4519 4520 4521 4522 |
*
*----------------------------------------------------------------------
*/
static int
SetCmdNameFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
| | | 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 |
*
*----------------------------------------------------------------------
*/
static int
SetCmdNameFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
{
const char *name;
Command *cmdPtr;
ResolvedCmdName *resPtr;
if (interp == NULL) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
4587 4588 4589 4590 4591 4592 4593 |
*----------------------------------------------------------------------
*/
int
Tcl_RepresentationCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 |
*----------------------------------------------------------------------
*/
int
Tcl_RepresentationCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *descObj;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "value");
return TCL_ERROR;
}
|
| ︙ | ︙ |
Changes to generic/tclOptimize.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* * tclOptimize.c -- * * This file contains the bytecode optimizer. * * Copyright © 2013 Donal Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * tclOptimize.c -- * * This file contains the bytecode optimizer. * * Copyright © 2013 Donal Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" /* * Forward declarations. */ static void AdvanceJumps(CompileEnv *envPtr); |
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
* because they are the targets of various types of jumps.
*/
for (currentInstPtr = envPtr->codeStart ;
currentInstPtr < envPtr->codeNext ;
currentInstPtr += AddrLength(currentInstPtr)) {
switch (*currentInstPtr) {
| < < | | | | < < < < < < < < | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
* because they are the targets of various types of jumps.
*/
for (currentInstPtr = envPtr->codeStart ;
currentInstPtr < envPtr->codeNext ;
currentInstPtr += AddrLength(currentInstPtr)) {
switch (*currentInstPtr) {
case INST_JUMP1:
case INST_JUMP_TRUE1:
case INST_JUMP_FALSE1:
targetInstPtr = currentInstPtr+TclGetInt1AtPtr(currentInstPtr+1);
goto storeTarget;
case INST_JUMP4:
case INST_JUMP_TRUE4:
case INST_JUMP_FALSE4:
case INST_START_CMD:
targetInstPtr = currentInstPtr+TclGetInt4AtPtr(currentInstPtr+1);
goto storeTarget;
case INST_BEGIN_CATCH4:
targetInstPtr = envPtr->codeStart + envPtr->exceptArrayPtr[
TclGetUInt4AtPtr(currentInstPtr+1)].codeOffset;
storeTarget:
DefineTargetAddress(tablePtr, targetInstPtr);
break;
case INST_JUMP_TABLE:
hPtr = Tcl_FirstHashEntry(
&JUMPTABLEINFO(envPtr, currentInstPtr+1)->hashTable,
&hSearch);
for (; hPtr ; hPtr = Tcl_NextHashEntry(&hSearch)) {
targetInstPtr = currentInstPtr +
PTR2INT(Tcl_GetHashValue(hPtr));
DefineTargetAddress(tablePtr, targetInstPtr);
}
break;
case INST_RETURN_CODE_BRANCH:
for (i=TCL_ERROR ; i<TCL_CONTINUE+1 ; i++) {
DefineTargetAddress(tablePtr, currentInstPtr + 2*i - 1);
}
break;
}
}
/*
* Add a marker *after* the last bytecode instruction. WARNING: points to
* one past the end!
*/
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
(void) TclGetStringFromObj(litPtr, &numBytes);
if (numBytes == 0) {
blank = size + InstLength(nextInst);
}
}
break;
| | < < | | | | < | < | | < < | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
(void) TclGetStringFromObj(litPtr, &numBytes);
if (numBytes == 0) {
blank = size + InstLength(nextInst);
}
}
break;
case INST_PUSH4:
if (nextInst == INST_POP) {
blank = size + 1;
} else if (nextInst == INST_STR_CONCAT1
&& TclGetUInt1AtPtr(currentInstPtr + size + 1) == 2) {
Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
TclGetUInt4AtPtr(currentInstPtr + 1));
Tcl_Size numBytes;
(void) TclGetStringFromObj(litPtr, &numBytes);
if (numBytes == 0) {
blank = size + InstLength(nextInst);
}
}
break;
case INST_LNOT:
switch (nextInst) {
case INST_JUMP_TRUE1:
blank = size;
currentInstPtr[size] = INST_JUMP_FALSE1;
break;
case INST_JUMP_FALSE1:
blank = size;
currentInstPtr[size] = INST_JUMP_TRUE1;
break;
case INST_JUMP_TRUE4:
blank = size;
currentInstPtr[size] = INST_JUMP_FALSE4;
break;
case INST_JUMP_FALSE4:
blank = size;
currentInstPtr[size] = INST_JUMP_TRUE4;
break;
}
break;
case INST_TRY_CVT_TO_NUMERIC:
switch (nextInst) {
case INST_JUMP_TRUE1:
case INST_JUMP_TRUE4:
case INST_JUMP_FALSE1:
case INST_JUMP_FALSE4:
case INST_INCR_SCALAR1:
case INST_INCR_ARRAY1:
case INST_INCR_ARRAY_STK:
case INST_INCR_SCALAR_STK:
case INST_INCR_STK:
case INST_EQ:
case INST_NEQ:
case INST_LT:
case INST_LE:
|
| ︙ | ︙ | |||
363 364 365 366 367 368 369 |
for (currentInstPtr = envPtr->codeStart ;
currentInstPtr < envPtr->codeNext-1 ;
currentInstPtr += AddrLength(currentInstPtr)) {
int offset, delta, isNew;
switch (*currentInstPtr) {
| < | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
for (currentInstPtr = envPtr->codeStart ;
currentInstPtr < envPtr->codeNext-1 ;
currentInstPtr += AddrLength(currentInstPtr)) {
int offset, delta, isNew;
switch (*currentInstPtr) {
case INST_JUMP1:
case INST_JUMP_TRUE1:
case INST_JUMP_FALSE1:
offset = TclGetInt1AtPtr(currentInstPtr + 1);
Tcl_InitHashTable(&jumps, TCL_ONE_WORD_KEYS);
for (delta=0 ; offset+delta != 0 ;) {
if (offset + delta < -128 || offset + delta > 127) {
|
| ︙ | ︙ | |||
386 387 388 389 390 391 392 |
switch (currentInstPtr[offset]) {
case INST_NOP:
delta = InstLength(INST_NOP);
continue;
case INST_JUMP1:
delta = TclGetInt1AtPtr(currentInstPtr + offset + 1);
continue;
| | < | | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
switch (currentInstPtr[offset]) {
case INST_NOP:
delta = InstLength(INST_NOP);
continue;
case INST_JUMP1:
delta = TclGetInt1AtPtr(currentInstPtr + offset + 1);
continue;
case INST_JUMP4:
delta = TclGetInt4AtPtr(currentInstPtr + offset + 1);
continue;
}
break;
}
Tcl_DeleteHashTable(&jumps);
TclStoreInt1AtPtr(offset, currentInstPtr + 1);
continue;
case INST_JUMP4:
case INST_JUMP_TRUE4:
case INST_JUMP_FALSE4:
Tcl_InitHashTable(&jumps, TCL_ONE_WORD_KEYS);
Tcl_CreateHashEntry(&jumps, INT2PTR(0), &isNew);
for (offset = TclGetInt4AtPtr(currentInstPtr + 1); offset!=0 ;) {
Tcl_CreateHashEntry(&jumps, INT2PTR(offset), &isNew);
if (!isNew) {
offset = TclGetInt4AtPtr(currentInstPtr + 1);
break;
}
switch (currentInstPtr[offset]) {
case INST_NOP:
offset += InstLength(INST_NOP);
continue;
case INST_JUMP1:
offset += TclGetInt1AtPtr(currentInstPtr + offset + 1);
continue;
case INST_JUMP4:
offset += TclGetInt4AtPtr(currentInstPtr + offset + 1);
continue;
}
break;
}
Tcl_DeleteHashTable(&jumps);
TclStoreInt4AtPtr(offset, currentInstPtr + 1);
continue;
}
}
}
/*
* ----------------------------------------------------------------------
*
* TclOptimizeBytecode --
*
* A very simple peephole optimizer for bytecode.
*
* ----------------------------------------------------------------------
*/
void
TclOptimizeBytecode(
void *envPtr)
{
ConvertZeroEffectToNOP((CompileEnv *)envPtr);
AdvanceJumps((CompileEnv *)envPtr);
TrimUnreachable((CompileEnv *)envPtr);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
* End:
*/
|
Changes to generic/tclPanic.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
*/
const char *
Tcl_SetPanicProc(
Tcl_PanicProc *proc)
{
panicProc = proc;
| | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
*/
const char *
Tcl_SetPanicProc(
Tcl_PanicProc *proc)
{
panicProc = proc;
return Tcl_InitSubsystems();
}
/*
*----------------------------------------------------------------------
*
* Tcl_Panic --
*
|
| ︙ | ︙ |
Changes to generic/tclParse.c.
| ︙ | ︙ | |||
115 116 117 118 119 120 121 |
TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
};
/*
* Prototypes for local functions defined in this file:
*/
| | | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
};
/*
* Prototypes for local functions defined in this file:
*/
static int CommandComplete(const char *script, Tcl_Size numBytes);
static Tcl_Size ParseComment(const char *src, Tcl_Size numBytes,
Tcl_Parse *parsePtr);
static int ParseTokens(const char *src, Tcl_Size numBytes, int mask,
int flags, Tcl_Parse *parsePtr);
static Tcl_Size ParseWhiteSpace(const char *src, Tcl_Size numBytes,
int *incompletePtr, char *typePtr);
static Tcl_Size ParseAllWhiteSpace(const char *src, Tcl_Size numBytes,
int *incompletePtr);
static int ParseHex(const char *src, Tcl_Size numBytes,
int *resultPtr);
/*
*----------------------------------------------------------------------
*
* TclParseInit --
*
|
| ︙ | ︙ | |||
200 201 202 203 204 205 206 |
Tcl_Size numBytes, /* Total number of bytes in string. If -1,
* the script consists of all bytes up to the
* first null character. */
int nested, /* Non-zero means this is a nested command:
* close bracket should be considered a
* command terminator. If zero, then close
* bracket has no special meaning. */
| > | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
Tcl_Size numBytes, /* Total number of bytes in string. If -1,
* the script consists of all bytes up to the
* first null character. */
int nested, /* Non-zero means this is a nested command:
* close bracket should be considered a
* command terminator. If zero, then close
* bracket has no special meaning. */
Tcl_Parse *parsePtr)
/* Structure to fill in with information about
* the parsed command; any previous
* information in the structure is ignored. */
{
const char *src; /* Points to current character in the
* command. */
char type; /* Result returned by CHAR_TYPE(*src). */
Tcl_Token *tokenPtr; /* Pointer to token being filled in. */
Tcl_Size wordIndex; /* Index of word token for current word. */
int terminators; /* CHAR_TYPE bits that indicate the end of a
* command. */
const char *termPtr; /* Set by Tcl_ParseBraces/QuotedString to
* point to char after terminating one. */
Tcl_Size scanned;
|
| ︙ | ︙ | |||
258 259 260 261 262 263 264 |
* The following loop parses the words of the command, one word in each
* iteration through the loop.
*/
parsePtr->commandStart = src;
type = CHAR_TYPE(*src);
scanned = 1; /* Can't have missing whitepsace before first word. */
| | | | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
* The following loop parses the words of the command, one word in each
* iteration through the loop.
*/
parsePtr->commandStart = src;
type = CHAR_TYPE(*src);
scanned = 1; /* Can't have missing whitepsace before first word. */
while (1) {
int expandWord = 0;
/* Are we at command termination? */
if ((numBytes == 0) || (type & terminators) != 0) {
parsePtr->term = src;
parsePtr->commandSize = src + (numBytes != 0)
- parsePtr->commandStart;
|
| ︙ | ︙ | |||
337 338 339 340 341 342 343 |
/*
* Check whether the braces contained the word expansion prefix
* {*}
*/
expPtr = &parsePtr->tokenPtr[expIdx];
| | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
/*
* Check whether the braces contained the word expansion prefix
* {*}
*/
expPtr = &parsePtr->tokenPtr[expIdx];
if ((0 == expandWord)
/* Haven't seen prefix already */
&& (expIdx + 1 == parsePtr->numTokens)
/* Only one token */
&& (((1 == expPtr->size)
/* Same length as prefix */
&& (expPtr->start[0] == '*')))
/* Is the prefix */
&& (numBytes > 0) && (0 == ParseWhiteSpace(termPtr,
numBytes, &parsePtr->incomplete, &type))
&& (type != TYPE_COMMAND_END)
/* Non-whitespace follows */) {
expandWord = 1;
parsePtr->numTokens--;
goto parseWord;
}
} else {
/*
* This is an unquoted word. Call ParseTokens and let it do all of
* the work.
|
| ︙ | ︙ | |||
377 378 379 380 381 382 383 |
*/
tokenPtr = &parsePtr->tokenPtr[wordIndex];
tokenPtr->size = src - tokenPtr->start;
tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1);
if (expandWord) {
Tcl_Size i;
| | | | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
*/
tokenPtr = &parsePtr->tokenPtr[wordIndex];
tokenPtr->size = src - tokenPtr->start;
tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1);
if (expandWord) {
Tcl_Size i;
int isLiteral = 1;
/*
* When a command includes a word that is an expanded literal; for
* example, {*}{1 2 3}, the parser performs that expansion
* immediately, generating several TCL_TOKEN_SIMPLE_WORDs instead
* of a single TCL_TOKEN_EXPAND_WORD that the Tcl_ParseCommand()
* caller might have to expand. This notably makes it simpler for
* those callers that wish to track line endings, such as those
* that implement key parts of TIP 280.
*
* First check whether the thing to be expanded is a literal,
* in the sense of being composed entirely of TCL_TOKEN_TEXT
* tokens.
*/
for (i = 1; i <= tokenPtr->numComponents; i++) {
if (tokenPtr[i].type != TCL_TOKEN_TEXT) {
isLiteral = 0;
break;
}
}
if (isLiteral) {
Tcl_Size elemCount = 0;
int code = TCL_OK, literal = 1;
|
| ︙ | ︙ | |||
548 549 550 551 552 553 554 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | < > | | | < > | | | | | | 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclIsSpaceProc(
int byte)
{
return CHAR_TYPE(byte) & (TYPE_SPACE) || byte == '\n';
}
/*
*----------------------------------------------------------------------
*
* TclIsBareword--
*
* Report whether byte is one that can be part of a "bareword".
* This concept is named in expression parsing, where it determines
* what can be a legal function name, but is the same definition used
* in determining what variable names can be parsed as variable
* substitutions without the benefit of enclosing braces. The set of
* ASCII chars that are accepted are the numeric chars ('0'-'9'),
* the alphabetic chars ('a'-'z', 'A'-'Z') and underscore ('_').
*
* Results:
* Returns 1, if byte is in the accepted set of chars, 0 otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclIsBareword(
int byte)
{
if (byte < '0' || byte > 'z') {
return 0;
}
if (byte <= '9' || byte >= 'a') {
return 1;
}
if (byte == '_') {
return 1;
}
if (byte < 'A' || byte > 'Z') {
return 0;
}
return 1;
}
/*
*----------------------------------------------------------------------
*
* ParseWhiteSpace --
*
|
| ︙ | ︙ | |||
622 623 624 625 626 627 628 |
static Tcl_Size
ParseWhiteSpace(
const char *src, /* First character to parse. */
Tcl_Size numBytes, /* Max number of bytes to scan. */
int *incompletePtr, /* Set this boolean memory to true if parsing
* indicates an incomplete command. */
| | | | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
static Tcl_Size
ParseWhiteSpace(
const char *src, /* First character to parse. */
Tcl_Size numBytes, /* Max number of bytes to scan. */
int *incompletePtr, /* Set this boolean memory to true if parsing
* indicates an incomplete command. */
char *typePtr) /* Points to location to store character type
* of character that ends run of whitespace */
{
char type = TYPE_NORMAL;
const char *p = src;
while (1) {
while (numBytes && ((type = CHAR_TYPE(*p)) & TYPE_SPACE)) {
numBytes--;
p++;
}
if (numBytes && (type & TYPE_SUBS)) {
if (*p != '\\') {
break;
|
| ︙ | ︙ | |||
676 677 678 679 680 681 682 |
static Tcl_Size
ParseAllWhiteSpace(
const char *src, /* First character to parse. */
Tcl_Size numBytes, /* Max number of byes to scan */
int *incompletePtr) /* Set true if parse is incomplete. */
{
| | | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 |
static Tcl_Size
ParseAllWhiteSpace(
const char *src, /* First character to parse. */
Tcl_Size numBytes, /* Max number of byes to scan */
int *incompletePtr) /* Set true if parse is incomplete. */
{
char type;
const char *p = src;
do {
Tcl_Size scanned = ParseWhiteSpace(p, numBytes, incompletePtr, &type);
p += scanned;
numBytes -= scanned;
|
| ︙ | ︙ | |||
719 720 721 722 723 724 725 | * * The digits '0' .. '9' and the letters 'A' .. 'Z' and 'a' .. 'z' occupy * consecutive code points, and '0' < 'A' < 'a'. * *---------------------------------------------------------------------- */ | | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
*
* The digits '0' .. '9' and the letters 'A' .. 'Z' and 'a' .. 'z' occupy
* consecutive code points, and '0' < 'A' < 'a'.
*
*----------------------------------------------------------------------
*/
int
ParseHex(
const char *src, /* First character to parse. */
Tcl_Size numBytes, /* Max number of byes to scan */
int *resultPtr) /* Points to storage provided by caller where
* the character resulting from the
* conversion is to be written. */
{
|
| ︙ | ︙ | |||
774 775 776 777 778 779 780 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclParseBackslash(
const char *src, /* Points to the backslash character of a
* backslash sequence. */
Tcl_Size numBytes, /* Max number of bytes to scan. */
Tcl_Size *readPtr, /* NULL, or points to storage where the number
* of bytes scanned should be written. */
char *dst) /* NULL, or points to buffer where the UTF-8
|
| ︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 |
* perform: TCL_SUBST_COMMANDS,
* TCL_SUBST_VARIABLES, and
* TCL_SUBST_BACKSLASHES */
Tcl_Parse *parsePtr) /* Information about parse in progress.
* Updated with additional tokens and
* termination information. */
{
| | > > > | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 |
* perform: TCL_SUBST_COMMANDS,
* TCL_SUBST_VARIABLES, and
* TCL_SUBST_BACKSLASHES */
Tcl_Parse *parsePtr) /* Information about parse in progress.
* Updated with additional tokens and
* termination information. */
{
char type;
Tcl_Size originalTokens;
int noSubstCmds = !(flags & TCL_SUBST_COMMANDS);
int noSubstVars = !(flags & TCL_SUBST_VARIABLES);
int noSubstBS = !(flags & TCL_SUBST_BACKSLASHES);
Tcl_Token *tokenPtr;
/*
* Each iteration through the following loop adds one token of type
* TCL_TOKEN_TEXT, TCL_TOKEN_BS, TCL_TOKEN_COMMAND, or TCL_TOKEN_VARIABLE
* to parsePtr. For TCL_TOKEN_VARIABLE tokens, additional tokens are added
* for the parsed variable name.
|
| ︙ | ︙ | |||
1081 1082 1083 1084 1085 1086 1087 |
}
tokenPtr->type = TCL_TOKEN_TEXT;
tokenPtr->size = src - tokenPtr->start;
parsePtr->numTokens++;
} else if (*src == '$') {
Tcl_Size varToken;
| | | 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 |
}
tokenPtr->type = TCL_TOKEN_TEXT;
tokenPtr->size = src - tokenPtr->start;
parsePtr->numTokens++;
} else if (*src == '$') {
Tcl_Size varToken;
if (noSubstVars) {
tokenPtr->type = TCL_TOKEN_TEXT;
tokenPtr->size = 1;
parsePtr->numTokens++;
src++;
numBytes--;
continue;
}
|
| ︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 |
return TCL_ERROR;
}
src += parsePtr->tokenPtr[varToken].size;
numBytes -= parsePtr->tokenPtr[varToken].size;
} else if (*src == '[') {
Tcl_Parse *nestedPtr;
| | | | 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 |
return TCL_ERROR;
}
src += parsePtr->tokenPtr[varToken].size;
numBytes -= parsePtr->tokenPtr[varToken].size;
} else if (*src == '[') {
Tcl_Parse *nestedPtr;
if (noSubstCmds) {
tokenPtr->type = TCL_TOKEN_TEXT;
tokenPtr->size = 1;
parsePtr->numTokens++;
src++;
numBytes--;
continue;
}
/*
* Command substitution. Call Tcl_ParseCommand recursively (and
* repeatedly) to parse the nested command(s), then throw away the
* parse information.
*/
src++;
numBytes--;
nestedPtr = (Tcl_Parse *)TclStackAlloc(parsePtr->interp, sizeof(Tcl_Parse));
while (1) {
const char *curEnd;
if (Tcl_ParseCommand(parsePtr->interp, src, numBytes, 1,
nestedPtr) != TCL_OK) {
parsePtr->errorType = nestedPtr->errorType;
parsePtr->term = nestedPtr->term;
parsePtr->incomplete = nestedPtr->incomplete;
|
| ︙ | ︙ | |||
1167 1168 1169 1170 1171 1172 1173 |
}
}
TclStackFree(parsePtr->interp, nestedPtr);
tokenPtr->type = TCL_TOKEN_COMMAND;
tokenPtr->size = src - tokenPtr->start;
parsePtr->numTokens++;
} else if (*src == '\\') {
| | | 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 |
}
}
TclStackFree(parsePtr->interp, nestedPtr);
tokenPtr->type = TCL_TOKEN_COMMAND;
tokenPtr->size = src - tokenPtr->start;
parsePtr->numTokens++;
} else if (*src == '\\') {
if (noSubstBS) {
tokenPtr->type = TCL_TOKEN_TEXT;
tokenPtr->size = 1;
parsePtr->numTokens++;
src++;
numBytes--;
continue;
}
|
| ︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 |
int append) /* Non-zero means append tokens to existing
* information in parsePtr; zero means ignore
* existing tokens in parsePtr and
* reinitialize it. */
{
Tcl_Token *tokenPtr;
const char *src;
| | | 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 |
int append) /* Non-zero means append tokens to existing
* information in parsePtr; zero means ignore
* existing tokens in parsePtr and
* reinitialize it. */
{
Tcl_Token *tokenPtr;
const char *src;
int varIndex;
unsigned array;
if (numBytes < 0 && start) {
numBytes = strlen(start);
}
if (!append) {
TclParseInit(interp, start, numBytes, parsePtr);
|
| ︙ | ︙ | |||
1394 1395 1396 1397 1398 1399 1400 |
case '}':
braceCount--;
break;
case '\\':
/* if 2 or more left, consume 2, else consume
* just the \ and let it run into the end */
if (numBytes > 1) {
| < | | 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 |
case '}':
braceCount--;
break;
case '\\':
/* if 2 or more left, consume 2, else consume
* just the \ and let it run into the end */
if (numBytes > 1) {
src++; numBytes--;
}
}
numBytes--;
src++;
ch= *src;
}
if (numBytes == 0) {
|
| ︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 |
Tcl_Interp *interp, /* Interpreter to use for error reporting; if
* NULL, then no error message is provided. */
const char *start, /* Start of string enclosed in braces. The
* first character must be {'. */
Tcl_Size numBytes, /* Total number of bytes in string. If -1,
* the string consists of all bytes up to the
* first null character. */
| > | | 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 |
Tcl_Interp *interp, /* Interpreter to use for error reporting; if
* NULL, then no error message is provided. */
const char *start, /* Start of string enclosed in braces. The
* first character must be {'. */
Tcl_Size numBytes, /* Total number of bytes in string. If -1,
* the string consists of all bytes up to the
* first null character. */
Tcl_Parse *parsePtr,
/* Structure to fill in with information about
* the string. */
int append, /* Non-zero means append tokens to existing
* information in parsePtr; zero means ignore
* existing tokens in parsePtr and
* reinitialize it. */
const char **termPtr) /* If non-NULL, points to word in which to
* store a pointer to the character just after
|
| ︙ | ︙ | |||
1650 1651 1652 1653 1654 1655 1656 |
TclGrowParseTokenArray(parsePtr, 1);
tokenPtr = &parsePtr->tokenPtr[startIndex];
tokenPtr->type = TCL_TOKEN_TEXT;
tokenPtr->start = src+1;
tokenPtr->numComponents = 0;
level = 1;
| | | 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 |
TclGrowParseTokenArray(parsePtr, 1);
tokenPtr = &parsePtr->tokenPtr[startIndex];
tokenPtr->type = TCL_TOKEN_TEXT;
tokenPtr->start = src+1;
tokenPtr->numComponents = 0;
level = 1;
while (1) {
while (++src, --numBytes) {
if (CHAR_TYPE(*src) != TYPE_NORMAL) {
break;
}
}
if (numBytes == 0) {
goto missingBraceError;
|
| ︙ | ︙ | |||
1753 1754 1755 1756 1757 1758 1759 |
* Guess if the problem is due to comments by searching the source string
* for a possible open brace within the context of a comment. Since we
* aren't performing a full Tcl parse, just look for an open brace
* preceded by a '<whitespace>#' on the same line.
*/
{
| | | | | 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 |
* Guess if the problem is due to comments by searching the source string
* for a possible open brace within the context of a comment. Since we
* aren't performing a full Tcl parse, just look for an open brace
* preceded by a '<whitespace>#' on the same line.
*/
{
int openBrace = 0;
while (--src > start) {
switch (*src) {
case '{':
openBrace = 1;
break;
case '\n':
openBrace = 0;
break;
case '#' :
if (openBrace && TclIsSpaceProcM(src[-1])) {
Tcl_AppendToObj(Tcl_GetObjResult(parsePtr->interp),
": possible unbalanced brace in comment", -1);
goto error;
}
|
| ︙ | ︙ | |||
1816 1817 1818 1819 1820 1821 1822 |
Tcl_Interp *interp, /* Interpreter to use for error reporting; if
* NULL, then no error message is provided. */
const char *start, /* Start of the quoted string. The first
* character must be '"'. */
Tcl_Size numBytes, /* Total number of bytes in string. If -1,
* the string consists of all bytes up to the
* first null character. */
| > | | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 |
Tcl_Interp *interp, /* Interpreter to use for error reporting; if
* NULL, then no error message is provided. */
const char *start, /* Start of the quoted string. The first
* character must be '"'. */
Tcl_Size numBytes, /* Total number of bytes in string. If -1,
* the string consists of all bytes up to the
* first null character. */
Tcl_Parse *parsePtr,
/* Structure to fill in with information about
* the string. */
int append, /* Non-zero means append tokens to existing
* information in parsePtr; zero means ignore
* existing tokens in parsePtr and
* reinitialize it. */
const char **termPtr) /* If non-NULL, points to word in which to
* store a pointer to the character just after
|
| ︙ | ︙ | |||
2094 2095 2096 2097 2098 2099 2100 |
Tcl_Interp *interp, /* Interpreter in which to lookup variables,
* execute nested commands, and report
* errors. */
Tcl_Token *tokenPtr, /* Pointer to first in an array of tokens to
* evaluate and concatenate. */
Tcl_Size count, /* Number of tokens to consider at tokenPtr.
* Must be at least 1. */
| | | | 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 |
Tcl_Interp *interp, /* Interpreter in which to lookup variables,
* execute nested commands, and report
* errors. */
Tcl_Token *tokenPtr, /* Pointer to first in an array of tokens to
* evaluate and concatenate. */
Tcl_Size count, /* Number of tokens to consider at tokenPtr.
* Must be at least 1. */
int *tokensLeftPtr, /* If not NULL, points to memory where an
* integer representing the number of tokens
* left to be substituted will be written */
Tcl_Size line, /* The line the script starts on. */
Tcl_Size *clNextOuter, /* Information about an outer context for */
const char *outerScript) /* continuation line data. This is set by
* EvalEx() to properly handle [...]-nested
* commands. The 'outerScript' refers to the
* most-outer script containing the embedded
* command, which is refered to by 'script'.
* The 'clNextOuter' refers to the current
|
| ︙ | ︙ | |||
2119 2120 2121 2122 2123 2124 2125 |
* command. See Tcl_EvalEx and TclEvalObjEx
* for the places generating arguments for
* which this is true. */
{
Tcl_Obj *result;
int code = TCL_OK;
#define NUM_STATIC_POS 20
| | | 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 |
* command. See Tcl_EvalEx and TclEvalObjEx
* for the places generating arguments for
* which this is true. */
{
Tcl_Obj *result;
int code = TCL_OK;
#define NUM_STATIC_POS 20
int isLiteral;
Tcl_Size i, maxNumCL, numCL, adjust;
Tcl_Size *clPosition = NULL;
Interp *iPtr = (Interp *) interp;
int inFile = iPtr->evalFlags & TCL_EVAL_FILE;
/*
* Each pass through this loop will substitute one token, and its
|
| ︙ | ︙ | |||
2145 2146 2147 2148 2149 2150 2151 |
* processing. Otherwise preallocate a small table to store the
* locations of all continuation lines we find in this literal, if any.
* The table is extended if needed.
*/
numCL = 0;
maxNumCL = 0;
| | | | | 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 |
* processing. Otherwise preallocate a small table to store the
* locations of all continuation lines we find in this literal, if any.
* The table is extended if needed.
*/
numCL = 0;
maxNumCL = 0;
isLiteral = 1;
for (i=0 ; i < count; i++) {
if ((tokenPtr[i].type != TCL_TOKEN_TEXT)
&& (tokenPtr[i].type != TCL_TOKEN_BS)) {
isLiteral = 0;
break;
}
}
if (isLiteral) {
maxNumCL = NUM_STATIC_POS;
clPosition = (Tcl_Size *)Tcl_Alloc(maxNumCL * sizeof(Tcl_Size));
}
adjust = 0;
result = NULL;
for (; count>0 && code==TCL_OK ; count--, tokenPtr++) {
Tcl_Obj *appendObj = NULL;
const char *append = NULL;
int appendByteLength = 0;
char utfCharBytes[4] = "";
switch (tokenPtr->type) {
case TCL_TOKEN_TEXT:
append = tokenPtr->start;
appendByteLength = tokenPtr->size;
break;
|
| ︙ | ︙ | |||
2389 2390 2391 2392 2393 2394 2395 | * CommandComplete -- * * This function is shared by TclCommandComplete and * Tcl_ObjCommandComplete; it does all the real work of seeing whether a * script is complete * * Results: | | | | | > | > > > | 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 |
* CommandComplete --
*
* This function is shared by TclCommandComplete and
* Tcl_ObjCommandComplete; it does all the real work of seeing whether a
* script is complete
*
* Results:
* 1 is returned if the script is complete, 0 if there are open
* delimiters such as " or (. 1 is also returned if there is a parse
* error in the script other than unmatched delimiters.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
CommandComplete(
const char *script, /* Script to check. */
Tcl_Size numBytes) /* Number of bytes in script. */
{
Tcl_Parse parse;
const char *p, *end;
int result;
p = script;
end = p + numBytes;
while (Tcl_ParseCommand(NULL, p, end - p, 0, &parse) == TCL_OK) {
p = parse.commandStart + parse.commandSize;
if (p >= end) {
break;
}
Tcl_FreeParse(&parse);
}
if (parse.incomplete) {
result = 0;
} else {
result = 1;
}
Tcl_FreeParse(&parse);
return result;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ |
Changes to generic/tclPathObj.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | static Tcl_Obj * AppendPath(Tcl_Obj *head, Tcl_Obj *tail); static void DupFsPathInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); static void FreeFsPathInternalRep(Tcl_Obj *pathPtr); static void UpdateStringOfFsPath(Tcl_Obj *pathPtr); static int SetFsPathFromAny(Tcl_Interp *interp, Tcl_Obj *pathPtr); static Tcl_Size FindSplitPos(const char *path, int separator); | | | | | | | | | | | | | | | | | | | | | < < | | | | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
static Tcl_Obj * AppendPath(Tcl_Obj *head, Tcl_Obj *tail);
static void DupFsPathInternalRep(Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr);
static void FreeFsPathInternalRep(Tcl_Obj *pathPtr);
static void UpdateStringOfFsPath(Tcl_Obj *pathPtr);
static int SetFsPathFromAny(Tcl_Interp *interp, Tcl_Obj *pathPtr);
static Tcl_Size FindSplitPos(const char *path, int separator);
static int IsSeparatorOrNull(int ch);
static Tcl_Obj * GetExtension(Tcl_Obj *pathPtr);
static int MakePathFromNormalized(Tcl_Interp *interp,
Tcl_Obj *pathPtr);
static int MakeTildeRelativePath(Tcl_Interp *interp,
const char *user, const char *subPath,
Tcl_DString *dsPtr);
/*
* Define the 'path' object type, which Tcl uses to represent file paths
* internally.
*/
static const Tcl_ObjType fsPathType = {
"path", /* name */
FreeFsPathInternalRep, /* freeIntRepProc */
DupFsPathInternalRep, /* dupIntRepProc */
UpdateStringOfFsPath, /* updateStringProc */
SetFsPathFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
/*
* struct FsPath --
*
* Internal representation of a Tcl_Obj of fsPathType
*/
typedef struct {
Tcl_Obj *translatedPathPtr; /* If the path has been normalized (flags ==
* 0), this is NULL. Otherwise it is a path
* in which any ~user sequences have been
* translated away. */
Tcl_Obj *normPathPtr; /* If the path has been normalized (flags ==
* 0), this is an absolute path without ., ..
* or ~user components. Otherwise it is a
* path, possibly absolute, to normalize
* relative to cwdPtr. */
Tcl_Obj *cwdPtr; /* If NULL, either translatedPtr exists or
* normPathPtr exists and is absolute. */
int flags; /* Flags to describe interpretation - see
* below. */
void *nativePathPtr; /* Native representation of this path, which
* is filesystem dependent. */
size_t filesystemEpoch; /* Used to ensure the path representation was
* generated during the correct filesystem
* epoch. The epoch changes when
* filesystem-mounts are changed. */
const Tcl_Filesystem *fsPtr;/* The Tcl_Filesystem that claims this path */
} FsPath;
/*
* Flag values for FsPath->flags.
*/
#define TCLPATH_APPENDED 1
#define TCLPATH_NEEDNORM 4
/*
* Define some macros to give us convenient access to path-object specific
* fields.
*/
#define PATHOBJ(pathPtr) ((FsPath *) (TclFetchInternalRep((pathPtr), &fsPathType)->twoPtrValue.ptr1))
#define SETPATHOBJ(pathPtr,fsPathPtr) \
do { \
Tcl_ObjInternalRep ir; \
ir.twoPtrValue.ptr1 = (void *) (fsPathPtr); \
ir.twoPtrValue.ptr2 = NULL; \
Tcl_StoreInternalRep((pathPtr), &fsPathType, &ir); \
} while (0)
#define PATHFLAGS(pathPtr) (PATHOBJ(pathPtr)->flags)
/*
*---------------------------------------------------------------------------
*
* TclFSNormalizeAbsolutePath --
*
|
| ︙ | ︙ | |||
137 138 139 140 141 142 143 |
Tcl_Obj *
TclFSNormalizeAbsolutePath(
Tcl_Interp *interp, /* Interpreter to use */
Tcl_Obj *pathPtr) /* Absolute path to normalize */
{
const char *dirSep, *oldDirSep;
| | | | | | | | | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
Tcl_Obj *
TclFSNormalizeAbsolutePath(
Tcl_Interp *interp, /* Interpreter to use */
Tcl_Obj *pathPtr) /* Absolute path to normalize */
{
const char *dirSep, *oldDirSep;
int first = 1; /* Set to zero once we've passed the first
* directory separator - we can't use '..' to
* remove the volume in a path. */
Tcl_Obj *retVal = NULL;
int zipVolumeLen;
dirSep = TclGetString(pathPtr);
zipVolumeLen = TclIsZipfsPath(dirSep);
if (zipVolumeLen) {
/*
* NOTE: file normalization for zipfs is very specific to
* format of zipfs volume being of the form //xxx:/
*/
dirSep += zipVolumeLen-1; /* Start parse after : */
} else if (tclPlatform == TCL_PLATFORM_WINDOWS) {
if ( (dirSep[0] == '/' || dirSep[0] == '\\')
&& (dirSep[1] == '/' || dirSep[1] == '\\')
&& (dirSep[2] == '?')
&& (dirSep[3] == '/' || dirSep[3] == '\\')) {
/* NT extended path */
dirSep += 4;
if ( (dirSep[0] == 'U' || dirSep[0] == 'u')
&& (dirSep[1] == 'N' || dirSep[1] == 'n')
&& (dirSep[2] == 'C' || dirSep[2] == 'c')
&& (dirSep[3] == '/' || dirSep[3] == '\\')) {
/* NT extended UNC path */
dirSep += 4;
}
}
if (dirSep[0] != 0 && dirSep[1] == ':' &&
(dirSep[2] == '/' || dirSep[2] == '\\')) {
/* Do nothing */
|
| ︙ | ︙ | |||
360 361 362 363 364 365 366 |
if (dirSep[0] != 0 && dirSep[1] == '.') {
goto again;
}
continue;
}
}
| | | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
if (dirSep[0] != 0 && dirSep[1] == '.') {
goto again;
}
continue;
}
}
first = 0;
if (retVal != NULL) {
Tcl_AppendToObj(retVal, oldDirSep, dirSep - oldDirSep);
}
}
/*
* If we didn't make any changes, just use the input path.
|
| ︙ | ︙ | |||
398 399 400 401 402 403 404 |
}
/*
* Ensure a windows drive like C:/ has a trailing separator.
* Likewise for zipfs volumes.
*/
if (zipVolumeLen || (tclPlatform == TCL_PLATFORM_WINDOWS)) {
| | | | | 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 |
}
/*
* Ensure a windows drive like C:/ has a trailing separator.
* Likewise for zipfs volumes.
*/
if (zipVolumeLen || (tclPlatform == TCL_PLATFORM_WINDOWS)) {
int needTrailingSlash = 0;
Tcl_Size len;
const char *path = TclGetStringFromObj(retVal, &len);
if (zipVolumeLen) {
if (len == (zipVolumeLen - 1)) {
needTrailingSlash = 1;
}
} else {
if (len == 2 && path[0] != 0 && path[1] == ':') {
needTrailingSlash = 1;
}
}
if (needTrailingSlash) {
if (Tcl_IsShared(retVal)) {
TclDecrRefCount(retVal);
retVal = Tcl_DuplicateObj(retVal);
Tcl_IncrRefCount(retVal);
|
| ︙ | ︙ | |||
669 670 671 672 673 674 675 | * suffix removed. Do that by joining our "head" to * our "tail" with the extension suffix removed from * the tail. */ Tcl_Obj *resultPtr = TclNewFSPathObj(fsPathPtr->cwdPtr, fileName, | | | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | * suffix removed. Do that by joining our "head" to * our "tail" with the extension suffix removed from * the tail. */ Tcl_Obj *resultPtr = TclNewFSPathObj(fsPathPtr->cwdPtr, fileName, length - strlen(extension)); Tcl_IncrRefCount(resultPtr); return resultPtr; } } default: TCL_UNREACHABLE(); |
| ︙ | ︙ | |||
755 756 757 758 759 760 761 |
Tcl_IncrRefCount(resultPtr);
TclDecrRefCount(splitPtr);
return resultPtr;
}
}
/*
| < < | | < | < < | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
Tcl_IncrRefCount(resultPtr);
TclDecrRefCount(splitPtr);
return resultPtr;
}
}
/*
* Simple helper function
*/
static Tcl_Obj *
GetExtension(
Tcl_Obj *pathPtr)
{
const char *tail, *extension;
Tcl_Obj *ret;
|
| ︙ | ︙ | |||
831 832 833 834 835 836 837 |
if (TclListObjLength(NULL, listObj, &objc) != TCL_OK) {
return NULL;
}
elements = ((elements >= 0) && (elements <= objc)) ? elements : objc;
TclListObjGetElements(NULL, listObj, &objc, &objv);
| | | | | 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 |
if (TclListObjLength(NULL, listObj, &objc) != TCL_OK) {
return NULL;
}
elements = ((elements >= 0) && (elements <= objc)) ? elements : objc;
TclListObjGetElements(NULL, listObj, &objc, &objv);
res = TclJoinPath(elements, objv, 0);
return res;
}
Tcl_Obj *
TclJoinPath(
Tcl_Size elements, /* Number of elements to use */
Tcl_Obj * const objv[], /* Path elements to join */
int forceRelative) /* If non-zero, assume all more paths are
* relative (e.g. simple normalization) */
{
Tcl_Obj *res = NULL;
Tcl_Size i;
const Tcl_Filesystem *fsPtr = NULL;
if (elements == 0) {
|
| ︙ | ︙ | |||
912 913 914 915 916 917 918 919 |
* Finally, on Windows, 'file join' is defined to convert
* all backslashes to forward slashes, so the base part
* cannot have backslashes either.
*/
if ((tclPlatform != TCL_PLATFORM_WINDOWS)
|| (strchr(TclGetString(elt), '\\') == NULL)) {
if (PATHFLAGS(elt)) {
| > | | | | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 |
* Finally, on Windows, 'file join' is defined to convert
* all backslashes to forward slashes, so the base part
* cannot have backslashes either.
*/
if ((tclPlatform != TCL_PLATFORM_WINDOWS)
|| (strchr(TclGetString(elt), '\\') == NULL)) {
if (PATHFLAGS(elt)) {
return TclNewFSPathObj(elt, str, len);
}
if (TCL_PATH_ABSOLUTE != Tcl_FSGetPathType(elt)) {
return TclNewFSPathObj(elt, str, len);
}
(void) Tcl_FSGetNormalizedPath(NULL, elt);
if (elt == PATHOBJ(elt)->normPathPtr) {
return TclNewFSPathObj(elt, str, len);
}
}
}
/*
* Otherwise we don't have an easy join, and we must let the
* more general code below handle things.
|
| ︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 |
Tcl_StoreInternalRep(pathPtr, &fsPathType, NULL);
}
return SetFsPathFromAny(interp, pathPtr);
}
/*
| < < < < | | | < | | | | | < < < < | | | | | < | | 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 |
Tcl_StoreInternalRep(pathPtr, &fsPathType, NULL);
}
return SetFsPathFromAny(interp, pathPtr);
}
/*
* Helper function for normalization.
*/
static int
IsSeparatorOrNull(
int ch)
{
if (ch == 0) {
return 1;
}
switch (tclPlatform) {
case TCL_PLATFORM_UNIX:
return (ch == '/' ? 1 : 0);
case TCL_PLATFORM_WINDOWS:
return ((ch == '/' || ch == '\\') ? 1 : 0);
}
return 0;
}
/*
* Helper function for SetFsPathFromAny. Returns position of first directory
* delimiter in the path. If no separator is found, then returns the position
* of the end of the string.
*/
static Tcl_Size
FindSplitPos(
const char *path,
int separator)
{
int count = 0;
switch (tclPlatform) {
case TCL_PLATFORM_UNIX:
while (path[count] != 0) {
if (path[count] == separator) {
return count;
}
count++;
|
| ︙ | ︙ | |||
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 | * TclNewFSPathObj -- * * Creates a path object whose string representation is '[file join * dirPtr addStrRep]', but does so in a way that allows for more * efficient creation and caching of normalized paths, and more efficient * 'file dirname', 'file tail', etc. * * Results: * The new Tcl object, with refCount zero. * * Side effects: * Memory is allocated. 'dirPtr' gets an additional refCount. * *--------------------------------------------------------------------------- */ Tcl_Obj * TclNewFSPathObj( | > > > | | | < | | | | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 |
* TclNewFSPathObj --
*
* Creates a path object whose string representation is '[file join
* dirPtr addStrRep]', but does so in a way that allows for more
* efficient creation and caching of normalized paths, and more efficient
* 'file dirname', 'file tail', etc.
*
* Assumptions:
* 'dirPtr' must be an absolute path. 'len' may not be zero.
*
* Results:
* The new Tcl object, with refCount zero.
*
* Side effects:
* Memory is allocated. 'dirPtr' gets an additional refCount.
*
*---------------------------------------------------------------------------
*/
Tcl_Obj *
TclNewFSPathObj(
Tcl_Obj *dirPtr,
const char *addStrRep,
Tcl_Size len)
{
FsPath *fsPathPtr;
Tcl_Obj *pathPtr;
#ifndef _WIN32
int state = 0, count = 0;
#endif
/*
* This comment is kept from the days of tilde expansion because
* it is illustrative of a more general problem.
* [Bug 2806250] - this is only a partial solution of the problem.
* The PATHFLAGS != 0 representation assumes in many places that
* the "tail" part stored in the normPathPtr field is itself a
|
| ︙ | ︙ | |||
1307 1308 1309 1310 1311 1312 1313 |
fsPathPtr->fsPtr = NULL;
fsPathPtr->filesystemEpoch = 0;
SETPATHOBJ(pathPtr, fsPathPtr);
PATHFLAGS(pathPtr) = TCLPATH_APPENDED;
TclInvalidateStringRep(pathPtr);
| | | | | | < < | < < | < < < < < < < < < > | | > | 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 |
fsPathPtr->fsPtr = NULL;
fsPathPtr->filesystemEpoch = 0;
SETPATHOBJ(pathPtr, fsPathPtr);
PATHFLAGS(pathPtr) = TCLPATH_APPENDED;
TclInvalidateStringRep(pathPtr);
#ifdef _WIN32
/*
* On Windows, paths are case insensitive but normalization means the
* path should match the exact case of the on-disk file entry. Since we
* do not know whether that is the case at this point, mark the path
* as needing normalization. Bug [108904173c]
*/
PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM;
#else
/*
* Look for path components made up of only "."
* This is overly conservative analysis to keep simple. It may mark some
* things as needing more aggressive normalization that don't actually
* need it. No harm done.
*/
const char *p;
for (p = addStrRep; len > 0; p++, len--) {
switch (state) {
case 0: /* So far only "." since last dirsep or start */
switch (*p) {
case '.':
count = 1;
break;
case '/':
case '\\':
case ':':
if (count) {
PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM;
len = 0;
}
break;
default:
count = 0;
state = 1;
}
break;
case 1: /* Scanning for next dirsep */
switch (*p) {
case '/':
case '\\':
case ':':
state = 0;
break;
}
}
}
if (len == 0 && count) {
PATHFLAGS(pathPtr) |= TCLPATH_NEEDNORM;
}
#endif
return pathPtr;
}
static Tcl_Obj *
AppendPath(
Tcl_Obj *head,
|
| ︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 |
Tcl_ObjInternalRep *translatedCwdIrPtr;
if (translatedCwdPtr == NULL) {
return NULL;
}
retObj = TclFSJoinPathHelper(translatedCwdPtr, 1,
| | | 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 |
Tcl_ObjInternalRep *translatedCwdIrPtr;
if (translatedCwdPtr == NULL) {
return NULL;
}
retObj = TclFSJoinPathHelper(translatedCwdPtr, 1,
&srcFsPathPtr->normPathPtr, 1);
Tcl_IncrRefCount(srcFsPathPtr->translatedPathPtr = retObj);
translatedCwdIrPtr = TclFetchInternalRep(translatedCwdPtr, &fsPathType);
if (translatedCwdIrPtr) {
srcFsPathPtr->filesystemEpoch
= PATHOBJ(translatedCwdPtr)->filesystemEpoch;
} else {
srcFsPathPtr->filesystemEpoch = 0;
|
| ︙ | ︙ | |||
2210 2211 2212 2213 2214 2215 2216 |
if (firstPtr == NULL || secondPtr == NULL) {
return 0;
}
firstStr = TclGetStringFromObj(firstPtr, &firstLen);
secondStr = TclGetStringFromObj(secondPtr, &secondLen);
| | | 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 |
if (firstPtr == NULL || secondPtr == NULL) {
return 0;
}
firstStr = TclGetStringFromObj(firstPtr, &firstLen);
secondStr = TclGetStringFromObj(secondPtr, &secondLen);
return ((firstLen == secondLen) && !memcmp(firstStr, secondStr, firstLen));
}
/*
*---------------------------------------------------------------------------
*
* SetFsPathFromAny --
*
|
| ︙ | ︙ | |||
2258 2259 2260 2261 2262 2263 2264 |
*
* However, the split/join routines are quite complex, and one has to make
* sure not to break anything on Unix or Win (fCmd.test, fileName.test and
* cmdAH.test exercise most of the code).
*/
TclGetStringFromObj(pathPtr, &len); /* TODO: Is this needed? */
| | | 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 |
*
* However, the split/join routines are quite complex, and one has to make
* sure not to break anything on Unix or Win (fCmd.test, fileName.test and
* cmdAH.test exercise most of the code).
*/
TclGetStringFromObj(pathPtr, &len); /* TODO: Is this needed? */
transPtr = TclJoinPath(1, &pathPtr, 1);
/*
* Now we have a translated filename in 'transPtr'. This will have forward
* slashes on Windows, and will not contain any ~user sequences.
*/
fsPathPtr = (FsPath *)Tcl_Alloc(sizeof(FsPath));
|
| ︙ | ︙ | |||
2397 2398 2399 2400 2401 2402 2403 |
if (PATHFLAGS(pathPtr) == 0 || fsPathPtr->cwdPtr == NULL) {
if (fsPathPtr->translatedPathPtr == NULL) {
Tcl_Panic("Called UpdateStringOfFsPath with invalid object");
} else {
copy = Tcl_DuplicateObj(fsPathPtr->translatedPathPtr);
}
} else {
| | | 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 |
if (PATHFLAGS(pathPtr) == 0 || fsPathPtr->cwdPtr == NULL) {
if (fsPathPtr->translatedPathPtr == NULL) {
Tcl_Panic("Called UpdateStringOfFsPath with invalid object");
} else {
copy = Tcl_DuplicateObj(fsPathPtr->translatedPathPtr);
}
} else {
copy = AppendPath(fsPathPtr->cwdPtr, fsPathPtr->normPathPtr);
}
if (Tcl_IsShared(copy)) {
copy = Tcl_DuplicateObj(copy);
}
Tcl_IncrRefCount(copy);
|
| ︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 | } /* *---------------------------------------------------------------------- * * MakeTildeRelativePath -- * | | | | | 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 |
}
/*
*----------------------------------------------------------------------
*
* MakeTildeRelativePath --
*
* Returns a path relative to the home directory of a user.
* Note there is a difference between not specifying a user and
* explicitly specifying the current user. This mimics Tcl8's tilde
* expansion.
*
* The subPath argument is joined to the expanded home directory
* as in Tcl_JoinPath. This means if it is not relative, it will
* returned as the result with the home directory only checked
* for user name validity.
*
* Results:
* Returns TCL_OK on success with home directory path in *dsPtr
* and TCL_ERROR on failure with error message in interp if non-NULL.
*
*----------------------------------------------------------------------
*/
int
MakeTildeRelativePath(
Tcl_Interp *interp, /* May be NULL. Only used for error messages */
const char *user, /* User name. NULL -> current user */
const char *subPath, /* Rest of path. May be NULL */
Tcl_DString *dsPtr) /* Output. Is initialized by the function. Must
* be freed on success */
{
|
| ︙ | ︙ | |||
2567 2568 2569 2570 2571 2572 2573 | *---------------------------------------------------------------------- * * TclGetHomeDirObj -- * * Wrapper around MakeTildeRelativePath. See that function. * * Results: | | | 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 |
*----------------------------------------------------------------------
*
* TclGetHomeDirObj --
*
* Wrapper around MakeTildeRelativePath. See that function.
*
* Results:
* Returns a Tcl_Obj containing the home directory of a user
* or NULL on failure with error message in interp if non-NULL.
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclGetHomeDirObj(
Tcl_Interp *interp, /* May be NULL. Only used for error messages */
|
| ︙ | ︙ | |||
2592 2593 2594 2595 2596 2597 2598 | /* *---------------------------------------------------------------------- * * Tcl_FSTildeExpand -- * * Copies the path passed in to the output Tcl_DString dsPtr, * resolving leading ~ and ~user components in the path if present. | | | | | < | | | | > | 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 |
/*
*----------------------------------------------------------------------
*
* Tcl_FSTildeExpand --
*
* Copies the path passed in to the output Tcl_DString dsPtr,
* resolving leading ~ and ~user components in the path if present.
* An error is returned if such a component IS present AND cannot
* be resolved.
*
* The output dsPtr must be cleared by caller on success.
*
* Results:
* TCL_OK - path did not contain leading ~ or it was successful resolved
* TCL_ERROR - ~ component could not be resolved.
*
*----------------------------------------------------------------------
*/
int Tcl_FSTildeExpand(
Tcl_Interp *interp, /* May be NULL. Only used for error messages */
const char *path, /* Path to resolve tilde */
Tcl_DString *dsPtr) /* Output DString for resolved path. */
{
Tcl_Size split;
int result;
assert(path);
assert(dsPtr);
|
| ︙ | ︙ | |||
2643 2644 2645 2646 2647 2648 2649 | Tcl_DStringInit(&dsUser); Tcl_DStringAppend(&dsUser, path+1, split-1); user = Tcl_DStringValue(&dsUser); /* path[split] is / for ~user/... or \0 for ~user */ result = MakeTildeRelativePath(interp, user, | | | | | 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 |
Tcl_DStringInit(&dsUser);
Tcl_DStringAppend(&dsUser, path+1, split-1);
user = Tcl_DStringValue(&dsUser);
/* path[split] is / for ~user/... or \0 for ~user */
result = MakeTildeRelativePath(interp, user,
path[split] ? &path[split + 1] : NULL, dsPtr);
Tcl_DStringFree(&dsUser);
}
if (result != TCL_OK) {
/* Do not rely on caller to free in case of errors */
Tcl_DStringFree(dsPtr);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* TclResolveTildePath --
*
* If the passed path is begins with a tilde, does tilde resolution
* and returns a Tcl_Obj containing the resolved path. If the tilde
* component cannot be resolved, returns NULL. If the path does not
* begin with a tilde, returns as is.
*
* Results:
* Returns a Tcl_Obj with resolved path. This may be a new Tcl_Obj
* with ref count 0 or that pathObj that was passed in without its
* ref count modified.
* Returns NULL if the path begins with a ~ that cannot be resolved
* and stores an error message in interp if non-NULL.
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
TclResolveTildePath(
Tcl_Interp *interp, /* May be NULL. Only used for error messages */
|
| ︙ | ︙ | |||
2703 2704 2705 2706 2707 2708 2709 | * * TclResolveTildePathList -- * * Given a Tcl_Obj that is a list of paths, returns a Tcl_Obj containing * the paths with any ~-prefixed paths resolved. * * Empty strings and ~-prefixed paths that cannot be resolved are | | | | 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 | * * TclResolveTildePathList -- * * Given a Tcl_Obj that is a list of paths, returns a Tcl_Obj containing * the paths with any ~-prefixed paths resolved. * * Empty strings and ~-prefixed paths that cannot be resolved are * removed from the returned list. * * The trailing components of the path are returned verbatim. No * processing is done on them. Moreover, no assumptions should be * made about the separators in the returned path. They may be / * or native. Appropriate path manipulations functions should be * used by caller if desired. * * Results: * Returns a Tcl_Obj with resolved paths. This may be a new Tcl_Obj with |
| ︙ | ︙ | |||
2765 2766 2767 2768 2769 2770 2771 2772 2773 |
/* Paths that cannot be resolved are skipped */
Tcl_ListObjAppendElement(NULL, resolvedPaths, resolvedPath);
}
}
return resolvedPaths;
}
/*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 |
/* Paths that cannot be resolved are skipped */
Tcl_ListObjAppendElement(NULL, resolvedPaths, resolvedPath);
}
}
return resolvedPaths;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclPipe.c.
| ︙ | ︙ | |||
190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
for (i = 0; i < numPids; i++) {
detPtr = (Detached *)Tcl_Alloc(sizeof(Detached));
detPtr->pid = pidPtr[i];
detPtr->nextPtr = detList;
detList = detPtr;
}
Tcl_MutexUnlock(&pipeMutex);
}
/*
*----------------------------------------------------------------------
*
* Tcl_ReapDetachedProcs --
*
| > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
for (i = 0; i < numPids; i++) {
detPtr = (Detached *)Tcl_Alloc(sizeof(Detached));
detPtr->pid = pidPtr[i];
detPtr->nextPtr = detList;
detList = detPtr;
}
Tcl_MutexUnlock(&pipeMutex);
}
/*
*----------------------------------------------------------------------
*
* Tcl_ReapDetachedProcs --
*
|
| ︙ | ︙ | |||
325 326 327 328 329 330 331 |
anyErrorInfo = 0;
if (errorChan != NULL) {
/*
* Make sure we start at the beginning of the file.
*/
if (interp != NULL) {
| | | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
anyErrorInfo = 0;
if (errorChan != NULL) {
/*
* Make sure we start at the beginning of the file.
*/
if (interp != NULL) {
int count;
Tcl_Obj *objPtr;
Tcl_Seek(errorChan, 0, SEEK_SET);
TclNewObj(objPtr);
count = Tcl_ReadChars(errorChan, objPtr, TCL_INDEX_NONE, 0);
if (count == -1) {
result = TCL_ERROR;
|
| ︙ | ︙ |
Changes to generic/tclPkg.c.
| ︙ | ︙ | |||
46 47 48 49 50 51 52 |
typedef struct PkgFiles {
PkgName *names; /* Package names being initialized. Must be
* first field. */
Tcl_HashTable table; /* Table which contains files for each
* package. */
} PkgFiles;
| < < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
typedef struct PkgFiles {
PkgName *names; /* Package names being initialized. Must be
* first field. */
Tcl_HashTable table; /* Table which contains files for each
* package. */
} PkgFiles;
/*
* For each package that is known in any way to an interpreter, there is one
* record of the following type. These records are stored in the
* "packageTable" hash table in the interpreter, keyed by package name such as
* "Tk" (no version number).
*/
|
| ︙ | ︙ | |||
85 86 87 88 89 90 91 | static int CheckVersionAndConvert(Tcl_Interp *interp, const char *string, char **internal, int *stable); static int CompareVersions(char *v1i, char *v2i, int *isMajorPtr); static int CheckRequirement(Tcl_Interp *interp, const char *string); | | | | | < | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | static int CheckVersionAndConvert(Tcl_Interp *interp, const char *string, char **internal, int *stable); static int CompareVersions(char *v1i, char *v2i, int *isMajorPtr); static int CheckRequirement(Tcl_Interp *interp, const char *string); static int CheckAllRequirements(Tcl_Interp *interp, int reqc, Tcl_Obj *const reqv[]); static int RequirementSatisfied(char *havei, const char *req); static int SomeRequirementSatisfied(char *havei, int reqc, Tcl_Obj *const reqv[]); static void AddRequirementsToResult(Tcl_Interp *interp, int reqc, Tcl_Obj *const reqv[]); static void AddRequirementsToDString(Tcl_DString *dstring, int reqc, Tcl_Obj *const reqv[]); static Package * FindPackage(Tcl_Interp *interp, const char *name); static int PkgRequireCore(void *data[], Tcl_Interp *interp, int result); static int PkgRequireCoreFinal(void *data[], Tcl_Interp *interp, int result); static int PkgRequireCoreCleanup(void *data[], Tcl_Interp *interp, int result); static int PkgRequireCoreStep1(void *data[], Tcl_Interp *interp, int result); static int PkgRequireCoreStep2(void *data[], Tcl_Interp *interp, int result); static int TclNRPkgRequireProc(void *clientData, Tcl_Interp *interp, int reqc, Tcl_Obj *const reqv[]); static int SelectPackage(void *data[], Tcl_Interp *interp, int result); static int SelectPackageFinal(void *data[], Tcl_Interp *interp, int result); static int TclNRPackageObjCmdCleanup(void *data[], Tcl_Interp *interp, int result); /* * Helper macros. */ |
| ︙ | ︙ | |||
258 259 260 261 262 263 264 |
TclInitPkgFiles(
Tcl_Interp *interp)
{
/*
* If assocdata "tclPkgFiles" doesn't exist yet, create it.
*/
| | | | > | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
TclInitPkgFiles(
Tcl_Interp *interp)
{
/*
* If assocdata "tclPkgFiles" doesn't exist yet, create it.
*/
PkgFiles *pkgFiles = (PkgFiles *)Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
if (!pkgFiles) {
pkgFiles = (PkgFiles *)Tcl_Alloc(sizeof(PkgFiles));
pkgFiles->names = NULL;
Tcl_InitHashTable(&pkgFiles->table, TCL_STRING_KEYS);
Tcl_SetAssocData(interp, "tclPkgFiles", PkgFilesCleanupProc, pkgFiles);
}
return pkgFiles;
}
void
TclPkgFileSeen(
Tcl_Interp *interp,
const char *fileName)
{
PkgFiles *pkgFiles = (PkgFiles *)
Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
if (pkgFiles && pkgFiles->names) {
const char *name = pkgFiles->names->name;
Tcl_HashTable *table = &pkgFiles->table;
int isNew;
Tcl_HashEntry *entry = (Tcl_HashEntry *)Tcl_CreateHashEntry(table, name, &isNew);
Tcl_Obj *list;
|
| ︙ | ︙ | |||
435 436 437 438 439 440 441 |
* available. */
void *clientDataPtr)
{
RequireProcArgs args;
args.name = name;
args.clientDataPtr = clientDataPtr;
| | | | > | | | > | | | | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
* available. */
void *clientDataPtr)
{
RequireProcArgs args;
args.name = name;
args.clientDataPtr = clientDataPtr;
return Tcl_NRCallObjProc(interp,
TclNRPkgRequireProc, (void *) &args, reqc, reqv);
}
static int
TclNRPkgRequireProc(
void *clientData,
Tcl_Interp *interp,
int reqc,
Tcl_Obj *const reqv[])
{
RequireProcArgs *args = (RequireProcArgs *)clientData;
Tcl_NRAddCallback(interp,
PkgRequireCore, (void *) args->name, INT2PTR(reqc), (void *) reqv,
args->clientDataPtr);
return TCL_OK;
}
static int
PkgRequireCore(
void *data[],
Tcl_Interp *interp,
TCL_UNUSED(int))
{
const char *name = (const char *)data[0];
int reqc = (int)PTR2INT(data[1]);
Tcl_Obj **reqv = (Tcl_Obj **)data[2];
int code = CheckAllRequirements(interp, reqc, reqv);
Require *reqPtr;
if (code != TCL_OK) {
return code;
}
reqPtr = (Require *)Tcl_Alloc(sizeof(Require));
Tcl_NRAddCallback(interp, PkgRequireCoreCleanup, reqPtr, NULL, NULL, NULL);
reqPtr->clientDataPtr = data[3];
reqPtr->name = name;
reqPtr->pkgPtr = FindPackage(interp, name);
if (reqPtr->pkgPtr->version == NULL) {
Tcl_NRAddCallback(interp,
SelectPackage, reqPtr, INT2PTR(reqc), reqv,
(void *)PkgRequireCoreStep1);
} else {
Tcl_NRAddCallback(interp,
PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), reqv, NULL);
}
return TCL_OK;
}
static int
PkgRequireCoreStep1(
void *data[],
|
| ︙ | ︙ | |||
502 503 504 505 506 507 508 |
/*
* If we've got the package in the DB already, go on to actually loading
* it.
*/
if (reqPtr->pkgPtr->version != NULL) {
| | | | | | | | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
/*
* If we've got the package in the DB already, go on to actually loading
* it.
*/
if (reqPtr->pkgPtr->version != NULL) {
Tcl_NRAddCallback(interp,
PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
return TCL_OK;
}
/*
* The package is not in the database. If there is a "package unknown"
* command, invoke it.
*/
script = ((Interp *) interp)->packageUnknown;
if (script == NULL) {
/*
* No package unknown script. Move on to finalizing.
*/
Tcl_NRAddCallback(interp,
PkgRequireCoreFinal, reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
return TCL_OK;
}
/*
* Invoke the "package unknown" script synchronously.
*/
Tcl_DStringInit(&command);
Tcl_DStringAppend(&command, script, -1);
Tcl_DStringAppendElement(&command, name);
AddRequirementsToDString(&command, reqc, reqv);
Tcl_NRAddCallback(interp,
PkgRequireCoreStep2, reqPtr, INT2PTR(reqc), (void *) reqv, NULL);
Tcl_NREvalObj(interp, Tcl_DStringToObj(&command), TCL_EVAL_GLOBAL);
return TCL_OK;
}
static int
PkgRequireCoreStep2(
void *data[],
|
| ︙ | ︙ | |||
567 568 569 570 571 572 573 |
Tcl_ResetResult(interp);
/*
* pkgPtr may now be invalid, so refresh it.
*/
reqPtr->pkgPtr = FindPackage(interp, name);
| | > | | | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
Tcl_ResetResult(interp);
/*
* pkgPtr may now be invalid, so refresh it.
*/
reqPtr->pkgPtr = FindPackage(interp, name);
Tcl_NRAddCallback(interp,
SelectPackage, reqPtr, INT2PTR(reqc), reqv,
(void *)PkgRequireCoreFinal);
return TCL_OK;
}
static int
PkgRequireCoreFinal(
void *data[],
Tcl_Interp *interp,
TCL_UNUSED(int))
{
Require *reqPtr = (Require *)data[0];
int reqc = (int)PTR2INT(data[1]), satisfies;
Tcl_Obj **const reqv = (Tcl_Obj **)data[2];
char *pkgVersionI;
void *clientDataPtr = reqPtr->clientDataPtr;
const char *name = reqPtr->name; /* Name of desired package. */
if (reqPtr->pkgPtr->version == NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
| ︙ | ︙ | |||
645 646 647 648 649 650 651 |
TCL_UNUSED(int))
{
PkgAvail *availPtr, *bestPtr, *bestStablePtr;
char *availVersion, *bestVersion, *bestStableVersion;
/* Internal rep. of versions */
int availStable, satisfies;
Require *reqPtr = (Require *)data[0];
| | | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 |
TCL_UNUSED(int))
{
PkgAvail *availPtr, *bestPtr, *bestStablePtr;
char *availVersion, *bestVersion, *bestStableVersion;
/* Internal rep. of versions */
int availStable, satisfies;
Require *reqPtr = (Require *)data[0];
int reqc = (int)PTR2INT(data[1]);
Tcl_Obj **const reqv = (Tcl_Obj **)data[2];
const char *name = reqPtr->name;
Package *pkgPtr = reqPtr->pkgPtr;
Interp *iPtr = (Interp *) interp;
/*
* Check whether we're already attempting to load some version of this
|
| ︙ | ︙ | |||
797 798 799 800 801 802 803 |
if ((iPtr->packagePrefer == PKG_PREFER_STABLE)
&& (bestStablePtr != NULL)) {
bestPtr = bestStablePtr;
}
if (bestPtr == NULL) {
| | | | 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 |
if ((iPtr->packagePrefer == PKG_PREFER_STABLE)
&& (bestStablePtr != NULL)) {
bestPtr = bestStablePtr;
}
if (bestPtr == NULL) {
Tcl_NRAddCallback(interp,
(Tcl_NRPostProc *)data[3], reqPtr, INT2PTR(reqc), (void *)reqv, NULL);
} else {
/*
* We found an ifneeded script for the package. Be careful while
* executing it: this could cause reentrancy, so (a) protect the
* script itself from deletion and (b) don't assume that bestPtr will
* still exist when the script completes.
*/
|
| ︙ | ︙ | |||
828 829 830 831 832 833 834 |
pkgName->nextPtr = pkgFiles->names;
strcpy(pkgName->name, name);
pkgFiles->names = pkgName;
if (bestPtr->pkgIndex) {
TclPkgFileSeen(interp, bestPtr->pkgIndex);
}
reqPtr->versionToProvide = versionToProvide;
| | | > | 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
pkgName->nextPtr = pkgFiles->names;
strcpy(pkgName->name, name);
pkgFiles->names = pkgName;
if (bestPtr->pkgIndex) {
TclPkgFileSeen(interp, bestPtr->pkgIndex);
}
reqPtr->versionToProvide = versionToProvide;
Tcl_NRAddCallback(interp,
SelectPackageFinal, reqPtr, INT2PTR(reqc), (void *)reqv,
data[3]);
Tcl_NREvalObj(interp, Tcl_NewStringObj(bestPtr->script, -1),
TCL_EVAL_GLOBAL);
}
return TCL_OK;
}
static int
|
| ︙ | ︙ | |||
852 853 854 855 856 857 858 |
const char *name = reqPtr->name;
char *versionToProvide = reqPtr->versionToProvide;
/*
* Pop the "ifneeded" package name from "tclPkgFiles" assocdata
*/
| | | 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 |
const char *name = reqPtr->name;
char *versionToProvide = reqPtr->versionToProvide;
/*
* Pop the "ifneeded" package name from "tclPkgFiles" assocdata
*/
PkgFiles *pkgFiles = (PkgFiles *)Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
PkgName *pkgName = pkgFiles->names;
pkgFiles->names = pkgName->nextPtr;
Tcl_Free(pkgName);
reqPtr->pkgPtr = FindPackage(interp, name);
if (result == TCL_OK) {
Tcl_ResetResult(interp);
|
| ︙ | ︙ | |||
934 935 936 937 938 939 940 |
Tcl_DecrRefCount(reqPtr->pkgPtr->version);
reqPtr->pkgPtr->version = NULL;
}
reqPtr->pkgPtr->clientData = NULL;
return result;
}
| | | | 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 |
Tcl_DecrRefCount(reqPtr->pkgPtr->version);
reqPtr->pkgPtr->version = NULL;
}
reqPtr->pkgPtr->clientData = NULL;
return result;
}
Tcl_NRAddCallback(interp,
(Tcl_NRPostProc *)data[3], reqPtr, INT2PTR(reqc), (void *) reqv, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tcl_PkgPresent / Tcl_PkgPresentEx --
|
| ︙ | ︙ | |||
1046 1047 1048 1049 1050 1051 1052 |
*
*----------------------------------------------------------------------
*/
int
Tcl_PackageObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 |
*
*----------------------------------------------------------------------
*/
int
Tcl_PackageObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRPackageObjCmd, clientData, objc, objv);
}
int
TclNRPackageObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const pkgOptions[] = {
"files", "forget", "ifneeded", "names", "prefer",
"present", "provide", "require", "unknown", "vcompare",
"versions", "vsatisfies", NULL
};
enum pkgOptionsEnum {
|
| ︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 |
switch (optionIndex) {
case PKG_FILES: {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "package");
return TCL_ERROR;
}
PkgFiles *pkgFiles = (PkgFiles *)
| | | | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 |
switch (optionIndex) {
case PKG_FILES: {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "package");
return TCL_ERROR;
}
PkgFiles *pkgFiles = (PkgFiles *)
Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
if (pkgFiles) {
Tcl_HashEntry *entry = Tcl_FindHashEntry(&pkgFiles->table,
TclGetString(objv[2]));
if (entry) {
Tcl_SetObjResult(interp, (Tcl_Obj *)Tcl_GetHashValue(entry));
}
}
break;
}
case PKG_FORGET: {
PkgFiles *pkgFiles = (PkgFiles *)
Tcl_GetAssocData(interp, "tclPkgFiles", NULL);
for (i = 2; i < objc; i++) {
const char *keyString = TclGetString(objv[i]);
if (pkgFiles) {
hPtr = Tcl_FindHashEntry(&pkgFiles->table, keyString);
if (hPtr) {
Tcl_Obj *obj = (Tcl_Obj *)Tcl_GetHashValue(hPtr);
|
| ︙ | ︙ | |||
1353 1354 1355 1356 1357 1358 1359 | Tcl_IncrRefCount(objv[3]); objvListPtr = Tcl_NewListObj(0, NULL); Tcl_IncrRefCount(objvListPtr); Tcl_ListObjAppendElement(interp, objvListPtr, ov); TclListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr); | | | | > | | 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 |
Tcl_IncrRefCount(objv[3]);
objvListPtr = Tcl_NewListObj(0, NULL);
Tcl_IncrRefCount(objvListPtr);
Tcl_ListObjAppendElement(interp, objvListPtr, ov);
TclListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr);
Tcl_NRAddCallback(interp,
TclNRPackageObjCmdCleanup, objv[3], objvListPtr, NULL,NULL);
Tcl_NRAddCallback(interp,
PkgRequireCore, (void *) argv3, INT2PTR(newobjc),
newObjvPtr, NULL);
return TCL_OK;
} else {
Tcl_Obj *const *newobjv = objv + 3;
newobjc = objc - 3;
if (CheckAllRequirements(interp, objc-3, objv+3) != TCL_OK) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
1378 1379 1380 1381 1382 1383 1384 | * so duplicate them. */ Tcl_ListObjAppendElement(interp, objvListPtr, Tcl_DuplicateObj(newobjv[i])); } TclListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr); | | | | > | | 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 |
* so duplicate them.
*/
Tcl_ListObjAppendElement(interp, objvListPtr,
Tcl_DuplicateObj(newobjv[i]));
}
TclListObjGetElements(interp, objvListPtr, &newobjc, &newObjvPtr);
Tcl_NRAddCallback(interp,
TclNRPackageObjCmdCleanup, objv[2], objvListPtr, NULL,NULL);
Tcl_NRAddCallback(interp,
PkgRequireCore, (void *) argv2, INT2PTR(newobjc),
newObjvPtr, NULL);
return TCL_OK;
}
break;
case PKG_UNKNOWN:
if (objc == 2) {
if (iPtr->packageUnknown != NULL) {
Tcl_SetObjResult(interp,
|
| ︙ | ︙ | |||
1944 1945 1946 1947 1948 1949 1950 |
*
*----------------------------------------------------------------------
*/
static int
CheckAllRequirements(
Tcl_Interp *interp,
| | | | 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 |
*
*----------------------------------------------------------------------
*/
static int
CheckAllRequirements(
Tcl_Interp *interp,
int reqc, /* Requirements to check. */
Tcl_Obj *const reqv[])
{
int i;
for (i = 0; i < reqc; i++) {
if ((CheckRequirement(interp, TclGetString(reqv[i])) != TCL_OK)) {
return TCL_ERROR;
}
}
return TCL_OK;
|
| ︙ | ︙ | |||
2050 2051 2052 2053 2054 2055 2056 |
*
*----------------------------------------------------------------------
*/
static void
AddRequirementsToResult(
Tcl_Interp *interp,
| | | 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 |
*
*----------------------------------------------------------------------
*/
static void
AddRequirementsToResult(
Tcl_Interp *interp,
int reqc, /* Requirements constraining the desired
* version. */
Tcl_Obj *const reqv[]) /* 0 means to use the latest version
* available. */
{
Tcl_Obj *result = Tcl_GetObjResult(interp);
int i;
Tcl_Size length;
|
| ︙ | ︙ | |||
2130 2131 2132 2133 2134 2135 2136 |
*----------------------------------------------------------------------
*/
static int
SomeRequirementSatisfied(
char *availVersionI, /* Candidate version to check against the
* requirements. */
| | | | 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 |
*----------------------------------------------------------------------
*/
static int
SomeRequirementSatisfied(
char *availVersionI, /* Candidate version to check against the
* requirements. */
int reqc, /* Requirements constraining the desired
* version. */
Tcl_Obj *const reqv[]) /* 0 means to use the latest version
* available. */
{
int i;
for (i = 0; i < reqc; i++) {
if (RequirementSatisfied(availVersionI, TclGetString(reqv[i]))) {
return 1;
}
}
return 0;
|
| ︙ | ︙ |
Changes to generic/tclPkgConfig.c.
| ︙ | ︙ | |||
89 90 91 92 93 94 95 | #ifdef TCL_CFG_PROFILED # define CFG_PROFILED "1" #else # define CFG_PROFILED "0" #endif /* | | | | | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | #ifdef TCL_CFG_PROFILED # define CFG_PROFILED "1" #else # define CFG_PROFILED "0" #endif /* The macOS framework build first installs the framework in the build directory and then copies it to /Library/Frameworks/Tcl.framework. Without these macros the pkgconfig paths point into the build directory instead of into the installed framework. */ #if defined(MAC_OSX_TCL) && defined(TCL_FRAMEWORK) #define VERSION_DIR "/Library/Frameworks/Tcl.framework/Versions/"TCL_VERSION #undef CFG_INSTALL_LIBDIR #undef CFG_RUNTIME_LIBDIR #undef CFG_INSTALL_BINDIR #undef CFG_RUNTIME_BINDIR |
| ︙ | ︙ |
Changes to generic/tclPlatDecls.h.
1 2 3 4 5 | /* * tclPlatDecls.h -- * * Declarations of platform specific Tcl APIs. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * tclPlatDecls.h -- * * Declarations of platform specific Tcl APIs. * * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. */ #ifndef _TCLPLATDECLS #define _TCLPLATDECLS #undef TCL_STORAGE_CLASS |
| ︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# ifdef __cplusplus
# define MODULE_SCOPE extern "C"
# else
# define MODULE_SCOPE extern
# endif
#endif
/* !BEGIN!: Do not edit below this line. */
#ifdef __cplusplus
extern "C" {
#endif
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# ifdef __cplusplus
# define MODULE_SCOPE extern "C"
# else
# define MODULE_SCOPE extern
# endif
#endif
#if TCL_MAJOR_VERSION < 9
#ifdef __cplusplus
extern "C" {
#endif
/*
* Exported function declarations:
*/
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
/* 0 */
EXTERN TCHAR * Tcl_WinUtfToTChar(const char *str, int len,
Tcl_DString *dsPtr);
/* 1 */
EXTERN char * Tcl_WinTCharToUtf(const TCHAR *str, int len,
Tcl_DString *dsPtr);
/* Slot 2 is reserved */
/* 3 */
EXTERN void Tcl_WinConvertError(unsigned errCode);
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
/* 0 */
EXTERN int Tcl_MacOSXOpenBundleResources(Tcl_Interp *interp,
const char *bundleName, int hasResourceFile,
Tcl_Size maxPathLen, char *libraryPath);
/* 1 */
EXTERN int Tcl_MacOSXOpenVersionedBundleResources(
Tcl_Interp *interp, const char *bundleName,
const char *bundleVersion,
int hasResourceFile, Tcl_Size maxPathLen,
char *libraryPath);
/* 2 */
EXTERN void Tcl_MacOSXNotifierAddRunLoopMode(
const void *runLoopMode);
#endif /* MACOSX */
typedef struct TclPlatStubs {
int magic;
void *hooks;
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
TCHAR * (*tcl_WinUtfToTChar) (const char *str, int len, Tcl_DString *dsPtr); /* 0 */
char * (*tcl_WinTCharToUtf) (const TCHAR *str, int len, Tcl_DString *dsPtr); /* 1 */
void (*reserved2)(void);
void (*tcl_WinConvertError) (unsigned errCode); /* 3 */
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
int (*tcl_MacOSXOpenBundleResources) (Tcl_Interp *interp, const char *bundleName, int hasResourceFile, Tcl_Size maxPathLen, char *libraryPath); /* 0 */
int (*tcl_MacOSXOpenVersionedBundleResources) (Tcl_Interp *interp, const char *bundleName, const char *bundleVersion, int hasResourceFile, Tcl_Size maxPathLen, char *libraryPath); /* 1 */
void (*tcl_MacOSXNotifierAddRunLoopMode) (const void *runLoopMode); /* 2 */
#endif /* MACOSX */
} TclPlatStubs;
extern const TclPlatStubs *tclPlatStubsPtr;
#ifdef __cplusplus
}
#endif
#if defined(USE_TCL_STUBS)
/*
* Inline function declarations:
*/
#if defined(_WIN32) || defined(__CYGWIN__) /* WIN */
#define Tcl_WinUtfToTChar \
(tclPlatStubsPtr->tcl_WinUtfToTChar) /* 0 */
#define Tcl_WinTCharToUtf \
(tclPlatStubsPtr->tcl_WinTCharToUtf) /* 1 */
/* Slot 2 is reserved */
#define Tcl_WinConvertError \
(tclPlatStubsPtr->tcl_WinConvertError) /* 3 */
#endif /* WIN */
#ifdef MAC_OSX_TCL /* MACOSX */
#define Tcl_MacOSXOpenBundleResources \
(tclPlatStubsPtr->tcl_MacOSXOpenBundleResources) /* 0 */
#define Tcl_MacOSXOpenVersionedBundleResources \
(tclPlatStubsPtr->tcl_MacOSXOpenVersionedBundleResources) /* 1 */
#define Tcl_MacOSXNotifierAddRunLoopMode \
(tclPlatStubsPtr->tcl_MacOSXNotifierAddRunLoopMode) /* 2 */
#endif /* MACOSX */
#endif /* defined(USE_TCL_STUBS) */
#else /* TCL_MAJOR_VERSION > 8 */
/* !BEGIN!: Do not edit below this line. */
#ifdef __cplusplus
extern "C" {
#endif
/*
|
| ︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | (tclPlatStubsPtr->tcl_MacOSXNotifierAddRunLoopMode) /* 2 */ #define Tcl_WinConvertError \ (tclPlatStubsPtr->tcl_WinConvertError) /* 3 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #ifdef MAC_OSX_TCL /* MACOSX */ #undef Tcl_MacOSXOpenBundleResources #define Tcl_MacOSXOpenBundleResources(a,b,c,d,e) Tcl_MacOSXOpenVersionedBundleResources(a,b,NULL,c,d,e) #endif #undef TCL_STORAGE_CLASS | > > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | (tclPlatStubsPtr->tcl_MacOSXNotifierAddRunLoopMode) /* 2 */ #define Tcl_WinConvertError \ (tclPlatStubsPtr->tcl_WinConvertError) /* 3 */ #endif /* defined(USE_TCL_STUBS) */ /* !END!: Do not edit above this line. */ #endif /* TCL_MAJOR_VERSION */ #ifdef MAC_OSX_TCL /* MACOSX */ #undef Tcl_MacOSXOpenBundleResources #define Tcl_MacOSXOpenBundleResources(a,b,c,d,e) Tcl_MacOSXOpenVersionedBundleResources(a,b,NULL,c,d,e) #endif #undef TCL_STORAGE_CLASS |
| ︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | # undef Tcl_WinConvertError #endif #ifndef MAC_OSX_TCL # undef Tcl_MacOSXOpenVersionedBundleResources # undef Tcl_MacOSXNotifierAddRunLoopMode #endif #ifdef _WIN32 #define Tcl_WinUtfToTChar(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ (TCHAR *)Tcl_UtfToChar16DString((string), (len), (dsPtr))) #define Tcl_WinTCharToUtf(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ Tcl_Char16ToUtfDString((const unsigned short *)(string), ((((len) + 2) >> 1) - 1), (dsPtr))) #endif #endif /* _TCLPLATDECLS */ | > > > > > | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | # undef Tcl_WinConvertError #endif #ifndef MAC_OSX_TCL # undef Tcl_MacOSXOpenVersionedBundleResources # undef Tcl_MacOSXNotifierAddRunLoopMode #endif #if defined(USE_TCL_STUBS) && (defined(_WIN32) || defined(__CYGWIN__))\ && (defined(TCL_NO_DEPRECATED) || TCL_MAJOR_VERSION > 8) #undef Tcl_WinUtfToTChar #undef Tcl_WinTCharToUtf #ifdef _WIN32 #define Tcl_WinUtfToTChar(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ (TCHAR *)Tcl_UtfToChar16DString((string), (len), (dsPtr))) #define Tcl_WinTCharToUtf(string, len, dsPtr) (Tcl_DStringInit(dsPtr), \ Tcl_Char16ToUtfDString((const unsigned short *)(string), ((((len) + 2) >> 1) - 1), (dsPtr))) #endif #endif #endif /* _TCLPLATDECLS */ |
Changes to generic/tclPort.h.
1 2 3 4 5 6 7 | /* * tclPort.h -- * * This header file handles porting issues that occur because * of differences between systems. It reads in platform specific * portability files. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * tclPort.h -- * * This header file handles porting issues that occur because * of differences between systems. It reads in platform specific * portability files. * * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLPORT #define _TCLPORT |
| ︙ | ︙ |
Changes to generic/tclPosixStr.c.
| ︙ | ︙ | |||
378 379 380 381 382 383 384 |
#endif
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP))
case EOPNOTSUPP: return "EOPNOTSUPP";
#endif
#ifdef EOTHER
case EOTHER: return "EOTHER";
#endif
| | < | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 |
#endif
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP))
case EOPNOTSUPP: return "EOPNOTSUPP";
#endif
#ifdef EOTHER
case EOTHER: return "EOTHER";
#endif
#if defined(EOVERFLOW) && (!defined(EFBIG) || (EOVERFLOW != EFBIG)) && (!defined(EINVAL) || (EOVERFLOW != EINVAL))
case EOVERFLOW: return "EOVERFLOW";
#endif
#ifdef EOWNERDEAD
case EOWNERDEAD: return "EOWNERDEAD";
#endif
#ifdef EPERM
case EPERM: return "EPERM";
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 | * None. * *---------------------------------------------------------------------- */ const char * Tcl_ErrnoMsg( | | | 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
* None.
*
*----------------------------------------------------------------------
*/
const char *
Tcl_ErrnoMsg(
int err) /* Error number (such as in errno variable). */
{
switch (err) {
#if defined(E2BIG) && (!defined(EOVERFLOW) || (E2BIG != EOVERFLOW))
case E2BIG: return "argument list too long";
#endif
#ifdef EACCES
case EACCES: return "permission denied";
|
| ︙ | ︙ | |||
872 873 874 875 876 877 878 |
#endif
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP))
case EOPNOTSUPP: return "operation not supported on socket";
#endif
#ifdef EOTHER
case EOTHER: return "other error";
#endif
| | < | 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 |
#endif
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || (ENOTSUP != EOPNOTSUPP))
case EOPNOTSUPP: return "operation not supported on socket";
#endif
#ifdef EOTHER
case EOTHER: return "other error";
#endif
#if defined(EOVERFLOW) && (!defined(EFBIG) || (EOVERFLOW != EFBIG)) && (!defined(EINVAL) || (EOVERFLOW != EINVAL))
case EOVERFLOW: return "value too large for defined data type";
#endif
#ifdef EOWNERDEAD
case EOWNERDEAD: return "owner died";
#endif
#ifdef EPERM
case EPERM: return "operation not permitted";
|
| ︙ | ︙ | |||
1028 1029 1030 1031 1032 1033 1034 | * None. * *---------------------------------------------------------------------- */ const char * Tcl_SignalId( | | | 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
* None.
*
*----------------------------------------------------------------------
*/
const char *
Tcl_SignalId(
int sig) /* Number of signal. */
{
switch (sig) {
#ifdef SIGABRT
case SIGABRT: return "SIGABRT";
#endif
#ifdef SIGALRM
case SIGALRM: return "SIGALRM";
|
| ︙ | ︙ | |||
1073 1074 1075 1076 1077 1078 1079 |
#endif
#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT))
case SIGIOT: return "SIGIOT";
#endif
#ifdef SIGKILL
case SIGKILL: return "SIGKILL";
#endif
| | < < < | < | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 |
#endif
#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGIOT != SIGABRT))
case SIGIOT: return "SIGIOT";
#endif
#ifdef SIGKILL
case SIGKILL: return "SIGKILL";
#endif
#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG)) && (!defined(SIGPROF) || (SIGLOST != SIGPROF)) && (!defined(SIGIO) || (SIGLOST != SIGIO))
case SIGLOST: return "SIGLOST";
#endif
#ifdef SIGPIPE
case SIGPIPE: return "SIGPIPE";
#endif
#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO))
case SIGPOLL: return "SIGPOLL";
#endif
#ifdef SIGPROF
case SIGPROF: return "SIGPROF";
#endif
#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ)) && (!defined(SIGLOST) || (SIGPWR != SIGLOST))
case SIGPWR: return "SIGPWR";
#endif
#ifdef SIGQUIT
case SIGQUIT: return "SIGQUIT";
#endif
#if defined(SIGSEGV) && (!defined(SIGBUS) || (SIGSEGV != SIGBUS))
case SIGSEGV: return "SIGSEGV";
|
| ︙ | ︙ | |||
1166 1167 1168 1169 1170 1171 1172 | * None. * *---------------------------------------------------------------------- */ const char * Tcl_SignalMsg( | | | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 |
* None.
*
*----------------------------------------------------------------------
*/
const char *
Tcl_SignalMsg(
int sig) /* Number of signal. */
{
switch (sig) {
#ifdef SIGABRT
case SIGABRT: return "SIGABRT";
#endif
#ifdef SIGALRM
case SIGALRM: return "alarm clock";
|
| ︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 |
#endif
#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGABRT != SIGIOT))
case SIGIOT: return "IOT instruction";
#endif
#ifdef SIGKILL
case SIGKILL: return "kill signal";
#endif
| | < < < | < | 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 |
#endif
#if defined(SIGIOT) && (!defined(SIGABRT) || (SIGABRT != SIGIOT))
case SIGIOT: return "IOT instruction";
#endif
#ifdef SIGKILL
case SIGKILL: return "kill signal";
#endif
#if defined(SIGLOST) && (!defined(SIGIOT) || (SIGLOST != SIGIOT)) && (!defined(SIGURG) || (SIGLOST != SIGURG)) && (!defined(SIGPROF) || (SIGLOST != SIGPROF)) && (!defined(SIGIO) || (SIGLOST != SIGIO))
case SIGLOST: return "resource lost";
#endif
#ifdef SIGPIPE
case SIGPIPE: return "write on pipe with no readers";
#endif
#if defined(SIGPOLL) && (!defined(SIGIO) || (SIGPOLL != SIGIO))
case SIGPOLL: return "input/output possible on file";
#endif
#ifdef SIGPROF
case SIGPROF: return "profiling alarm";
#endif
#if defined(SIGPWR) && (!defined(SIGXFSZ) || (SIGPWR != SIGXFSZ)) && (!defined(SIGLOST) || (SIGPWR != SIGLOST))
case SIGPWR: return "power-fail restart";
#endif
#ifdef SIGQUIT
case SIGQUIT: return "quit signal";
#endif
#if defined(SIGSEGV) && (!defined(SIGBUS) || (SIGSEGV != SIGBUS))
case SIGSEGV: return "segmentation violation";
|
| ︙ | ︙ |
Changes to generic/tclProc.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #include "tclCompile.h" | | < < < < < < < < < | | | | > | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
#include "tclCompile.h"
#include <assert.h>
/*
* Prototypes for static functions in this file
*/
static void DupLambdaInternalRep(Tcl_Obj *objPtr,
Tcl_Obj *copyPtr);
static void FreeLambdaInternalRep(Tcl_Obj *objPtr);
static int InitArgsAndLocals(Tcl_Interp *interp, int skip);
static void InitResolvedLocals(Tcl_Interp *interp,
ByteCode *codePtr, Var *defPtr,
Namespace *nsPtr);
static void InitLocalCache(Proc *procPtr);
static void ProcBodyDup(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr);
static void ProcBodyFree(Tcl_Obj *objPtr);
static int ProcWrongNumArgs(Tcl_Interp *interp, int skip);
static void MakeProcError(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
static void MakeLambdaError(Tcl_Interp *interp,
Tcl_Obj *procNameObj);
static int SetLambdaFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static Tcl_NRPostProc InterpProcNR2;
static Tcl_NRPostProc Uplevel_Callback;
static Tcl_ObjCmdProc NRInterpProc;
/*
* The ProcBodyObjType type
*/
const Tcl_ObjType tclProcBodyType = {
"procbody", /* name for this type */
ProcBodyFree, /* FreeInternalRep function */
ProcBodyDup, /* DupInternalRep function */
NULL, /* UpdateString function; Tcl_GetString and
* Tcl_GetStringFromObj should panic
* instead. */
NULL, /* SetFromAny function; Tcl_ConvertToType
* should panic instead. */
TCL_OBJTYPE_V0
};
|
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
*
* Uses the default behaviour throughout, and never disposes of the string
* rep; it's just a cache type.
*/
static const Tcl_ObjType levelReferenceType = {
"levelReference",
| | | | | | | | | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
*
* Uses the default behaviour throughout, and never disposes of the string
* rep; it's just a cache type.
*/
static const Tcl_ObjType levelReferenceType = {
"levelReference",
NULL,
NULL,
NULL,
NULL,
TCL_OBJTYPE_V1(TclLengthOne)
};
/*
* The type of lambdas. Note that every lambda will *always* have a string
* representation.
*
* Internally, ptr1 is a pointer to a Proc instance that is not bound to a
* command name, and ptr2 is a pointer to the namespace that the Proc instance
* will execute within. IF YOU CHANGE THIS, CHECK IN tclDisassemble.c TOO.
*/
static const Tcl_ObjType lambdaType = {
"lambdaExpr", /* name */
FreeLambdaInternalRep, /* freeIntRepProc */
DupLambdaInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
SetLambdaFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define LambdaSetInternalRep(objPtr, procPtr, nsObjPtr) \
do { \
Tcl_ObjInternalRep ir; \
ir.twoPtrValue.ptr1 = (procPtr); \
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 | * * Side effects: * A new procedure gets created. * *---------------------------------------------------------------------- */ | | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
*
* Side effects:
* A new procedure gets created.
*
*----------------------------------------------------------------------
*/
#undef TclObjInterpProc
int
Tcl_ProcObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
Proc *procPtr;
const char *procName;
const char *simpleName, *procArgs, *procBody;
Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
Tcl_Command cmd;
|
| ︙ | ︙ | |||
205 206 207 208 209 210 211 |
Tcl_AddErrorInfo(interp, "\n (creating proc \"");
Tcl_AddErrorInfo(interp, simpleName);
Tcl_AddErrorInfo(interp, "\")");
return TCL_ERROR;
}
cmd = TclNRCreateCommandInNs(interp, simpleName, (Tcl_Namespace *) nsPtr,
| | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
Tcl_AddErrorInfo(interp, "\n (creating proc \"");
Tcl_AddErrorInfo(interp, simpleName);
Tcl_AddErrorInfo(interp, "\")");
return TCL_ERROR;
}
cmd = TclNRCreateCommandInNs(interp, simpleName, (Tcl_Namespace *) nsPtr,
TclObjInterpProc, NRInterpProc, procPtr, TclProcDeleteProc);
/*
* Now initialize the new procedure's cmdPtr field. This will be used
* later when the procedure is called to determine what namespace the
* procedure will run in. This will be different than the current
* namespace if the proc was renamed into a different namespace.
*/
|
| ︙ | ︙ | |||
265 266 267 268 269 270 271 |
&& (contextPtr->nline >= 4) && (contextPtr->line[3] >= 0)) {
int isNew;
Tcl_HashEntry *hePtr;
CmdFrame *cfPtr = (CmdFrame *)Tcl_Alloc(sizeof(CmdFrame));
cfPtr->level = -1;
cfPtr->type = contextPtr->type;
| | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
&& (contextPtr->nline >= 4) && (contextPtr->line[3] >= 0)) {
int isNew;
Tcl_HashEntry *hePtr;
CmdFrame *cfPtr = (CmdFrame *)Tcl_Alloc(sizeof(CmdFrame));
cfPtr->level = -1;
cfPtr->type = contextPtr->type;
cfPtr->line = (Tcl_Size *)Tcl_Alloc(sizeof(Tcl_Size));
cfPtr->line[0] = contextPtr->line[3];
cfPtr->nline = 1;
cfPtr->framePtr = NULL;
cfPtr->nextPtr = NULL;
cfPtr->data.eval.path = contextPtr->data.eval.path;
Tcl_IncrRefCount(cfPtr->data.eval.path);
|
| ︙ | ︙ | |||
478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
procPtr->iPtr = iPtr;
procPtr->refCount = 1;
procPtr->bodyPtr = bodyPtr;
procPtr->numArgs = 0; /* Actual argument count is set below. */
procPtr->numCompiledLocals = 0;
procPtr->firstLocalPtr = NULL;
procPtr->lastLocalPtr = NULL;
}
/*
* Break up the argument list into argument specifiers, then process each
* argument specifier. If the body is precompiled, processing is limited
* to checking that the parsed argument is consistent with the one stored
* in the Proc.
| > | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
procPtr->iPtr = iPtr;
procPtr->refCount = 1;
procPtr->bodyPtr = bodyPtr;
procPtr->numArgs = 0; /* Actual argument count is set below. */
procPtr->numCompiledLocals = 0;
procPtr->firstLocalPtr = NULL;
procPtr->lastLocalPtr = NULL;
procPtr->flags = 0;
}
/*
* Break up the argument list into argument specifiers, then process each
* argument specifier. If the body is precompiled, processing is limited
* to checking that the parsed argument is consistent with the one stored
* in the Proc.
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 |
result = TclListObjGetElements(interp, argArray[i], &fieldCount,
&fieldValues);
if (result != TCL_OK) {
goto procError;
}
if (fieldCount > 2) {
| | | | > > | 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
result = TclListObjGetElements(interp, argArray[i], &fieldCount,
&fieldValues);
if (result != TCL_OK) {
goto procError;
}
if (fieldCount > 2) {
Tcl_Obj *errorObj = Tcl_NewStringObj(
"too many fields in argument specifier \"", -1);
Tcl_AppendObjToObj(errorObj, argArray[i]);
Tcl_AppendToObj(errorObj, "\"", -1);
Tcl_SetObjResult(interp, errorObj);
errorCode = "FORMALARGUMENTFORMAT";
goto procError;
}
if ((fieldCount == 0) || (Tcl_GetCharLength(fieldValues[0]) == 0)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"argument with no name", -1));
errorCode = "FORMALARGUMENTFORMAT";
|
| ︙ | ︙ | |||
553 554 555 556 557 558 559 |
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"formal parameter \"%s\" is an array element",
TclGetString(fieldValues[0])));
errorCode = "FORMALARGUMENTFORMAT";
goto procError;
}
} else if (argnamei[0] == ':' && argnamei[1] == ':') {
| | | | > > | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 |
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"formal parameter \"%s\" is an array element",
TclGetString(fieldValues[0])));
errorCode = "FORMALARGUMENTFORMAT";
goto procError;
}
} else if (argnamei[0] == ':' && argnamei[1] == ':') {
Tcl_Obj *errorObj = Tcl_NewStringObj(
"formal parameter \"", -1);
Tcl_AppendObjToObj(errorObj, fieldValues[0]);
Tcl_AppendToObj(errorObj, "\" is not a simple name", -1);
Tcl_SetObjResult(interp, errorObj);
errorCode = "FORMALARGUMENTFORMAT";
goto procError;
}
argnamei++;
}
if (precompiled) {
|
| ︙ | ︙ | |||
598 599 600 601 602 603 604 |
if (localPtr->defValuePtr != NULL) {
Tcl_Size tmpLength, valueLength;
const char *tmpPtr = TclGetStringFromObj(localPtr->defValuePtr, &tmpLength);
const char *value = TclGetStringFromObj(fieldValues[1], &valueLength);
if ((valueLength != tmpLength)
|| memcmp(value, tmpPtr, tmpLength) != 0) {
| | | > > | < > | 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
if (localPtr->defValuePtr != NULL) {
Tcl_Size tmpLength, valueLength;
const char *tmpPtr = TclGetStringFromObj(localPtr->defValuePtr, &tmpLength);
const char *value = TclGetStringFromObj(fieldValues[1], &valueLength);
if ((valueLength != tmpLength)
|| memcmp(value, tmpPtr, tmpLength) != 0) {
Tcl_Obj *errorObj = Tcl_ObjPrintf(
"procedure \"%s\": formal parameter \"", procName);
Tcl_AppendObjToObj(errorObj, fieldValues[0]);
Tcl_AppendToObj(errorObj, "\" has "
"default value inconsistent with precompiled body", -1);
Tcl_SetObjResult(interp, errorObj);
errorCode = "BYTECODELIES";
goto procError;
}
}
if ((i == numArgs - 1)
&& (localPtr->nameLength == 4)
&& (localPtr->name[0] == 'a')
|
| ︙ | ︙ | |||
720 721 722 723 724 725 726 |
int
TclGetFrame(
Tcl_Interp *interp, /* Interpreter in which to find frame. */
const char *name, /* String describing frame. */
CallFrame **framePtrPtr) /* Store pointer to frame here (or NULL if
* global frame indicated). */
{
| | | | | | | | | | < < < < < | < | < | | | | 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 |
int
TclGetFrame(
Tcl_Interp *interp, /* Interpreter in which to find frame. */
const char *name, /* String describing frame. */
CallFrame **framePtrPtr) /* Store pointer to frame here (or NULL if
* global frame indicated). */
{
int result;
Tcl_Obj obj;
obj.bytes = (char *) name;
obj.length = strlen(name);
obj.typePtr = NULL;
result = TclObjGetFrame(interp, &obj, framePtrPtr);
TclFreeInternalRep(&obj);
return result;
}
/*
*----------------------------------------------------------------------
*
* TclObjGetFrame --
*
* Given a description of a procedure frame, such as the first argument
* to an "uplevel" or "upvar" command, locate the call frame for the
* appropriate level of procedure.
*
* Results:
* The return value is -1 if an error occurred in finding the frame (in
* this case an error message is left in the interp's result). 1 is
* returned if objPtr was either an int or an int preceded by "#" and
* it specified a valid frame. 0 is returned if objPtr isn't one of the
* two things above (in this case, the lookup acts as if objPtr were
* "1"). The variable pointed to by framePtrPtr is filled in with the
* address of the desired frame (unless an error occurs, in which case it
* isn't modified).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclObjGetFrame(
Tcl_Interp *interp, /* Interpreter in which to find frame. */
Tcl_Obj *objPtr, /* Object describing frame. */
CallFrame **framePtrPtr) /* Store pointer to frame here (or NULL if
* global frame indicated). */
{
Interp *iPtr = (Interp *) interp;
int curLevel, level, result;
const Tcl_ObjInternalRep *irPtr;
const char *name = NULL;
Tcl_WideInt w;
/*
* Parse object to figure out which level number to go to.
*/
result = 0;
curLevel = iPtr->varFramePtr->level;
/*
* Check for integer first, since that has potential to spare us
* a generation of a stringrep.
*/
if (objPtr == NULL) {
/* Do nothing */
} else if (TCL_OK == Tcl_GetIntFromObj(NULL, objPtr, &level)) {
TclGetWideIntFromObj(NULL, objPtr, &w);
if (w < 0 || w > INT_MAX || curLevel > w + INT_MAX) {
result = -1;
} else {
level = curLevel - level;
result = 1;
}
} else if ((irPtr = TclFetchInternalRep(objPtr, &levelReferenceType))) {
level = irPtr->wideValue;
result = 1;
} else {
name = TclGetString(objPtr);
if (name[0] == '#') {
if (TCL_OK == Tcl_GetInt(NULL, name+1, &level)) {
if (level < 0 || (level > 0 && name[1] == '-')) {
result = -1;
|
| ︙ | ︙ | |||
827 828 829 830 831 832 833 |
* Docs say we have to treat this as a 'bad level' error.
*/
result = -1;
}
}
if (result != -1) {
| < < < < | | 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 |
* Docs say we have to treat this as a 'bad level' error.
*/
result = -1;
}
}
if (result != -1) {
/* if relative current level */
if (result == 0) {
if (!curLevel) {
/* we are in top-level, so simply generate bad level */
name = "1";
goto badLevel;
}
level = curLevel - 1;
}
if (level >= 0) {
CallFrame *framePtr;
for (framePtr = iPtr->varFramePtr; framePtr != NULL;
framePtr = framePtr->callerVarPtr) {
if ((int)framePtr->level == level) {
*framePtrPtr = framePtr;
|
| ︙ | ︙ | |||
877 878 879 880 881 882 883 | * * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ | | | | 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 |
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
Uplevel_Callback(
void *data[],
Tcl_Interp *interp,
int result)
{
CallFrame *savedVarFramePtr = (CallFrame *)data[0];
if (result == TCL_ERROR) {
|
| ︙ | ︙ | |||
902 903 904 905 906 907 908 |
return result;
}
int
Tcl_UplevelObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | > > | 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 |
return result;
}
int
Tcl_UplevelObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRUplevelObjCmd, clientData, objc, objv);
}
int
TclNRUplevelObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
CmdFrame *invoker = NULL;
int word = 0;
int result;
CallFrame *savedVarFramePtr, *framePtr;
Tcl_Obj *objPtr;
if (objc < 2) {
/* to do
* simplify things by interpreting the argument as a command when there
* is only one argument. This requires a TIP since currently a single
* argument is interpreted as a level indicator if possible.
*/
uplevelSyntax:
Tcl_WrongNumArgs(interp, 1, objv, "?level? command ?arg ...?");
return TCL_ERROR;
} else if (!TclHasStringRep(objv[1]) && objc == 2) {
int status;
Tcl_Size llength;
status = TclListObjLength(interp, objv[1], &llength);
if (status == TCL_OK && llength > 1) {
/* the first argument can't interpreted as a level. Avoid
* generating a string representation of the script. */
|
| ︙ | ︙ | |||
961 962 963 964 965 966 967 |
}
objc -= result + 1;
if (objc == 0) {
goto uplevelSyntax;
}
objv += result + 1;
| | > | | < < < | 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
}
objc -= result + 1;
if (objc == 0) {
goto uplevelSyntax;
}
objv += result + 1;
havelevel:
/*
* Modify the interpreter state to execute in the given frame.
*/
savedVarFramePtr = iPtr->varFramePtr;
iPtr->varFramePtr = framePtr;
/*
* Execute the residual arguments as a command.
*/
if (objc == 1) {
/*
* TIP #280. Make actual argument location available to eval'd script
*/
TclArgumentGet(interp, objv[0], &invoker, &word);
objPtr = objv[0];
} else {
/*
* More than one argument: concatenate them together with spaces
* between, then evaluate the result. Tcl_EvalObjEx will delete the
* object when it decrements its refcount after eval'ing it.
*/
objPtr = Tcl_ConcatObj(objc, objv);
}
TclNRAddCallback(interp, Uplevel_Callback, savedVarFramePtr, NULL, NULL,
NULL);
return TclNREvalObjEx(interp, objPtr, 0, invoker, word);
}
/*
*----------------------------------------------------------------------
*
* TclFindProc --
*
|
| ︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 |
{
Tcl_Command origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (origCmd != NULL) {
cmdPtr = (Command *) origCmd;
}
if (cmdPtr->deleteProc == TclProcDeleteProc) {
| | | | 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 |
{
Tcl_Command origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (origCmd != NULL) {
cmdPtr = (Command *) origCmd;
}
if (cmdPtr->deleteProc == TclProcDeleteProc) {
return (Proc *)cmdPtr->objClientData;
}
return NULL;
}
static int
ProcWrongNumArgs(
Tcl_Interp *interp,
int skip)
{
CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
Proc *procPtr = framePtr->procPtr;
Tcl_Size localCt = procPtr->numCompiledLocals, numArgs, i;
Tcl_Obj **desiredObjs;
const char *final = NULL;
|
| ︙ | ︙ | |||
1159 1160 1161 1162 1163 1164 1165 |
ByteCode *codePtr,
Var *varPtr,
Namespace *nsPtr) /* Pointer to current namespace. */
{
Interp *iPtr = (Interp *) interp;
int haveResolvers = (nsPtr->compiledVarResProc || iPtr->resolverPtr);
CompiledLocal *firstLocalPtr, *localPtr;
| | | 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 |
ByteCode *codePtr,
Var *varPtr,
Namespace *nsPtr) /* Pointer to current namespace. */
{
Interp *iPtr = (Interp *) interp;
int haveResolvers = (nsPtr->compiledVarResProc || iPtr->resolverPtr);
CompiledLocal *firstLocalPtr, *localPtr;
int varNum;
Tcl_ResolvedVarInfo *resVarInfo;
/*
* Find the localPtr corresponding to varPtr
*/
varNum = varPtr - iPtr->framePtr->compiledLocals;
|
| ︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 |
*----------------------------------------------------------------------
*/
static int
InitArgsAndLocals(
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
| | | 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 |
*----------------------------------------------------------------------
*/
static int
InitArgsAndLocals(
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
int skip) /* Number of initial arguments to be skipped,
* i.e., words in the "command name". */
{
CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
Proc *procPtr = framePtr->procPtr;
ByteCode *codePtr;
Var *varPtr, *defPtr;
Tcl_Size localCt = procPtr->numCompiledLocals, numArgs, argCt, i, imax;
|
| ︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 |
TclPushProcCallFrame(
void *clientData, /* Record describing procedure to be
* interpreted. */
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
Tcl_Size objc, /* Count of number of arguments to this
* procedure. */
| | | 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 |
TclPushProcCallFrame(
void *clientData, /* Record describing procedure to be
* interpreted. */
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
Tcl_Size objc, /* Count of number of arguments to this
* procedure. */
Tcl_Obj *const objv[], /* Argument value objects. */
int isLambda) /* 1 if this is a call by ApplyObjCmd: it
* needs special rules for error msg */
{
Proc *procPtr = (Proc *)clientData;
Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
CallFrame *framePtr, **framePtrPtr;
int result;
|
| ︙ | ︙ | |||
1594 1595 1596 1597 1598 1599 1600 |
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
| | | | | | | | < | < | | | | | < | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 |
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclObjInterpProc --
*
* When a Tcl procedure gets invoked during bytecode evaluation, this
* object-based routine gets invoked to interpret the procedure.
*
* Results:
* A standard Tcl object result value.
*
* Side effects:
* Depends on the commands in the procedure.
*
*----------------------------------------------------------------------
*/
int
TclObjInterpProc(
void *clientData, /* Record describing procedure to be
* interpreted. */
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
int objc, /* Count of number of arguments to this
* procedure. */
Tcl_Obj *const objv[]) /* Argument value objects. */
{
/*
* Not used much in the core; external interface for iTcl
*/
return Tcl_NRCallObjProc(interp, NRInterpProc, clientData, objc, objv);
}
int
TclNRInterpProc(
void *clientData, /* Record describing procedure to be
* interpreted. */
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
Tcl_Size objc, /* Count of number of arguments to this
* procedure. */
Tcl_Obj *const objv[]) /* Argument value objects. */
{
int result = TclPushProcCallFrame(clientData, interp, objc, objv,
/*isLambda*/ 0);
if (result != TCL_OK) {
return TCL_ERROR;
}
return TclNRInterpProcCore(interp, objv[0], 1, &MakeProcError);
}
static int
NRInterpProc(
void *clientData, /* Record describing procedure to be
* interpreted. */
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
int objc, /* Count of number of arguments to this
* procedure. */
Tcl_Obj *const objv[]) /* Argument value objects. */
{
int result = TclPushProcCallFrame(clientData, interp, objc, objv,
/*isLambda*/ 0);
if (result != TCL_OK) {
return TCL_ERROR;
}
return TclNRInterpProcCore(interp, objv[0], 1, &MakeProcError);
}
static int
ObjInterpProc2(
void *clientData, /* Record describing procedure to be
* interpreted. */
Tcl_Interp *interp, /* Interpreter in which procedure was
* invoked. */
Tcl_Size objc, /* Count of number of arguments to this
* procedure. */
Tcl_Obj *const objv[]) /* Argument value objects. */
{
/*
* Not used much in the core; external interface for iTcl
*/
return Tcl_NRCallObjProc2(interp, TclNRInterpProc, clientData, objc, objv);
}
/*
*----------------------------------------------------------------------
*
* TclNRInterpProcCore --
*
* When a Tcl procedure, lambda term or anything else that works like a
|
| ︙ | ︙ | |||
1728 1729 1730 1731 1732 1733 1734 |
TclStackFree(interp, freePtr->compiledLocals);
/* Free compiledLocals. */
TclStackFree(interp, freePtr); /* Free CallFrame. */
return TCL_ERROR;
}
#if defined(TCL_COMPILE_DEBUG)
| | | | 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 |
TclStackFree(interp, freePtr->compiledLocals);
/* Free compiledLocals. */
TclStackFree(interp, freePtr); /* Free CallFrame. */
return TCL_ERROR;
}
#if defined(TCL_COMPILE_DEBUG)
if (tclTraceExec >= 1) {
CallFrame *framePtr = iPtr->varFramePtr;
Tcl_Size i;
if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
fprintf(stdout, "Calling lambda ");
} else {
fprintf(stdout, "Calling proc ");
}
for (i = 0; i < framePtr->objc; i++) {
TclPrintObject(stdout, framePtr->objv[i], 15);
fprintf(stdout, " ");
}
fprintf(stdout, "\n");
fflush(stdout);
}
#endif /*TCL_COMPILE_DEBUG*/
#ifdef USE_DTRACE
if (TCL_DTRACE_PROC_ARGS_ENABLED()) {
Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
const char *a[10];
Tcl_Size i;
for (i = 0 ; i < 10 ; i++) {
a[i] = (l < iPtr->varFramePtr->objc ?
TclGetString(iPtr->varFramePtr->objv[l]) : NULL);
l++;
|
| ︙ | ︙ | |||
1770 1771 1772 1773 1774 1775 1776 |
Tcl_Size i[2];
TclDTraceInfo(info, a, i);
TCL_DTRACE_PROC_INFO(a[0], a[1], a[2], a[3], i[0], i[1], a[4], a[5]);
TclDecrRefCount(info);
}
if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
| | | | 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 |
Tcl_Size i[2];
TclDTraceInfo(info, a, i);
TCL_DTRACE_PROC_INFO(a[0], a[1], a[2], a[3], i[0], i[1], a[4], a[5]);
TclDecrRefCount(info);
}
if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
TCL_DTRACE_PROC_ENTRY(l < iPtr->varFramePtr->objc ?
TclGetString(iPtr->varFramePtr->objv[l]) : NULL,
iPtr->varFramePtr->objc - l - 1,
(Tcl_Obj **)(iPtr->varFramePtr->objv + l + 1));
}
if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
TCL_DTRACE_PROC_ENTRY(l < iPtr->varFramePtr->objc ?
TclGetString(iPtr->varFramePtr->objv[l]) : NULL,
iPtr->varFramePtr->objc - l - 1,
(Tcl_Obj **)(iPtr->varFramePtr->objv + l + 1));
}
#endif /* USE_DTRACE */
|
| ︙ | ︙ | |||
1812 1813 1814 1815 1816 1817 1818 |
Interp *iPtr = (Interp *) interp;
Proc *procPtr = iPtr->varFramePtr->procPtr;
CallFrame *freePtr;
Tcl_Obj *procNameObj = (Tcl_Obj *)data[0];
ProcErrorProc *errorProc = (ProcErrorProc *)data[1];
if (TCL_DTRACE_PROC_RETURN_ENABLED()) {
| | | 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 |
Interp *iPtr = (Interp *) interp;
Proc *procPtr = iPtr->varFramePtr->procPtr;
CallFrame *freePtr;
Tcl_Obj *procNameObj = (Tcl_Obj *)data[0];
ProcErrorProc *errorProc = (ProcErrorProc *)data[1];
if (TCL_DTRACE_PROC_RETURN_ENABLED()) {
Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
TCL_DTRACE_PROC_RETURN(l < iPtr->varFramePtr->objc ?
TclGetString(iPtr->varFramePtr->objv[l]) : NULL, result);
}
if (procPtr->refCount-- <= 1) {
TclProcCleanupProc(procPtr);
}
|
| ︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 |
if (result != TCL_OK) {
goto process;
}
done:
if (TCL_DTRACE_PROC_RESULT_ENABLED()) {
| | | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 |
if (result != TCL_OK) {
goto process;
}
done:
if (TCL_DTRACE_PROC_RESULT_ENABLED()) {
Tcl_Size l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
Tcl_Obj *r = Tcl_GetObjResult(interp);
TCL_DTRACE_PROC_RESULT(l < iPtr->varFramePtr->objc ?
TclGetString(iPtr->varFramePtr->objv[l]) : NULL, result,
TclGetString(r), r);
}
|
| ︙ | ︙ | |||
1971 1972 1973 1974 1975 1976 1977 |
}
}
if (codePtr == NULL) {
Tcl_HashEntry *hePtr;
#ifdef TCL_COMPILE_DEBUG
| | | 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 |
}
}
if (codePtr == NULL) {
Tcl_HashEntry *hePtr;
#ifdef TCL_COMPILE_DEBUG
if (tclTraceCompile >= 1) {
/*
* Display a line summarizing the top level command we are about
* to compile.
*/
Tcl_Obj *message;
|
| ︙ | ︙ | |||
2006 2007 2008 2009 2010 2011 2012 |
*/
iPtr->compiledProcPtr = procPtr;
if (procPtr->numCompiledLocals > procPtr->numArgs) {
CompiledLocal *clPtr = procPtr->firstLocalPtr;
CompiledLocal *lastPtr = NULL;
| | | 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 |
*/
iPtr->compiledProcPtr = procPtr;
if (procPtr->numCompiledLocals > procPtr->numArgs) {
CompiledLocal *clPtr = procPtr->firstLocalPtr;
CompiledLocal *lastPtr = NULL;
int i, numArgs = procPtr->numArgs;
for (i = 0; i < numArgs; i++) {
lastPtr = clPtr;
clPtr = clPtr->nextPtr;
}
if (lastPtr) {
|
| ︙ | ︙ | |||
2071 2072 2073 2074 2075 2076 2077 | } /* *---------------------------------------------------------------------- * * MakeProcError -- * | | | 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 | } /* *---------------------------------------------------------------------- * * MakeProcError -- * * Function called by TclObjInterpProc to create the stack information * upon an error from a procedure. * * Results: * The interpreter's error info trace is set to a value that supplements * the error code. * * Side effects: |
| ︙ | ︙ | |||
2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 |
if (localPtr->defValuePtr != NULL) {
defPtr = localPtr->defValuePtr;
Tcl_DecrRefCount(defPtr);
}
Tcl_Free(localPtr);
localPtr = nextPtr;
}
Tcl_Free(procPtr);
/*
* TIP #280: Release the location data associated with this Proc
* structure, if any. The interpreter may not exist (For example for
* procbody structures created by tbcload.
*/
| > > > > > > > > > > | 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 |
if (localPtr->defValuePtr != NULL) {
defPtr = localPtr->defValuePtr;
Tcl_DecrRefCount(defPtr);
}
Tcl_Free(localPtr);
localPtr = nextPtr;
}
if ( procPtr->cmdPtr && (procPtr->flags & PROC_CMD_OWNED)
&& procPtr->cmdPtr->refCount-- <= 1
) {
/* cmdPtr owned by procPtr (lambda) */
if (procPtr->cmdPtr->nsPtr) {
TclNsDecrRefCount(procPtr->cmdPtr->nsPtr);
}
Tcl_Free(procPtr->cmdPtr);
}
Tcl_Free(procPtr);
/*
* TIP #280: Release the location data associated with this Proc
* structure, if any. The interpreter may not exist (For example for
* procbody structures created by tbcload.
*/
|
| ︙ | ︙ | |||
2273 2274 2275 2276 2277 2278 2279 |
}
return code;
}
/*
*----------------------------------------------------------------------
*
| | | | | | | > < < | | 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 |
}
return code;
}
/*
*----------------------------------------------------------------------
*
* TclGetObjInterpProc/TclGetObjInterpProc2 --
*
* Returns a pointer to the TclObjInterpProc/ObjInterpProc2 functions;
* this is different from the value obtained from the TclObjInterpProc
* reference on systems like Windows where import and export versions
* of a function exported by a DLL exist.
*
* Results:
* Returns the internal address of the TclObjInterpProc/ObjInterpProc2
* functions.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Tcl_ObjCmdProc *
TclGetObjInterpProc(void)
{
return TclObjInterpProc;
}
Tcl_ObjCmdProc2 *
TclGetObjInterpProc2(void)
{
return ObjInterpProc2;
}
/*
*----------------------------------------------------------------------
*
* TclNewProcBodyObj --
*
|
| ︙ | ︙ | |||
2456 2457 2458 2459 2460 2461 2462 |
SetLambdaFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
{
Interp *iPtr = (Interp *) interp;
const char *name;
Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv;
| | > > | 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 |
SetLambdaFromAny(
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
Tcl_Obj *objPtr) /* The object to convert. */
{
Interp *iPtr = (Interp *) interp;
const char *name;
Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv;
int isNew, result;
Tcl_Size objc;
CmdFrame *cfPtr = NULL;
Proc *procPtr;
Tcl_Namespace *nsPtr;
Command *cmdPtr;
if (interp == NULL) {
return TCL_ERROR;
}
/*
* Convert objPtr to list type first; if it cannot be converted, or if its
|
| ︙ | ︙ | |||
2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 |
if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't interpret \"%s\" as a lambda expression",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", (char *)NULL);
return TCL_ERROR;
}
argsPtr = objv[0];
bodyPtr = objv[1];
/*
| > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > | > | 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 |
if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"can't interpret \"%s\" as a lambda expression",
TclGetString(objPtr)));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", (char *)NULL);
return TCL_ERROR;
}
/*
* Set the namespace for this lambda: given by objv[2] understood as a
* global reference, or else global per default.
*/
if (objc == 2) {
TclNewLiteralStringObj(nsObjPtr, "::");
} else {
const char *nsName = TclGetString(objv[2]);
if ((*nsName != ':') || (*(nsName+1) != ':')) {
TclNewLiteralStringObj(nsObjPtr, "::");
Tcl_AppendObjToObj(nsObjPtr, objv[2]);
} else {
nsObjPtr = objv[2];
}
}
Tcl_IncrRefCount(nsObjPtr);
/* Find the namespace where this lambda should run. */
result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
if (result != TCL_OK) {
Tcl_DecrRefCount(nsObjPtr);
return TCL_ERROR;
}
argsPtr = objv[0];
bodyPtr = objv[1];
/*
* Create and initialize the Proc struct. The cmdPtr field is set to
* artificial command owned by the procPtr with few info, e. g. used
* in TclInfoFrame.
*/
name = TclGetString(objPtr);
if (TclCreateProc(interp, /*ignored nsPtr*/ NULL, name, argsPtr, bodyPtr,
&procPtr) != TCL_OK) {
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (parsing lambda expression \"%s\")", name));
Tcl_DecrRefCount(nsObjPtr);
return TCL_ERROR;
}
/*
* CAREFUL: TclCreateProc returns refCount==1! [Bug 1578454]
* procPtr->refCount = 1;
*/
cmdPtr = (Command *)Tcl_Alloc(sizeof(Command));
memset(cmdPtr, 0, sizeof(*cmdPtr));
cmdPtr->nsPtr = (Namespace *) nsPtr;
((Namespace *)nsPtr)->refCount++;
cmdPtr->objClientData = objPtr;
cmdPtr->refCount++;
procPtr->cmdPtr = cmdPtr;
procPtr->flags = PROC_CMD_OWNED;
/*
* TIP #280: Remember the line the apply body is starting on. In a Byte
* code context we ask the engine to provide us with the necessary
* information. This is for the initialization of the byte code compiler
* when the body is used for the first time.
*
|
| ︙ | ︙ | |||
2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 |
} else if (contextPtr->type == TCL_LOCATION_SOURCE) {
/*
* We created a new reference to the source file path name when we
* created 'context' above. Account for the reference.
*/
Tcl_IncrRefCount(contextPtr->data.eval.path);
}
if (contextPtr->type == TCL_LOCATION_SOURCE) {
/*
* We can record source location within a lambda only if the body
* was not created by substitution.
*/
if (contextPtr->line
&& (contextPtr->nline >= 2) && (contextPtr->line[1] >= 0)) {
| > | | | 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 |
} else if (contextPtr->type == TCL_LOCATION_SOURCE) {
/*
* We created a new reference to the source file path name when we
* created 'context' above. Account for the reference.
*/
Tcl_IncrRefCount(contextPtr->data.eval.path);
}
if (contextPtr->type == TCL_LOCATION_SOURCE) {
/*
* We can record source location within a lambda only if the body
* was not created by substitution.
*/
if (contextPtr->line
&& (contextPtr->nline >= 2) && (contextPtr->line[1] >= 0)) {
Tcl_Size buf[2];
/*
* Move from approximation (line of list cmd word) to actual
* location (line of 2nd list element).
*/
cfPtr = (CmdFrame *)Tcl_Alloc(sizeof(CmdFrame));
TclListLines(objPtr, contextPtr->line[1], 2, buf, NULL);
cfPtr->level = -1;
cfPtr->type = contextPtr->type;
cfPtr->line = (Tcl_Size *)Tcl_Alloc(sizeof(Tcl_Size));
cfPtr->line[0] = buf[1];
cfPtr->nline = 1;
cfPtr->framePtr = NULL;
cfPtr->nextPtr = NULL;
cfPtr->data.eval.path = contextPtr->data.eval.path;
Tcl_IncrRefCount(cfPtr->data.eval.path);
|
| ︙ | ︙ | |||
2595 2596 2597 2598 2599 2600 2601 |
*/
Tcl_DecrRefCount(contextPtr->data.eval.path);
}
TclStackFree(interp, contextPtr);
}
Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr, procPtr,
| | < < < < < < < < < < < < < < < < < < > | 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 |
*/
Tcl_DecrRefCount(contextPtr->data.eval.path);
}
TclStackFree(interp, contextPtr);
}
Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr, procPtr,
&isNew), cfPtr);
/*
* Free the list internalrep of objPtr - this will free argsPtr, but
* bodyPtr retains a reference from the Proc structure. Then finish the
* conversion to lambdaType.
*/
LambdaSetInternalRep(objPtr, procPtr, nsObjPtr);
Tcl_DecrRefCount(nsObjPtr);
return TCL_OK;
}
Proc *
TclGetLambdaFromObj(
Tcl_Interp *interp,
Tcl_Obj *objPtr,
|
| ︙ | ︙ | |||
2644 2645 2646 2647 2648 2649 2650 |
if (SetLambdaFromAny(interp, objPtr) != TCL_OK) {
return NULL;
}
LambdaGetInternalRep(objPtr, procPtr, nsObjPtr);
}
assert(procPtr != NULL);
| > | > > > > > > > > > | > > > | 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 |
if (SetLambdaFromAny(interp, objPtr) != TCL_OK) {
return NULL;
}
LambdaGetInternalRep(objPtr, procPtr, nsObjPtr);
}
assert(procPtr != NULL);
assert(procPtr->cmdPtr != NULL);
if (!procPtr->cmdPtr->nsPtr || procPtr->cmdPtr->nsPtr->flags & NS_DEAD) {
Command *cmdPtr = procPtr->cmdPtr;
Tcl_Namespace *nsPtr;
if (cmdPtr->nsPtr) {
TclNsDecrRefCount(cmdPtr->nsPtr);
cmdPtr->nsPtr = NULL;
}
/* Retry to obtain namespace again... */
if (TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr) != TCL_OK) {
return NULL;
}
cmdPtr->nsPtr = (Namespace *) nsPtr;
((Namespace *)nsPtr)->refCount++;
}
*nsObjPtrPtr = nsObjPtr;
return procPtr;
}
/*
|
| ︙ | ︙ | |||
2673 2674 2675 2676 2677 2678 2679 |
*----------------------------------------------------------------------
*/
int
Tcl_ApplyObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 |
*----------------------------------------------------------------------
*/
int
Tcl_ApplyObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, TclNRApplyObjCmd, clientData, objc, objv);
}
int
TclNRApplyObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Proc *procPtr = NULL;
Tcl_Obj *lambdaPtr, *nsObjPtr;
int result;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "lambdaExpr ?arg ...?");
return TCL_ERROR;
}
/*
* Set lambdaPtr, convert it to tclLambdaType in the current interp if
* necessary.
*/
lambdaPtr = objv[1];
procPtr = TclGetLambdaFromObj(interp, lambdaPtr, &nsObjPtr);
if (procPtr == NULL) {
return TCL_ERROR;
}
/*
* Push a call frame for that procPtr. Note that TclNRInterpProcCore()
* will pop it (NRE-based).
*/
result = TclPushProcCallFrame(procPtr, interp, objc, objv, 1);
if (result == TCL_OK) {
result = TclNRInterpProcCore(interp, objv[1], 2, &MakeLambdaError);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* MakeLambdaError --
*
* Function called by TclObjInterpProc to create the stack information
* upon an error from a lambda term.
*
* Results:
* The interpreter's error info trace is set to a value that supplements
* the error code.
*
* Side effects:
|
| ︙ | ︙ | |||
2847 2848 2849 2850 2851 2852 2853 | * * Side effects: * Modifies the target namespace's commands. * *---------------------------------------------------------------------- */ | | > > | | > | | 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 |
*
* Side effects:
* Modifies the target namespace's commands.
*
*----------------------------------------------------------------------
*/
/* Duplicate an argument to a procedure. */
static inline int
DuplicateArgument(
Proc *newProc,
const CompiledLocal *origLocal,
Tcl_Size i)
{
const char *argname = origLocal->name;
Tcl_Size nameLength = origLocal->nameLength;
CompiledLocal *localPtr;
/*
* Allocate an entry in the runtime procedure frame's list of local
* variables for the argument.
*/
localPtr = (CompiledLocal *)Tcl_AttemptAlloc(
offsetof(CompiledLocal, name) + 1U + nameLength);
if (!localPtr) {
return TCL_ERROR;
}
if (newProc->firstLocalPtr == NULL) {
newProc->firstLocalPtr = newProc->lastLocalPtr = localPtr;
} else {
|
| ︙ | ︙ | |||
2887 2888 2889 2890 2891 2892 2893 |
memcpy(localPtr->name, argname, nameLength + 1);
if (origLocal->flags & VAR_IS_ARGS) {
localPtr->flags |= VAR_IS_ARGS;
}
return TCL_OK;
}
| | > > > > > | < | | | | > | | | | | | | | > > | | | < | | | | | | | > | > | | | | | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 |
memcpy(localPtr->name, argname, nameLength + 1);
if (origLocal->flags & VAR_IS_ARGS) {
localPtr->flags |= VAR_IS_ARGS;
}
return TCL_OK;
}
/* Duplicate a procedure into a different namespace. */
static int
DuplicateProc(
Tcl_Interp *interp,
Namespace *nsPtr,
const char *cmdName,
const Proc *origProc,
const Command *origCmd)
{
Interp *iPtr = (Interp *) interp;
Tcl_Size length, i;
const char *bytes;
Tcl_Obj *bodyPtr;
Proc *newProc;
const CompiledLocal *origLocal;
Tcl_HashEntry *origHePtr;
/* Duplicate the string of body, not the bytecode. */
bytes = TclGetStringFromObj(origProc->bodyPtr, &length);
bodyPtr = Tcl_NewStringObj(bytes, length);
TclContinuationsCopy(bodyPtr, origProc->bodyPtr);
Tcl_IncrRefCount(bodyPtr);
/* The new procedure record. */
newProc = (Proc *) Tcl_Alloc(sizeof(Proc));
newProc->iPtr = iPtr;
newProc->refCount = 1;
newProc->bodyPtr = bodyPtr;
newProc->numArgs = origProc->numArgs;
newProc->numCompiledLocals = origProc->numArgs;
newProc->firstLocalPtr = NULL;
newProc->lastLocalPtr = NULL;
newProc->flags = 0;
/* Work through the original arguments, duplicating them. */
origLocal = origProc->firstLocalPtr;
for (i = 0; i < newProc->numArgs; i++) {
if (DuplicateArgument(newProc, origLocal, i) != TCL_OK) {
/* Don't set the interp result here. Since a malloc just failed,
* first clean up some memory before doing that. */
goto procError;
}
origLocal = origLocal->nextPtr;
}
/* Create the new command backed by the procedure. */
newProc->cmdPtr = (Command *) TclNRCreateCommandInNs(interp, cmdName,
(Tcl_Namespace *) nsPtr, TclObjInterpProc, NRInterpProc, newProc,
TclProcDeleteProc);
/* TIP #280: Duplicate the origin information (if we have it). */
origHePtr = Tcl_FindHashEntry(iPtr->linePBodyPtr, origProc);
if (origHePtr) {
CmdFrame *newCfPtr = (CmdFrame *) Tcl_Alloc(sizeof(CmdFrame));
const CmdFrame *origCfPtr = (CmdFrame *) Tcl_GetHashValue(origHePtr);
Tcl_HashEntry *hePtr;
int isNew;
/* Copy info, then fix up bits that need different treatment. */
memcpy(newCfPtr, origCfPtr, sizeof(CmdFrame));
newCfPtr->line = (Tcl_Size *)Tcl_Alloc(sizeof(Tcl_Size));
newCfPtr->line[0] = origCfPtr->line[0];
Tcl_IncrRefCount(newCfPtr->data.eval.path);
hePtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr, newProc, &isNew);
Tcl_SetHashValue(hePtr, newCfPtr);
}
/* Optimize for no-op procs. Note that this is simpler than in [proc]; we
* just see whether we've got the compiler in the old command! */
if (origCmd->compileProc == TclCompileNoOp) {
newProc->cmdPtr->compileProc = TclCompileNoOp;
}
return TCL_OK;
procError:
/* Delete the data allocated so far. */
Tcl_DecrRefCount(bodyPtr);
while (newProc->firstLocalPtr != NULL) {
CompiledLocal *localPtr = newProc->firstLocalPtr;
newProc->firstLocalPtr = localPtr->nextPtr;
if (localPtr->defValuePtr != NULL) {
Tcl_DecrRefCount(localPtr->defValuePtr);
}
Tcl_Free(localPtr);
}
Tcl_Free(newProc);
/* Complain about the failure to allocate. */
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"procedure \"%s\": arg list contains too many (%"
TCL_SIZE_MODIFIER "d) entries", cmdName, origProc->numArgs));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "PROC",
TOOMANYARGS, (char *)NULL);
return TCL_ERROR;
}
/* Duplicate all the procedures in a namespace into another (new) namespace. */
int
TclCopyNamespaceProcedures(
Tcl_Interp *interp,
Namespace *srcNsPtr, /* Where to copy from. */
Namespace *tgtNsPtr) /* Where to copy to. */
{
Tcl_HashEntry *entryPtr;
Tcl_HashSearch search;
if (srcNsPtr == tgtNsPtr) {
Tcl_Panic("cannot copy procedures from one namespace to itself");
}
for (entryPtr = Tcl_FirstHashEntry(&srcNsPtr->cmdTable, &search);
entryPtr; entryPtr = Tcl_NextHashEntry(&search)) {
const char *cmdName = (const char *)
Tcl_GetHashKey(&srcNsPtr->cmdTable, entryPtr);
Command *cmdPtr = (Command *) Tcl_GetHashValue(entryPtr);
Proc *procPtr;
/* For non-procedures, check if this is an import of a procedure; those
* also get copied. */
if (!TclIsProc(cmdPtr)) {
Command *realCmdPtr = (Command *)
TclGetOriginalCommand((Tcl_Command) cmdPtr);
if (!realCmdPtr || !TclIsProc(realCmdPtr)) {
continue;
}
cmdPtr = realCmdPtr;
}
/* Make the copy. */
procPtr = (Proc *) cmdPtr->objClientData;
if (DuplicateProc(interp, tgtNsPtr, cmdName, procPtr, cmdPtr) != TCL_OK) {
return TCL_ERROR;
}
}
return TCL_OK;
}
|
| ︙ | ︙ |
Changes to generic/tclProcess.c.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 |
/*
* Hash tables that keeps track of all child process statuses. Keys are the
* child process ids and resolved pids, values are (ProcessInfo *).
*/
typedef struct ProcessInfo {
Tcl_Pid pid; /* Process id. */
| | | | | | | < < < < < < < < | | | | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
/*
* Hash tables that keeps track of all child process statuses. Keys are the
* child process ids and resolved pids, values are (ProcessInfo *).
*/
typedef struct ProcessInfo {
Tcl_Pid pid; /* Process id. */
int resolvedPid; /* Resolved process id. */
int purge; /* Purge eventualy. */
TclProcessWaitStatus status;/* Process status. */
int code; /* Error code, exit status or signal
* number. */
Tcl_Obj *msg; /* Error message. */
Tcl_Obj *error; /* Error code. */
} ProcessInfo;
static Tcl_HashTable infoTablePerPid;
static Tcl_HashTable infoTablePerResolvedPid;
static int infoTablesInitialized = 0; /* 0 means not yet initialized. */
TCL_DECLARE_MUTEX(infoTablesMutex)
/*
* Prototypes for functions defined later in this file:
*/
static void InitProcessInfo(ProcessInfo *info, Tcl_Pid pid,
Tcl_Size resolvedPid);
static void FreeProcessInfo(ProcessInfo *info);
static int RefreshProcessInfo(ProcessInfo *info, int options);
static TclProcessWaitStatus WaitProcessStatus(Tcl_Pid pid, Tcl_Size resolvedPid,
int options, int *codePtr, Tcl_Obj **msgPtr,
Tcl_Obj **errorObjPtr);
static Tcl_Obj * BuildProcessStatusObj(ProcessInfo *info);
static Tcl_ObjCmdProc ProcessListObjCmd;
static Tcl_ObjCmdProc ProcessStatusObjCmd;
static Tcl_ObjCmdProc ProcessPurgeObjCmd;
static Tcl_ObjCmdProc ProcessAutopurgeObjCmd;
/*
*----------------------------------------------------------------------
*
* InitProcessInfo --
*
* Initializes the ProcessInfo structure.
*
* Results:
* None.
*
* Side effects:
* Memory written.
*
*----------------------------------------------------------------------
*/
void
InitProcessInfo(
ProcessInfo *info, /* Structure to initialize. */
Tcl_Pid pid, /* Process id. */
Tcl_Size resolvedPid) /* Resolved process id. */
{
info->pid = pid;
info->resolvedPid = resolvedPid;
info->purge = 0;
info->status = TCL_PROCESS_UNCHANGED;
info->code = 0;
info->msg = NULL;
info->error = NULL;
}
/*
*----------------------------------------------------------------------
*
* FreeProcessInfo --
*
* Free the ProcessInfo structure.
*
* Results:
* None.
*
* Side effects:
* Memory deallocated, Tcl_Obj refcount decreased.
*
*----------------------------------------------------------------------
*/
void
FreeProcessInfo(
ProcessInfo *info) /* Structure to free. */
{
/*
* Free stored Tcl_Objs.
*/
if (info->msg) {
Tcl_DecrRefCount(info->msg);
}
if (info->error) {
Tcl_DecrRefCount(info->error);
}
/*
* Free allocated structure.
*/
Tcl_Free(info);
}
/*
*----------------------------------------------------------------------
*
* RefreshProcessInfo --
*
* Refresh process info.
*
* Results:
* Nonzero if state changed, else zero.
*
* Side effects:
* May call WaitProcessStatus, which can block if WNOHANG option is set.
*
*----------------------------------------------------------------------
*/
int
RefreshProcessInfo(
ProcessInfo *info, /* Structure to refresh. */
int options) /* Options passed to WaitProcessStatus. */
{
if (info->status == TCL_PROCESS_UNCHANGED) {
/*
* Refresh & store status.
|
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
/*
* No change.
*/
return 0;
}
}
| | | | 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
/*
* No change.
*/
return 0;
}
}
/*
*----------------------------------------------------------------------
*
* WaitProcessStatus --
*
* Wait for process status to change.
*
* Results:
* TclProcessWaitStatus enum value.
*
* Side effects:
* May call WaitProcessStatus, which can block if WNOHANG option is set.
*
*----------------------------------------------------------------------
*/
TclProcessWaitStatus
WaitProcessStatus(
Tcl_Pid pid, /* Process id. */
Tcl_Size resolvedPid, /* Resolved process id. */
int options, /* Options passed to Tcl_WaitPid. */
int *codePtr, /* If non-NULL, will receive either:
* - 0 for normal exit.
* - errno in case of error.
|
| ︙ | ︙ | |||
353 354 355 356 357 358 359 |
errorStrings[3] = Tcl_NewStringObj("ODDWAITRESULT", -1);
TclNewIntObj(errorStrings[4], resolvedPid);
*errorObjPtr = Tcl_NewListObj(5, errorStrings);
}
return TCL_PROCESS_UNKNOWN_STATUS;
}
}
| | | | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
errorStrings[3] = Tcl_NewStringObj("ODDWAITRESULT", -1);
TclNewIntObj(errorStrings[4], resolvedPid);
*errorObjPtr = Tcl_NewListObj(5, errorStrings);
}
return TCL_PROCESS_UNKNOWN_STATUS;
}
}
/*
*----------------------------------------------------------------------
*
* BuildProcessStatusObj --
*
* Build a list object with process status. The first element is always
* a standard Tcl return value, which can be either TCL_OK or TCL_ERROR.
* In the latter case, the second element is the error message and the
* third element is a Tcl error code (see tclvars).
*
* Results:
* A list object.
*
* Side effects:
* Tcl_Objs are created.
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
BuildProcessStatusObj(
ProcessInfo *info)
{
Tcl_Obj *resultObjs[3];
if (info->status == TCL_PROCESS_UNCHANGED) {
/*
|
| ︙ | ︙ | |||
424 425 426 427 428 429 430 |
*----------------------------------------------------------------------
*/
static int
ProcessListObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
*----------------------------------------------------------------------
*/
static int
ProcessListObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *list;
Tcl_HashEntry *entry;
Tcl_HashSearch search;
ProcessInfo *info;
if (objc != 1) {
|
| ︙ | ︙ | |||
475 476 477 478 479 480 481 |
*----------------------------------------------------------------------
*/
static int
ProcessStatusObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
*----------------------------------------------------------------------
*/
static int
ProcessStatusObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *dict;
int options = WNOHANG;
Tcl_HashEntry *entry;
Tcl_HashSearch search;
ProcessInfo *info;
Tcl_Size i, numPids;
|
| ︙ | ︙ | |||
623 624 625 626 627 628 629 |
*----------------------------------------------------------------------
*/
static int
ProcessPurgeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
*----------------------------------------------------------------------
*/
static int
ProcessPurgeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_HashEntry *entry;
Tcl_HashSearch search;
ProcessInfo *info;
Tcl_Size i, numPids;
Tcl_Obj **pidObjs;
int result, pid;
|
| ︙ | ︙ | |||
721 722 723 724 725 726 727 |
*----------------------------------------------------------------------
*/
static int
ProcessAutopurgeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 |
*----------------------------------------------------------------------
*/
static int
ProcessAutopurgeObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 1 && objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?flag?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
751 752 753 754 755 756 757 |
/*
* Return current value.
*/
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(autopurge));
return TCL_OK;
}
| | | | | | | | > > > > > > > > | | > | > | | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 |
/*
* Return current value.
*/
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(autopurge));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclInitProcessCmd --
*
* This procedure creates the "tcl::process" Tcl command. See the user
* documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitProcessCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap processImplMap[] = {
{"list", ProcessListObjCmd, TclCompileBasic0ArgCmd, NULL, NULL, 1},
{"status", ProcessStatusObjCmd, TclCompileBasicMin0ArgCmd, NULL, NULL, 1},
{"purge", ProcessPurgeObjCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1},
{"autopurge", ProcessAutopurgeObjCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1},
{NULL, NULL, NULL, NULL, NULL, 0}
};
Tcl_Command processCmd;
if (infoTablesInitialized == 0) {
Tcl_MutexLock(&infoTablesMutex);
if (infoTablesInitialized == 0) {
Tcl_InitHashTable(&infoTablePerPid, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&infoTablePerResolvedPid, TCL_ONE_WORD_KEYS);
infoTablesInitialized = 1;
}
Tcl_MutexUnlock(&infoTablesMutex);
}
processCmd = TclMakeEnsemble(interp, "::tcl::process", processImplMap);
Tcl_Export(interp, Tcl_FindNamespace(interp, "::tcl", NULL, 0),
"process", 0);
return processCmd;
}
/*
*----------------------------------------------------------------------
*
* TclProcessCreated --
*
* Called when a child process has been created by Tcl.
*
|
| ︙ | ︙ | |||
853 854 855 856 857 858 859 |
/*
* Add entry to tables.
*/
Tcl_SetHashValue(entry, info);
entry = Tcl_CreateHashEntry(&infoTablePerResolvedPid, INT2PTR(resolvedPid),
| | | | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 |
/*
* Add entry to tables.
*/
Tcl_SetHashValue(entry, info);
entry = Tcl_CreateHashEntry(&infoTablePerResolvedPid, INT2PTR(resolvedPid),
&isNew);
Tcl_SetHashValue(entry, info);
Tcl_MutexUnlock(&infoTablesMutex);
}
/*
*----------------------------------------------------------------------
*
* TclProcessWait --
*
* Wait for process status to change.
*
|
| ︙ | ︙ |
Changes to generic/tclRegexp.c.
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
int initialized; /* Set to 1 when the module is initialized. */
char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled regular
* expression patterns. NULL means that this
* slot isn't used. Malloc-ed. */
size_t patLengths[NUM_REGEXPS];/* Number of non-null characters in
* corresponding entry in patterns. -1 means
* entry isn't used. */
| | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
int initialized; /* Set to 1 when the module is initialized. */
char *patterns[NUM_REGEXPS];/* Strings corresponding to compiled regular
* expression patterns. NULL means that this
* slot isn't used. Malloc-ed. */
size_t patLengths[NUM_REGEXPS];/* Number of non-null characters in
* corresponding entry in patterns. -1 means
* entry isn't used. */
struct TclRegexp *regexps[NUM_REGEXPS];
/* Compiled forms of above strings. Also
* malloc-ed, or NULL if not in use yet. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
|
| ︙ | ︙ | |||
98 99 100 101 102 103 104 |
/*
* The regular expression Tcl object type. This serves as a cache of the
* compiled form of the regular expression.
*/
const Tcl_ObjType tclRegexpType = {
| | | | | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
/*
* The regular expression Tcl object type. This serves as a cache of the
* compiled form of the regular expression.
*/
const Tcl_ObjType tclRegexpType = {
"regexp", /* name */
FreeRegexpInternalRep, /* freeIntRepProc */
DupRegexpInternalRep, /* dupIntRepProc */
NULL, /* updateStringProc */
SetRegexpFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
#define RegexpSetInternalRep(objPtr, rePtr) \
do { \
Tcl_ObjInternalRep ir; \
(rePtr)->refCount++; \
|
| ︙ | ︙ | |||
858 859 860 861 862 863 864 |
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
const char *string, /* The regexp to compile (UTF-8). */
size_t length, /* The length of the string in bytes. */
int flags) /* Compilation flags. */
{
TclRegexp *regexpPtr;
const Tcl_UniChar *uniString;
| < | | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 |
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
const char *string, /* The regexp to compile (UTF-8). */
size_t length, /* The length of the string in bytes. */
int flags) /* Compilation flags. */
{
TclRegexp *regexpPtr;
const Tcl_UniChar *uniString;
int numChars, status, i, exact;
Tcl_DString stringBuf;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->initialized) {
tsdPtr->initialized = 1;
Tcl_CreateThreadExitHandler(FinalizeRegexp, NULL);
}
|
| ︙ | ︙ | |||
931 932 933 934 935 936 937 |
numChars = Tcl_DStringLength(&stringBuf) / sizeof(Tcl_UniChar);
/*
* Compile the string and check for errors.
*/
regexpPtr->flags = flags;
| | | 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 |
numChars = Tcl_DStringLength(&stringBuf) / sizeof(Tcl_UniChar);
/*
* Compile the string and check for errors.
*/
regexpPtr->flags = flags;
status = TclReComp(®expPtr->re, uniString, (size_t) numChars, flags);
Tcl_DStringFree(&stringBuf);
if (status != REG_OKAY) {
/*
* Clean up and report errors in the interpreter, if possible.
*/
|
| ︙ | ︙ |
Changes to generic/tclRegexp.h.
1 2 3 4 5 6 | /* * tclRegexp.h -- * * This file contains definitions used internally by Henry Spencer's * regular expression code. * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * tclRegexp.h -- * * This file contains definitions used internally by Henry Spencer's * regular expression code. * * Copyright (c) 1998 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLREGEXP #define _TCLREGEXP |
| ︙ | ︙ |
Changes to generic/tclResolve.c.
| ︙ | ︙ | |||
61 62 63 64 65 66 67 |
* runtime. */
Tcl_ResolveCompiledVarProc *compiledVarProc)
/* Function for variable resolution at compile
* time. */
{
Interp *iPtr = (Interp *) interp;
ResolverScheme *resPtr;
| | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
* runtime. */
Tcl_ResolveCompiledVarProc *compiledVarProc)
/* Function for variable resolution at compile
* time. */
{
Interp *iPtr = (Interp *) interp;
ResolverScheme *resPtr;
unsigned len;
/*
* Since we're adding a new name resolution scheme, we must force all code
* to be recompiled to use the new scheme. If there are new compiled
* variable resolution rules, bump the compiler epoch to invalidate
* compiled code. If there are new command resolution rules, bump the
* cmdRefEpoch in all namespaces.
|
| ︙ | ︙ |
Changes to generic/tclResult.c.
| ︙ | ︙ | |||
207 208 209 210 211 212 213 |
Tcl_Free(statePtr);
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetObjResult --
| < | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 |
Tcl_Free(statePtr);
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetObjResult --
* Makes objPtr the interpreter's result value.
*
* Results:
* None.
*
* Side effects:
* Stores objPtr interp->objResultPtr, increments its reference count, and
|
| ︙ | ︙ | |||
547 548 549 550 551 552 553 | } /* *---------------------------------------------------------------------- * * Tcl_GetErrorLine -- * | | | | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 |
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetErrorLine --
*
* Returns the line number associated with the current error.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetErrorLine(
Tcl_Interp *interp)
{
return ((Interp *) interp)->errorLine;
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetErrorLine --
*
* Sets the line number associated with the current error.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetErrorLine(
Tcl_Interp *interp,
|
| ︙ | ︙ | |||
808 809 810 811 812 813 814 |
*/
static int
ExpandedOptions(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Obj **keys, /* Built-in keys (per thread) */
Tcl_Obj *returnOpts, /* Options dict we are building */
| | | | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 |
*/
static int
ExpandedOptions(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Obj **keys, /* Built-in keys (per thread) */
Tcl_Obj *returnOpts, /* Options dict we are building */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
for (; objc > 1; objv += 2, objc -= 2) {
const char *opt = TclGetString(objv[0]);
const char *compare = TclGetString(keys[KEY_OPTIONS]);
if ((objv[0]->length == keys[KEY_OPTIONS]->length)
&& (memcmp(opt, compare, objv[0]->length) == 0)) {
|
| ︙ | ︙ | |||
849 850 851 852 853 854 855 |
}
return TCL_OK;
}
int
TclMergeReturnOptions(
Tcl_Interp *interp, /* Current interpreter. */
| | | | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 |
}
return TCL_OK;
}
int
TclMergeReturnOptions(
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[], /* Argument objects. */
Tcl_Obj **optionsPtrPtr, /* If not NULL, points to space for a (Tcl_Obj
* *) where the pointer to the merged return
* options dictionary should be written. */
int *codePtr, /* If not NULL, points to space where the
* -code value should be written. */
int *levelPtr) /* If not NULL, points to space where the
* -level value should be written. */
|
| ︙ | ︙ | |||
914 915 916 917 918 919 920 |
* Check for bogus -errorcode value.
*/
Tcl_DictObjGet(NULL, returnOpts, keys[KEY_ERRORCODE], &valuePtr);
if (valuePtr != NULL) {
Tcl_Size length;
| | | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
* Check for bogus -errorcode value.
*/
Tcl_DictObjGet(NULL, returnOpts, keys[KEY_ERRORCODE], &valuePtr);
if (valuePtr != NULL) {
Tcl_Size length;
if (TCL_ERROR == TclListObjLength(NULL, valuePtr, &length )) {
/*
* Value is not a list, which is illegal for -errorcode.
*/
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad -errorcode value: expected a list but got \"%s\"",
TclGetString(valuePtr)));
|
| ︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | Tcl_SetReturnOptions(targetInterp, Tcl_GetReturnOptions(sourceInterp, code)); /* * Add line number if needed: not in line 1 and info contains no number * yet at end of the stack (e. g. proc etc), to avoid double reporting */ if (tiPtr->errorLine > 1 && tiPtr->errorInfo && | | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 |
Tcl_SetReturnOptions(targetInterp,
Tcl_GetReturnOptions(sourceInterp, code));
/*
* Add line number if needed: not in line 1 and info contains no number
* yet at end of the stack (e. g. proc etc), to avoid double reporting
*/
if (tiPtr->errorLine > 1 && tiPtr->errorInfo &&
tiPtr->errorInfo->length &&
tiPtr->errorInfo->bytes[tiPtr->errorInfo->length-1] != ')'
) {
Tcl_AppendObjToErrorInfo(targetInterp, Tcl_ObjPrintf(
"\n (\"interp eval\" body line %d)", tiPtr->errorLine));
}
tiPtr->flags &= ~(ERR_ALREADY_LOGGED);
}
Tcl_SetObjResult(targetInterp, Tcl_GetObjResult(sourceInterp));
Tcl_ResetResult(sourceInterp);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/
|
Changes to generic/tclScan.c.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 |
*/
static const char *
BuildCharSet(
CharSet *cset,
const char *format) /* Points to first char of set. */
{
| < < < > > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
*/
static const char *
BuildCharSet(
CharSet *cset,
const char *format) /* Points to first char of set. */
{
Tcl_UniChar ch = 0, start;
int offset, nranges;
const char *end;
memset(cset, 0, sizeof(CharSet));
offset = TclUtfToUniChar(format, &ch);
if (ch == '^') {
cset->exclude = 1;
format += offset;
|
| ︙ | ︙ | |||
592 593 594 595 596 597 598 |
*----------------------------------------------------------------------
*/
int
Tcl_ScanObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 |
*----------------------------------------------------------------------
*/
int
Tcl_ScanObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *format;
int numVars, nconversions, totalVars = -1;
int objIndex, offset, i, result, code;
int value;
const char *string, *end, *baseString;
char op = 0;
int underflow = 0;
Tcl_Size width;
Tcl_WideInt wideValue;
Tcl_UniChar ch = 0, sch = 0;
Tcl_Obj **objs = NULL, *objPtr = NULL;
int flags;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv,
"string format ?varName ...?");
return TCL_ERROR;
}
format = TclGetString(objv[2]);
numVars = objc-3;
/*
* Check for errors in the format string.
*/
if (ValidateFormat(interp, format, numVars, &totalVars) == TCL_ERROR) {
return TCL_ERROR;
|
| ︙ | ︙ |
Changes to generic/tclStrIdxTree.c.
1 2 3 4 5 6 7 | /* * tclStrIdxTree.c -- * * Contains the routines for managing string index tries in Tcl. * * This code is back-ported from the tclSE engine, by Serg G. Brester. * | | | | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/*
* tclStrIdxTree.c --
*
* Contains the routines for managing string index tries in Tcl.
*
* This code is back-ported from the tclSE engine, by Serg G. Brester.
*
* Copyright (c) 2016 by Sergey G. Brester aka sebres. All rights reserved.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* -----------------------------------------------------------------------
*
* String index tries are prepaired structures used for fast greedy search of the string
* (index) by unique string prefix as key.
*
* Index tree build for two lists together can be explained in the following datagram
*
* Lists:
*
* {Januar Februar Maerz April Mai Juni Juli August September Oktober November Dezember}
* {Jnr Fbr Mrz Apr Mai Jni Jli Agt Spt Okt Nvb Dzb}
*
* Index-Tree:
|
| ︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | * Thereby value 0 shows pure group items (corresponding ambigous matches). * But the group may have a value if it contains only same values * (see for example group "f" above). * * StrIdxTree's are very fast, so: * build of above-mentioned tree takes about 10 microseconds. * search of string index in this tree takes fewer as 0.1 microseconds. */ #include "tclInt.h" #include "tclStrIdxTree.h" static void StrIdxTreeObj_DupIntRepProc(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); static void StrIdxTreeObj_FreeIntRepProc(Tcl_Obj *objPtr); static void StrIdxTreeObj_UpdateStringProc(Tcl_Obj *objPtr); | > | | | | | | | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
* Thereby value 0 shows pure group items (corresponding ambigous matches).
* But the group may have a value if it contains only same values
* (see for example group "f" above).
*
* StrIdxTree's are very fast, so:
* build of above-mentioned tree takes about 10 microseconds.
* search of string index in this tree takes fewer as 0.1 microseconds.
*
*/
#include "tclInt.h"
#include "tclStrIdxTree.h"
static void StrIdxTreeObj_DupIntRepProc(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static void StrIdxTreeObj_FreeIntRepProc(Tcl_Obj *objPtr);
static void StrIdxTreeObj_UpdateStringProc(Tcl_Obj *objPtr);
static const Tcl_ObjType StrIdxTreeObjType = {
"str-idx-tree", /* name */
StrIdxTreeObj_FreeIntRepProc, /* freeIntRepProc */
StrIdxTreeObj_DupIntRepProc, /* dupIntRepProc */
StrIdxTreeObj_UpdateStringProc, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
/*
*----------------------------------------------------------------------
*
* TclStrIdxTreeSearch --
|
| ︙ | ︙ | |||
249 250 251 252 253 254 255 |
int ret = TCL_ERROR;
void *val;
const char *s, *e, *f;
TclStrIdx *item;
/* create lowercase reflection of the list keys */
| | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
int ret = TCL_ERROR;
void *val;
const char *s, *e, *f;
TclStrIdx *item;
/* create lowercase reflection of the list keys */
lwrv = (Tcl_Obj **) Tcl_AttemptAlloc(sizeof(Tcl_Obj*) * lstc);
if (lwrv == NULL) {
return TCL_ERROR;
}
for (i = 0; i < lstc; i++) {
lwrv[i] = Tcl_DuplicateObj(lstv[i]);
Tcl_IncrRefCount(lwrv[i]);
lwrv[i]->length = Tcl_UtfToLower(TclGetString(lwrv[i]));
|
| ︙ | ︙ | |||
383 384 385 386 387 388 389 |
* internal representation of a Tcl_Obj instead of needing to hang it
* off the back with an extra alloc.
*/
TCL_CT_ASSERT(sizeof(TclStrIdxTree) <= sizeof(Tcl_ObjInternalRep));
tree->firstPtr = NULL;
tree->lastPtr = NULL;
| | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
* internal representation of a Tcl_Obj instead of needing to hang it
* off the back with an extra alloc.
*/
TCL_CT_ASSERT(sizeof(TclStrIdxTree) <= sizeof(Tcl_ObjInternalRep));
tree->firstPtr = NULL;
tree->lastPtr = NULL;
objPtr->typePtr = &StrIdxTreeObjType;
/* return tree root in internal representation */
return objPtr;
}
static void
StrIdxTreeObj_DupIntRepProc(
Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr)
{
/* follow links (smart pointers) */
srcPtr = FollowPossibleLink(srcPtr);
/* create smart pointer to it (ptr1 != NULL, ptr2 = NULL) */
TclInitObjRef(*((Tcl_Obj **) ©Ptr->internalRep.twoPtrValue.ptr1),
srcPtr);
copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
copyPtr->typePtr = &StrIdxTreeObjType;
}
static void
StrIdxTreeObj_FreeIntRepProc(
Tcl_Obj *objPtr)
{
/* follow links (smart pointers) */
|
| ︙ | ︙ | |||
437 438 439 440 441 442 443 |
objPtr->bytes = &tclEmptyString;
}
TclStrIdxTree *
TclStrIdxTreeGetFromObj(
Tcl_Obj *objPtr)
{
| | | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
objPtr->bytes = &tclEmptyString;
}
TclStrIdxTree *
TclStrIdxTreeGetFromObj(
Tcl_Obj *objPtr)
{
if (objPtr->typePtr != &StrIdxTreeObjType) {
return NULL;
}
/* follow links (smart pointers) */
objPtr = FollowPossibleLink(objPtr);
/* return tree root in internal representation */
|
| ︙ | ︙ | |||
481 482 483 484 485 486 487 |
}
TclUnsetObjRef(obj[0]);
}
int
TclStrIdxTreeTestObjCmd(
void *clientData, Tcl_Interp *interp,
| | | 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
}
TclUnsetObjRef(obj[0]);
}
int
TclStrIdxTreeTestObjCmd(
void *clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *const objv[])
{
const char *cs, *cin, *ret;
static const char *const options[] = {
"findequal", "index", "puts-index", NULL
};
enum optionInd {
O_FINDEQUAL, O_INDEX, O_PUTS_INDEX
|
| ︙ | ︙ |
Changes to generic/tclStrIdxTree.h.
1 2 3 4 | /* * tclStrIdxTree.h -- * * Declarations of string index tries and other primitives currently | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * tclStrIdxTree.h -- * * Declarations of string index tries and other primitives currently * back-ported from tclSE. * * Copyright (c) 2016 Serg G. Brester (aka sebres) * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLSTRIDXTREE_H #define _TCLSTRIDXTREE_H |
| ︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
break;
}
}
*cinfnd = cin;
} while ((ret = cs) < cse && cin < cine);
return ret;
}
/*
* Prototypes of module functions.
*/
MODULE_SCOPE const char*TclStrIdxTreeSearch(TclStrIdxTree **foundParent,
TclStrIdx **foundItem, TclStrIdxTree *tree,
const char *start, const char *end);
MODULE_SCOPE int TclStrIdxTreeBuildFromList(TclStrIdxTree *idxTree,
Tcl_Size lstc, Tcl_Obj **lstv, void **values);
MODULE_SCOPE Tcl_Obj * TclStrIdxTreeNewObj(void);
MODULE_SCOPE TclStrIdxTree*TclStrIdxTreeGetFromObj(Tcl_Obj *objPtr);
#ifdef TEST_STR_IDX_TREE
/* currently unused, debug resp. test purposes only */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
break;
}
}
*cinfnd = cin;
} while ((ret = cs) < cse && cin < cine);
return ret;
}
/*
* Primitives to safe set, reset and free references.
*/
#define TclUnsetObjRef(obj) \
do { \
if (obj != NULL) { \
Tcl_DecrRefCount(obj); \
obj = NULL; \
} \
} while (0)
#define TclInitObjRef(obj, val) \
do { \
obj = (val); \
if (obj) { \
Tcl_IncrRefCount(obj); \
} \
} while (0)
#define TclSetObjRef(obj, val) \
do { \
Tcl_Obj *nval = (val); \
if (obj != nval) { \
Tcl_Obj *prev = obj; \
TclInitObjRef(obj, nval); \
if (prev != NULL) { \
Tcl_DecrRefCount(prev); \
} \
} \
} while (0)
/*
* Prototypes of module functions.
*/
MODULE_SCOPE const char*TclStrIdxTreeSearch(TclStrIdxTree **foundParent,
TclStrIdx **foundItem, TclStrIdxTree *tree,
const char *start, const char *end);
MODULE_SCOPE int TclStrIdxTreeBuildFromList(TclStrIdxTree *idxTree,
Tcl_Size lstc, Tcl_Obj **lstv, void **values);
MODULE_SCOPE Tcl_Obj * TclStrIdxTreeNewObj(void);
MODULE_SCOPE TclStrIdxTree*TclStrIdxTreeGetFromObj(Tcl_Obj *objPtr);
#ifdef TEST_STR_IDX_TREE
/* currently unused, debug resp. test purposes only */
MODULE_SCOPE Tcl_ObjCmdProc TclStrIdxTreeTestObjCmd;
#endif
#endif /* _TCLSTRIDXTREE_H */
|
Changes to generic/tclStrToD.c.
| ︙ | ︙ | |||
201 202 203 204 205 206 207 |
1.0e+16,
1.0e+32,
1.0e+64,
1.0e+128,
1.0e+256
};
| | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
1.0e+16,
1.0e+32,
1.0e+64,
1.0e+128,
1.0e+256
};
static int n770_fp; /* Flag is 1 on Nokia N770 floating point.
* Nokia's floating point has the words
* reversed: if big-endian is 7654 3210,
* and little-endian is 0123 4567,
* then Nokia's FP is 4567 0123;
* little-endian within the 32-bit words but
* big-endian between them. */
|
| ︙ | ︙ | |||
232 233 234 235 236 237 238 |
* 5**104, 5**208 */
static const double tens[] = {
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22
};
| | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
* 5**104, 5**208 */
static const double tens[] = {
1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22
};
static const int itens [] = {
1,
10,
100,
1000,
10000,
100000,
1000000,
|
| ︙ | ︙ | |||
584 585 586 587 588 589 590 | } /* * span multiple numeric whitespace * V * example: 5___6 */ for (before = (p - 1); | | | | | | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
}
/*
* span multiple numeric whitespace
* V
* example: 5___6
*/
for (before = (p - 1);
(before && *before == '_');
before = (before > p ? (before - 1) : NULL));
for (after = (p + 1);
(after && *after && *after == '_');
after = (*after && *after == '_') ? (after + 1) : NULL);
switch (state) {
case ZERO_B:
case BINARY:
if ((before && (*before != '0' && *before != '1')) ||
(after && (*after != '0' && *after != '1'))) {
/* Not a valid digit */
|
| ︙ | ︙ | |||
869 870 871 872 873 874 875 |
* for too large shifts first.
*/
if (significandWide != 0 &&
((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) ||
significandWide > (UWIDE_MAX >> shift))) {
significandOverflow = 1;
| | > | 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 |
* for too large shifts first.
*/
if (significandWide != 0 &&
((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) ||
significandWide > (UWIDE_MAX >> shift))) {
significandOverflow = 1;
err = mp_init_u64(&significandBig,
significandWide);
}
}
if (!significandOverflow) {
/*
* When the significand is 0, it is possible for the
* amount to be shifted to equal or exceed the width
* of the significand. Do not shift when the
|
| ︙ | ︙ | |||
925 926 927 928 929 930 931 |
* for too large shifts first.
*/
if (significandWide != 0 &&
((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) ||
significandWide > (UWIDE_MAX >> shift))) {
significandOverflow = 1;
| | > | 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 |
* for too large shifts first.
*/
if (significandWide != 0 &&
((size_t)shift >= CHAR_BIT*sizeof(Tcl_WideUInt) ||
significandWide > (UWIDE_MAX >> shift))) {
significandOverflow = 1;
err = mp_init_u64(&significandBig,
significandWide);
}
}
if (!significandOverflow) {
/*
* When the significand is 0, it is possible for the
* amount to be shifted to equal or exceed the width
* of the significand. Do not shift when the
|
| ︙ | ︙ | |||
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 |
*/
/*
* TCL bug ca62367d61: the following two if-conditions handle the case,
* if the mantissa is to long to be represented.
* Very high numbers are returned, if this is not handled
*/
if (exponent < -511) {
if (mp_init_copy(&bntmp, significand) != MP_OKAY) {
Tcl_Panic("initialization failure in MakeHighPrecisionDouble");
}
shift = -exponent - 511;
exponent += shift;
| > | 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 |
*/
/*
* TCL bug ca62367d61: the following two if-conditions handle the case,
* if the mantissa is to long to be represented.
* Very high numbers are returned, if this is not handled
*/
if (exponent < -511) {
if (mp_init_copy(&bntmp, significand) != MP_OKAY) {
Tcl_Panic("initialization failure in MakeHighPrecisionDouble");
}
shift = -exponent - 511;
exponent += shift;
|
| ︙ | ︙ | |||
2050 2051 2052 2053 2054 2055 2056 |
/*
* We are trying to compute a corrector term that, when added to the
* approximate result, will yield close to the exact result.
* The exact result is exactSignificand * 10**exponent.
* The approximate result is significand * 2**binExponent
* If exponent<0, we need to multiply the exact value by 10**-exponent
* to make it an integer, plus another factor of 2 to decide on rounding.
| | | 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 |
/*
* We are trying to compute a corrector term that, when added to the
* approximate result, will yield close to the exact result.
* The exact result is exactSignificand * 10**exponent.
* The approximate result is significand * 2**binExponent
* If exponent<0, we need to multiply the exact value by 10**-exponent
* to make it an integer, plus another factor of 2 to decide on rounding.
* Similarly if binExponent<FP_PRECISION, we need
* to multiply by 2**FP_PRECISION to make the approximate value an integer.
*
* Let M = 2**M2 * 5**M5 be the least common multiple of these two
* multipliers.
*/
i = mantBits - binExponent;
|
| ︙ | ︙ | |||
4749 4750 4751 4752 4753 4754 4755 |
* significant word first.
*/
#ifdef IEEE_FLOATING_POINT
bitwhack.dv = 1.000000238418579;
/* 3ff0 0000 4000 0000 */
if ((bitwhack.iv >> 32) == 0x3FF00000) {
| | | | 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 |
* significant word first.
*/
#ifdef IEEE_FLOATING_POINT
bitwhack.dv = 1.000000238418579;
/* 3ff0 0000 4000 0000 */
if ((bitwhack.iv >> 32) == 0x3FF00000) {
n770_fp = 0;
} else if ((bitwhack.iv & 0xFFFFFFFF) == 0x3FF00000) {
n770_fp = 1;
} else {
Tcl_Panic("unknown floating point word order on this machine");
}
#endif
}
/*
|
| ︙ | ︙ | |||
4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 |
} else if (shift == 0) {
err = mp_copy(a, &b);
} else if (shift > 0) {
err = mp_mul_2d(a, shift, &b);
} else if (shift < 0) {
lsb = mp_cnt_lsb(a);
if (lsb == -1-shift) {
/*
* Round to even
*/
err = mp_div_2d(a, -shift, &b, NULL);
if ((err == MP_OKAY) && mp_isodd(&b)) {
if (mp_isneg(&b)) {
err = mp_sub_d(&b, 1, &b);
} else {
err = mp_add_d(&b, 1, &b);
}
}
} else {
/*
* Ordinary rounding
*/
err = mp_div_2d(a, -1-shift, &b, NULL);
if (err != MP_OKAY) {
/* just skip */
| > > | 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 |
} else if (shift == 0) {
err = mp_copy(a, &b);
} else if (shift > 0) {
err = mp_mul_2d(a, shift, &b);
} else if (shift < 0) {
lsb = mp_cnt_lsb(a);
if (lsb == -1-shift) {
/*
* Round to even
*/
err = mp_div_2d(a, -shift, &b, NULL);
if ((err == MP_OKAY) && mp_isodd(&b)) {
if (mp_isneg(&b)) {
err = mp_sub_d(&b, 1, &b);
} else {
err = mp_add_d(&b, 1, &b);
}
}
} else {
/*
* Ordinary rounding
*/
err = mp_div_2d(a, -1-shift, &b, NULL);
if (err != MP_OKAY) {
/* just skip */
|
| ︙ | ︙ | |||
5345 5346 5347 5348 5349 5350 5351 | * * Transpose the two words of a number for Nokia 770 floating point * handling. * *---------------------------------------------------------------------- */ | < > | 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 |
*
* Transpose the two words of a number for Nokia 770 floating point
* handling.
*
*----------------------------------------------------------------------
*/
int
TclNokia770Doubles(void)
{
return n770_fp;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclStringObj.c.
| ︙ | ︙ | |||
72 73 74 75 76 77 78 |
/*
* The structure below defines the string Tcl object type by means of
* functions that can be invoked by generic object code.
*/
const Tcl_ObjType tclStringType = {
| | | | | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
/*
* The structure below defines the string Tcl object type by means of
* functions that can be invoked by generic object code.
*/
const Tcl_ObjType tclStringType = {
"string", /* name */
FreeStringInternalRep, /* freeIntRepPro */
DupStringInternalRep, /* dupIntRepProc */
UpdateStringOfString, /* updateStringProc */
SetStringFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
/*
* TCL STRING GROWTH ALGORITHM
*
* When growing strings (during an append, for example), the following growth
|
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
String *stringPtr = GET_STRING(objPtr);
Tcl_Size maxChars;
/* Note STRING_MAXCHARS already takes into account space for nul */
if (needed > STRING_MAXCHARS) {
Tcl_Panic("max size for a Tcl unicode rep (%" TCL_Z_MODIFIER "d bytes) exceeded",
| | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
String *stringPtr = GET_STRING(objPtr);
Tcl_Size maxChars;
/* Note STRING_MAXCHARS already takes into account space for nul */
if (needed > STRING_MAXCHARS) {
Tcl_Panic("max size for a Tcl unicode rep (%" TCL_Z_MODIFIER "d bytes) exceeded",
STRING_MAXCHARS);
}
if (stringPtr->maxChars > 0) {
/* Expansion - try allocating extra space */
stringPtr = (String *) TclReallocElemsEx(stringPtr,
needed + 1, /* +1 for nul */
sizeof(Tcl_UniChar), offsetof(String, unicode), &maxChars);
maxChars -= 1; /* End nul not included */
|
| ︙ | ︙ | |||
234 235 236 237 238 239 240 |
* byte. */
{
return Tcl_DbNewStringObj(bytes, length, "unknown", 0);
}
// Redefine the macro
#define Tcl_NewStringObj(bytes, len) \
| | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
* byte. */
{
return Tcl_DbNewStringObj(bytes, length, "unknown", 0);
}
// Redefine the macro
#define Tcl_NewStringObj(bytes, len) \
Tcl_DbNewStringObj(bytes, len, __FILE__, __LINE__)
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_NewStringObj(
const char *bytes, /* Points to the first of the length bytes
* used to initialize the new object. */
Tcl_Size length) /* The number of bytes to copy from "bytes"
* when initializing the new object. If -1,
|
| ︙ | ︙ | |||
302 303 304 305 306 307 308 |
{
Tcl_Obj *objPtr;
if (length < 0) {
length = (bytes? strlen(bytes) : 0);
}
TclDbNewObj(objPtr, file, line);
| | < < < | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
{
Tcl_Obj *objPtr;
if (length < 0) {
length = (bytes? strlen(bytes) : 0);
}
TclDbNewObj(objPtr, file, line);
TclInitStringRep(objPtr, bytes, length);
return objPtr;
}
#else /* if not TCL_MEM_DEBUG */
Tcl_Obj *
Tcl_DbNewStringObj(
const char *bytes, /* Points to the first of the length bytes
* used to initialize the new object. */
|
| ︙ | ︙ | |||
461 462 463 464 465 466 467 |
} else {
TclGetString(objPtr);
numChars = TclNumUtfChars(objPtr->bytes, objPtr->length);
}
return numChars;
}
| | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
} else {
TclGetString(objPtr);
numChars = TclNumUtfChars(objPtr->bytes, objPtr->length);
}
return numChars;
}
/*
*----------------------------------------------------------------------
*
* TclCheckEmptyString --
*
* Determine whether the string value of an object is or would be the
* empty string, without generating a string representation.
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 |
* we don't need to convert to a string to perform the indexing operation.
*/
if (TclIsPureByteArray(objPtr)) {
Tcl_Size length = 0;
unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &length);
if (index >= length) {
| | | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 |
* we don't need to convert to a string to perform the indexing operation.
*/
if (TclIsPureByteArray(objPtr)) {
Tcl_Size length = 0;
unsigned char *bytes = Tcl_GetBytesFromObj(NULL, objPtr, &length);
if (index >= length) {
return -1;
}
return bytes[index];
}
/*
* OK, need to work with the object as a string.
|
| ︙ | ︙ | |||
644 645 646 647 648 649 650 | * Side effects: * Converts the object to have the String internal rep. * *---------------------------------------------------------------------- */ #undef Tcl_GetUnicodeFromObj | | | 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 |
* Side effects:
* Converts the object to have the String internal rep.
*
*----------------------------------------------------------------------
*/
#undef Tcl_GetUnicodeFromObj
#if !defined(TCL_NO_DEPRECATED)
Tcl_UniChar *
TclGetUnicodeFromObj(
Tcl_Obj *objPtr, /* The object to find the Unicode string
* for. */
void *lengthPtr) /* If non-NULL, the location where the string
* rep's Tcl_UniChar length should be stored. If
* NULL, no length is stored. */
|
| ︙ | ︙ | |||
672 673 674 675 676 677 678 |
Tcl_Panic("Tcl_GetUnicodeFromObj with 'int' lengthPtr"
" cannot handle such long strings. Please use 'Tcl_Size'");
}
*(int *)lengthPtr = (int)stringPtr->numChars;
}
return stringPtr->unicode;
}
| | | 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
Tcl_Panic("Tcl_GetUnicodeFromObj with 'int' lengthPtr"
" cannot handle such long strings. Please use 'Tcl_Size'");
}
*(int *)lengthPtr = (int)stringPtr->numChars;
}
return stringPtr->unicode;
}
#endif /* !defined(TCL_NO_DEPRECATED) */
Tcl_UniChar *
Tcl_GetUnicodeFromObj(
Tcl_Obj *objPtr, /* The object to find the unicode string
* for. */
Tcl_Size *lengthPtr) /* If non-NULL, the location where the string
* rep's unichar length should be stored. If
|
| ︙ | ︙ | |||
1853 1854 1855 1856 1857 1858 1859 |
int
Tcl_AppendFormatToObj(
Tcl_Interp *interp,
Tcl_Obj *appendObj,
const char *format,
Tcl_Size objc,
| | | 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 |
int
Tcl_AppendFormatToObj(
Tcl_Interp *interp,
Tcl_Obj *appendObj,
const char *format,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
const char *span = format, *msg, *errCode;
int gotXpg = 0, gotSequential = 0;
Tcl_Size objIndex = 0, originalLength, limit, numBytes = 0;
Tcl_UniChar ch = 0;
static const char *mixedXPG =
"cannot mix \"%\" and \"%n$\" conversion specifiers";
|
| ︙ | ︙ | |||
1886 1887 1888 1889 1890 1891 1892 | int gotMinus = 0, gotHash = 0, gotZero = 0, gotSpace = 0, gotPlus = 0; int gotPrecision, sawFlag, useShort = 0, useBig = 0; Tcl_WideInt width, precision; int useWide = 0; int newXpg, allocSegment = 0; Tcl_Size numChars, segmentLimit, segmentNumBytes; Tcl_Obj *segment; | | | 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 |
int gotMinus = 0, gotHash = 0, gotZero = 0, gotSpace = 0, gotPlus = 0;
int gotPrecision, sawFlag, useShort = 0, useBig = 0;
Tcl_WideInt width, precision;
int useWide = 0;
int newXpg, allocSegment = 0;
Tcl_Size numChars, segmentLimit, segmentNumBytes;
Tcl_Obj *segment;
int step = TclUtfToUniChar(format, &ch);
format += step;
if (ch != '%') {
numBytes += step;
continue;
}
if (numBytes) {
|
| ︙ | ︙ | |||
2030 2031 2032 2033 2034 2035 2036 | goto errorMsg; } /* * Step 4. Precision. */ | | | 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 |
goto errorMsg;
}
/*
* Step 4. Precision.
*/
gotPrecision = precision = 0;
if (ch == '.') {
gotPrecision = 1;
format += step;
step = TclUtfToUniChar(format, &ch);
}
if (isdigit(UCHAR(ch))) {
/* Note ull will be >= 0 because of isdigit check above */
|
| ︙ | ︙ | |||
2151 2152 2153 2154 2155 2156 2157 |
numChars = precision;
Tcl_IncrRefCount(segment);
allocSegment = 1;
}
}
break;
case 'c': {
| < < > | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 |
numChars = precision;
Tcl_IncrRefCount(segment);
allocSegment = 1;
}
}
break;
case 'c': {
char buf[4] = "";
int code, length;
if (TclGetIntFromObj(interp, segment, &code) != TCL_OK) {
goto error;
}
if ((unsigned)code > 0x10FFFF) {
code = 0xFFFD;
}
|
| ︙ | ︙ | |||
2371 2372 2373 2374 2375 2376 2377 |
}
if (useShort) {
unsigned short us = (unsigned short) s;
bits = (Tcl_WideUInt) us;
while (us) {
numDigits++;
| | | 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 |
}
if (useShort) {
unsigned short us = (unsigned short) s;
bits = (Tcl_WideUInt) us;
while (us) {
numDigits++;
us /= base;
}
} else if (useWide) {
Tcl_WideUInt uw = (Tcl_WideUInt) w;
bits = uw;
while (uw) {
numDigits++;
|
| ︙ | ︙ | |||
2428 2429 2430 2431 2432 2433 2434 |
if (index < big.used && (size_t) shift <
CHAR_BIT*sizeof(Tcl_WideUInt) - MP_DIGIT_BIT) {
bits |= ((Tcl_WideUInt) big.dp[index++]) << shift;
shift += MP_DIGIT_BIT;
}
shift -= numBits;
}
| | | | | | 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 |
if (index < big.used && (size_t) shift <
CHAR_BIT*sizeof(Tcl_WideUInt) - MP_DIGIT_BIT) {
bits |= ((Tcl_WideUInt) big.dp[index++]) << shift;
shift += MP_DIGIT_BIT;
}
shift -= numBits;
}
digitOffset = bits % base;
if (digitOffset > 9) {
if (ch == 'X') {
bytes[numDigits] = 'A' + digitOffset - 10;
} else {
bytes[numDigits] = 'a' + digitOffset - 10;
}
} else {
bytes[numDigits] = '0' + digitOffset;
}
bits /= base;
}
if (useBig) {
mp_clear(&big);
}
if (gotPrecision) {
|
| ︙ | ︙ | |||
2513 2514 2515 2516 2517 2518 2519 |
}
if (gotPlus) {
*p++ = '+';
}
if (width) {
p += snprintf(p, TCL_INTEGER_SPACE, "%" TCL_LL_MODIFIER "d", width);
if (width > length) {
| | | | | 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 |
}
if (gotPlus) {
*p++ = '+';
}
if (width) {
p += snprintf(p, TCL_INTEGER_SPACE, "%" TCL_LL_MODIFIER "d", width);
if (width > length) {
length = width;
}
}
if (gotPrecision) {
*p++ = '.';
p += snprintf(p, TCL_INTEGER_SPACE, "%" TCL_LL_MODIFIER "d", precision);
if (precision > TCL_SIZE_MAX - length) {
msg = overflow;
errCode = "OVERFLOW";
goto errorMsg;
}
length += precision;
}
/*
* Don't pass length modifiers!
*/
*p++ = (char) ch;
|
| ︙ | ︙ | |||
2565 2566 2567 2568 2569 2570 2571 |
*q = 'p';
}
}
break;
}
default:
if (interp != NULL) {
| | | | 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 |
*q = 'p';
}
}
break;
}
default:
if (interp != NULL) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("bad field specifier \"%c\"", ch));
Tcl_SetErrorCode(interp, "TCL", "FORMAT", "BADTYPE", (char *)NULL);
}
goto error;
}
if (width>0 && numChars<0) {
numChars = Tcl_GetCharLength(segment);
|
| ︙ | ︙ | |||
2653 2654 2655 2656 2657 2658 2659 |
*/
Tcl_Obj *
Tcl_Format(
Tcl_Interp *interp,
const char *format,
Tcl_Size objc,
| | | 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 |
*/
Tcl_Obj *
Tcl_Format(
Tcl_Interp *interp,
const char *format,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
int result;
Tcl_Obj *objPtr;
TclNewObj(objPtr);
result = Tcl_AppendFormatToObj(interp, objPtr, format, objc, objv);
if (result != TCL_OK) {
|
| ︙ | ︙ | |||
2813 2814 2815 2816 2817 2818 2819 |
case 'A':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
if (size > 0) {
| | | | | | 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 |
case 'A':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
if (size > 0) {
Tcl_ListObjAppendElement(NULL, list, Tcl_NewDoubleObj(
(double)va_arg(argList, long double)));
} else {
Tcl_ListObjAppendElement(NULL, list, Tcl_NewDoubleObj(
va_arg(argList, double)));
}
seekingConversion = 0;
break;
case '*':
lastNum = va_arg(argList, int);
Tcl_ListObjAppendElement(NULL, list, Tcl_NewWideIntObj(lastNum));
p++;
|
| ︙ | ︙ | |||
3152 3153 3154 3155 3156 3157 3158 |
*---------------------------------------------------------------------------
*/
Tcl_Obj *
TclStringCat(
Tcl_Interp *interp,
Tcl_Size objc,
| | | | 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 |
*---------------------------------------------------------------------------
*/
Tcl_Obj *
TclStringCat(
Tcl_Interp *interp,
Tcl_Size objc,
Tcl_Obj * const objv[],
int flags)
{
Tcl_Obj *objResultPtr, * const *ov;
int binary = 1;
Tcl_Size oc, length = 0;
int allowUniChar = 1, requestUniChar = 0, forceUniChar = 0;
Tcl_Size first = objc - 1; /* Index of first value possibly not empty */
Tcl_Size last = 0; /* Index of last value possibly not empty */
int inPlace = (flags & TCL_STRING_IN_PLACE) && !Tcl_IsShared(*objv);
|
| ︙ | ︙ | |||
3416 3417 3418 3419 3420 3421 3422 |
/* Ugly interface! Force resize of the unicode array. */
(void)Tcl_GetUnicodeFromObj(objResultPtr, &start);
Tcl_InvalidateStringRep(objResultPtr);
if (0 == Tcl_AttemptSetObjLength(objResultPtr, length)) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
| | | | | | | | 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 |
/* Ugly interface! Force resize of the unicode array. */
(void)Tcl_GetUnicodeFromObj(objResultPtr, &start);
Tcl_InvalidateStringRep(objResultPtr);
if (0 == Tcl_AttemptSetObjLength(objResultPtr, length)) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"concatenation failed: unable to alloc %"
TCL_Z_MODIFIER "u bytes",
STRING_SIZE(length)));
Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
}
return NULL;
}
dst = Tcl_GetUnicode(objResultPtr) + start;
} else {
Tcl_UniChar ch = 0;
/* Ugly interface! No scheme to init array size. */
objResultPtr = Tcl_NewUnicodeObj(&ch, 0); /* PANIC? */
if (0 == Tcl_AttemptSetObjLength(objResultPtr, length)) {
Tcl_DecrRefCount(objResultPtr);
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"concatenation failed: unable to alloc %"
TCL_Z_MODIFIER "u bytes",
STRING_SIZE(length)));
Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
}
return NULL;
}
dst = Tcl_GetUnicode(objResultPtr);
}
while (objc--) {
|
| ︙ | ︙ | |||
3466 3467 3468 3469 3470 3471 3472 |
objResultPtr = *objv++;
objc--;
(void)TclGetStringFromObj(objResultPtr, &start);
if (0 == Tcl_AttemptSetObjLength(objResultPtr, length)) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
| | < | | < | | 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 |
objResultPtr = *objv++;
objc--;
(void)TclGetStringFromObj(objResultPtr, &start);
if (0 == Tcl_AttemptSetObjLength(objResultPtr, length)) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"concatenation failed: unable to alloc %" TCL_SIZE_MODIFIER "d bytes",
length));
Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
}
return NULL;
}
dst = TclGetString(objResultPtr) + start;
TclFreeInternalRep(objResultPtr);
} else {
TclNewObj(objResultPtr); /* PANIC? */
if (0 == Tcl_AttemptSetObjLength(objResultPtr, length)) {
Tcl_DecrRefCount(objResultPtr);
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"concatenation failed: unable to alloc %" TCL_SIZE_MODIFIER "d bytes",
length));
Tcl_SetErrorCode(interp, "TCL", "MEMORY", (char *)NULL);
}
return NULL;
}
dst = TclGetString(objResultPtr);
}
while (objc--) {
|
| ︙ | ︙ | |||
3521 3522 3523 3524 3525 3526 3527 |
return NULL;
}
/*
*---------------------------------------------------------------------------
*
* TclStringCmp --
| < | 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 |
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
|
| ︙ | ︙ | |||
3814 3815 3816 3817 3818 3819 3820 |
* The comparison function should compare up to the minimum byte
* length only.
*/
match = memCmpFn(s1, s2, length);
}
if ((match == 0) && (reqlength > length)) {
| < < | > | 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 |
* The comparison function should compare up to the minimum byte
* length only.
*/
match = memCmpFn(s1, s2, length);
}
if ((match == 0) && (reqlength > length)) {
match = s1len - s2len;
}
match = (match > 0) ? 1 : (match < 0) ? -1 : 0;
}
matchdone:
return match;
}
/*
*---------------------------------------------------------------------------
|
| ︙ | ︙ | |||
4145 4146 4147 4148 4149 4150 4151 |
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.
*/
| | | 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 |
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.
*/
int bytesInChar = TclUtfToUniChar(from, &chw);
ReverseBytes((unsigned char *)to, (unsigned char *)from,
bytesInChar);
to += bytesInChar;
from += bytesInChar;
bytesLeft -= bytesInChar;
}
|
| ︙ | ︙ | |||
4380 4381 4382 4383 4384 4385 4386 |
}
*dst = 0;
}
/*
*----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 |
}
*dst = 0;
}
/*
*----------------------------------------------------------------------
*
* DupStringInternalRep --
*
* Initialize the internal representation of a new Tcl_Obj to a copy of
* the internal representation of an existing string object.
*
* Results:
* None.
|
| ︙ | ︙ | |||
4457 4458 4459 4460 4461 4462 4463 |
* bother copying it. Don't even bother allocating space in which to
* copy it. Just let the copy be untyped.
*/
return;
}
if (srcStringPtr->hasUnicode) {
| | | 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 |
* bother copying it. Don't even bother allocating space in which to
* copy it. Just let the copy be untyped.
*/
return;
}
if (srcStringPtr->hasUnicode) {
int copyMaxChars;
if (srcStringPtr->maxChars / 2 >= srcStringPtr->numChars) {
copyMaxChars = 2 * srcStringPtr->numChars;
} else {
copyMaxChars = srcStringPtr->maxChars;
}
copyStringPtr = stringAttemptAlloc(copyMaxChars);
|
| ︙ | ︙ |
Changes to generic/tclStringRep.h.
1 2 3 | /* * tclStringRep.h -- * | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * tclStringRep.h -- * * This file contains the definition of internal representations of a string * and macros to access it. * * Conceptually, a string is a sequence of Unicode code points. Internally * it may be stored in an encoding form such as a modified version of UTF-8 * or UTF-32. * * Copyright (c) 1995-1997 Sun Microsystems, Inc. * Copyright (c) 1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLSTRINGREP #define _TCLSTRINGREP |
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
(String *) Tcl_AttemptRealloc((ptr), STRING_SIZE(numChars))
#define GET_STRING(objPtr) \
((String *) (objPtr)->internalRep.twoPtrValue.ptr1)
#define SET_STRING(objPtr, stringPtr) \
((objPtr)->internalRep.twoPtrValue.ptr2 = NULL), \
((objPtr)->internalRep.twoPtrValue.ptr1 = (void *) (stringPtr))
| | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
(String *) Tcl_AttemptRealloc((ptr), STRING_SIZE(numChars))
#define GET_STRING(objPtr) \
((String *) (objPtr)->internalRep.twoPtrValue.ptr1)
#define SET_STRING(objPtr, stringPtr) \
((objPtr)->internalRep.twoPtrValue.ptr2 = NULL), \
((objPtr)->internalRep.twoPtrValue.ptr1 = (void *) (stringPtr))
#endif /* _TCLSTRINGREP */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclStringTrim.h.
1 2 3 4 5 6 7 | /* * tclStringTrim.h -- * * This file contains the definition of what characters are to be trimmed * from a string by [string trim] by default. It's only needed by Tcl's * implementation; it does not form a public or private API at all. * | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * tclStringTrim.h -- * * This file contains the definition of what characters are to be trimmed * from a string by [string trim] by default. It's only needed by Tcl's * implementation; it does not form a public or private API at all. * * Copyright (c) 1987-1993 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 1998-2000 Scriptics Corporation. * Copyright (c) 2002 ActiveState Corporation. * Copyright (c) 2003-2013 Donal K. Fellows. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef TCL_STRING_TRIM_H #define TCL_STRING_TRIM_H |
| ︙ | ︙ |
Changes to generic/tclStubCall.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | #else # define dlopen(a,b) (void *)LoadLibraryW(JOIN(L,a)) # define dlsym(a,b) (void *)GetProcAddress((HMODULE)(a),b) # define dlerror() "" #endif MODULE_SCOPE void *tclStubsHandle; | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #else # define dlopen(a,b) (void *)LoadLibraryW(JOIN(L,a)) # define dlsym(a,b) (void *)GetProcAddress((HMODULE)(a),b) # define dlerror() "" #endif MODULE_SCOPE void *tclStubsHandle; /* *---------------------------------------------------------------------- * * TclStubCall -- * * Load the Tcl core dynamically, version "9.0" (or higher, in future versions). * |
| ︙ | ︙ |
Changes to generic/tclStubInit.c.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #undef Tcl_NewDoubleObj #undef Tcl_NewIntObj #undef Tcl_NewListObj #undef Tcl_NewLongObj #undef Tcl_DbNewLongObj #undef Tcl_NewObj #undef Tcl_NewStringObj #undef Tcl_DumpActiveMemory #undef Tcl_ValidateAllMemory #undef Tcl_FindExecutable #undef TclpGetPid #undef TclSockMinimumBuffers #undef Tcl_SetIntObj #undef Tcl_SetLongObj #undef Tcl_SplitPath #undef Tcl_FSSplitPath #undef Tcl_ParseArgsObjv #undef TclStaticLibrary #define TclStaticLibrary Tcl_StaticLibrary #if !defined(_WIN32) && !defined(__CYGWIN__) # define Tcl_WinConvertError 0 #endif #undef TclGetStringFromObj #ifdef TCL_NO_DEPRECATED # define TclGetStringFromObj 0 # define TclGetBytesFromObj 0 # define TclGetUnicodeFromObj 0 #endif | > > > > > > > > > > > > > > < < < < | < < < < < | | | < < < | < < | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | #undef Tcl_NewDoubleObj #undef Tcl_NewIntObj #undef Tcl_NewListObj #undef Tcl_NewLongObj #undef Tcl_DbNewLongObj #undef Tcl_NewObj #undef Tcl_NewStringObj #undef Tcl_GetUnicode #undef Tcl_GetUnicodeFromObj #undef Tcl_NewUnicodeObj #undef Tcl_SetUnicodeObj #undef Tcl_DumpActiveMemory #undef Tcl_ValidateAllMemory #undef Tcl_FindHashEntry #undef Tcl_CreateHashEntry #undef Tcl_Panic #undef Tcl_FindExecutable #undef Tcl_SetExitProc #undef Tcl_SetPanicProc #undef TclpGetPid #undef TclSockMinimumBuffers #undef Tcl_SetIntObj #undef Tcl_SetLongObj #undef Tcl_ListObjGetElements #undef Tcl_ListObjLength #undef Tcl_DictObjSize #undef Tcl_SplitList #undef Tcl_SplitPath #undef Tcl_FSSplitPath #undef Tcl_ParseArgsObjv #undef TclStaticLibrary #define TclStaticLibrary Tcl_StaticLibrary #undef TclObjInterpProc #if !defined(_WIN32) && !defined(__CYGWIN__) # define Tcl_WinConvertError 0 #endif #undef TclGetStringFromObj #ifdef TCL_NO_DEPRECATED # define TclGetStringFromObj 0 # define TclGetBytesFromObj 0 # define TclGetUnicodeFromObj 0 #endif #undef Tcl_Close #define Tcl_Close 0 #undef Tcl_GetByteArrayFromObj #define Tcl_GetByteArrayFromObj 0 #define TclUnusedStubEntry 0 #define TclUtfCharComplete Tcl_UtfCharComplete #define TclUtfNext Tcl_UtfNext #define TclUtfPrev Tcl_UtfPrev #undef TclListObjGetElements #undef TclListObjLength #ifdef TCL_NO_DEPRECATED |
| ︙ | ︙ | |||
190 191 192 193 194 195 196 |
}
int TclGetAliasObj(Tcl_Interp *interp, const char *childCmd,
Tcl_Interp **targetInterpPtr, const char **targetCmdPtr,
int *objcPtr, Tcl_Obj ***objv) {
Tcl_Size n = TCL_INDEX_NONE;
int result = Tcl_GetAliasObj(interp, childCmd, targetInterpPtr, targetCmdPtr, &n, objv);
if (objcPtr) {
| | | > > > > > > > > > > > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
}
int TclGetAliasObj(Tcl_Interp *interp, const char *childCmd,
Tcl_Interp **targetInterpPtr, const char **targetCmdPtr,
int *objcPtr, Tcl_Obj ***objv) {
Tcl_Size n = TCL_INDEX_NONE;
int result = Tcl_GetAliasObj(interp, childCmd, targetInterpPtr, targetCmdPtr, &n, objv);
if (objcPtr) {
if ((sizeof(int) != sizeof(Tcl_Size)) && (result == TCL_OK) && (n > INT_MAX)) {
if (interp) {
Tcl_AppendResult(interp, "List too large to be processed", (char *)NULL);
}
return TCL_ERROR;
}
*objcPtr = (int)n;
}
return result;
}
#endif /* !defined(TCL_NO_DEPRECATED) */
#define Tcl_CreateHashEntry createHashEntry
static Tcl_HashEntry *
Tcl_CreateHashEntry(
Tcl_HashTable *tablePtr,
const void *key,
int *newPtr)
{
return (*((tablePtr)->createProc))(tablePtr, (const char *)(key), newPtr);
}
#define TclBN_mp_add mp_add
#define TclBN_mp_add_d mp_add_d
#define TclBN_mp_and mp_and
#define TclBN_mp_clamp mp_clamp
#define TclBN_mp_clear mp_clear
#define TclBN_mp_clear_multi mp_clear_multi
|
| ︙ | ︙ | |||
282 283 284 285 286 287 288 | # define Tcl_CreateFileHandler 0 # define Tcl_DeleteFileHandler 0 # define Tcl_GetOpenFile 0 # define TclUnixWaitForFile 0 # define TclUnixCopyFile 0 # define TclUnixOpenTemporaryFile 0 # define TclpReaddir 0 | | | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# define Tcl_CreateFileHandler 0
# define Tcl_DeleteFileHandler 0
# define Tcl_GetOpenFile 0
# define TclUnixWaitForFile 0
# define TclUnixCopyFile 0
# define TclUnixOpenTemporaryFile 0
# define TclpReaddir 0
# define TclpIsAtty _isatty
#else
# define TclpIsAtty isatty
#endif
#ifdef __CYGWIN__
static void
doNothing(void)
{
/* dummy implementation, no need to do anything */
|
| ︙ | ︙ | |||
327 328 329 330 331 332 333 |
{
return (Tcl_Size)PTR2INT(pid);
}
/* On Cygwin, long is 64-bit while on Win64 long is 32-bit. Therefore we have
* to make sure that all stub entries on Cygwin follow the Win64 signature.
*/
| | | | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
{
return (Tcl_Size)PTR2INT(pid);
}
/* On Cygwin, long is 64-bit while on Win64 long is 32-bit. Therefore we have
* to make sure that all stub entries on Cygwin follow the Win64 signature.
*/
#define Tcl_GetLongFromObj (int(*)(Tcl_Interp*,Tcl_Obj*,long*))(void *)Tcl_GetIntFromObj
static int exprInt(Tcl_Interp *interp, const char *expr, int *ptr){
long longValue;
int result = Tcl_ExprLong(interp, expr, &longValue);
if (result == TCL_OK) {
if ((longValue >= (long)(INT_MIN))
&& (longValue <= (long)(UINT_MAX))) {
*ptr = (int)longValue;
} else {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"integer value too large to represent", -1));
result = TCL_ERROR;
}
}
return result;
}
#define Tcl_ExprLong (int(*)(Tcl_Interp*,const char*,long*))(void *)exprInt
static int exprIntObj(Tcl_Interp *interp, Tcl_Obj*expr, int *ptr){
long longValue;
int result = Tcl_ExprLongObj(interp, expr, &longValue);
if (result == TCL_OK) {
if ((longValue >= (long)(INT_MIN))
&& (longValue <= (long)(UINT_MAX))) {
*ptr = (int)longValue;
} else {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"integer value too large to represent", -1));
result = TCL_ERROR;
}
}
return result;
}
#define Tcl_ExprLongObj (int(*)(Tcl_Interp*,Tcl_Obj*,long*))(void *)exprIntObj
#else /* __CYGWIN__ */
# define TclWinGetTclInstance 0
# define TclpGetPid 0
# define TclWinFlushDirtyChannels 0
# define TclWinNoBackslash 0
# define TclWinAddProcess 0
|
| ︙ | ︙ | |||
391 392 393 394 395 396 397 |
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#ifdef TCL_WITH_EXTERNAL_TOMMATH
/* If Tcl is linked with an external libtommath 1.2.x, then mp_expt_n doesn't
* exist (since that was introduced in libtommath 1.3.0. Provide it here.) */
mp_err MP_WUR TclBN_mp_expt_n(const mp_int *a, int b, mp_int *c) {
| | | | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#ifdef TCL_WITH_EXTERNAL_TOMMATH
/* If Tcl is linked with an external libtommath 1.2.x, then mp_expt_n doesn't
* exist (since that was introduced in libtommath 1.3.0. Provide it here.) */
mp_err MP_WUR TclBN_mp_expt_n(const mp_int *a, int b, mp_int *c) {
if ((unsigned)b > MP_MIN(MP_DIGIT_MAX, INT_MAX)) {
return MP_VAL;
}
return mp_expt_u32(a, (uint32_t)b, c);;
}
#endif /* TCL_WITH_EXTERNAL_TOMMATH */
/* !BEGIN!: Do not edit below this line. */
static const TclIntStubs tclIntStubs = {
|
| ︙ | ︙ | |||
833 834 835 836 837 838 839 |
Tcl_DbDecrRefCount, /* 19 */
Tcl_DbIncrRefCount, /* 20 */
Tcl_DbIsShared, /* 21 */
0, /* 22 */
Tcl_DbNewByteArrayObj, /* 23 */
Tcl_DbNewDoubleObj, /* 24 */
Tcl_DbNewListObj, /* 25 */
| | | | | | | | | | | | | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 |
Tcl_DbDecrRefCount, /* 19 */
Tcl_DbIncrRefCount, /* 20 */
Tcl_DbIsShared, /* 21 */
0, /* 22 */
Tcl_DbNewByteArrayObj, /* 23 */
Tcl_DbNewDoubleObj, /* 24 */
Tcl_DbNewListObj, /* 25 */
0, /* 26 */
Tcl_DbNewObj, /* 27 */
Tcl_DbNewStringObj, /* 28 */
Tcl_DuplicateObj, /* 29 */
TclFreeObj, /* 30 */
Tcl_GetBoolean, /* 31 */
Tcl_GetBooleanFromObj, /* 32 */
Tcl_GetByteArrayFromObj, /* 33 */
Tcl_GetDouble, /* 34 */
Tcl_GetDoubleFromObj, /* 35 */
0, /* 36 */
Tcl_GetInt, /* 37 */
Tcl_GetIntFromObj, /* 38 */
Tcl_GetLongFromObj, /* 39 */
Tcl_GetObjType, /* 40 */
TclGetStringFromObj, /* 41 */
Tcl_InvalidateStringRep, /* 42 */
Tcl_ListObjAppendList, /* 43 */
Tcl_ListObjAppendElement, /* 44 */
TclListObjGetElements, /* 45 */
Tcl_ListObjIndex, /* 46 */
TclListObjLength, /* 47 */
Tcl_ListObjReplace, /* 48 */
0, /* 49 */
Tcl_NewByteArrayObj, /* 50 */
Tcl_NewDoubleObj, /* 51 */
0, /* 52 */
Tcl_NewListObj, /* 53 */
0, /* 54 */
Tcl_NewObj, /* 55 */
Tcl_NewStringObj, /* 56 */
0, /* 57 */
Tcl_SetByteArrayLength, /* 58 */
Tcl_SetByteArrayObj, /* 59 */
Tcl_SetDoubleObj, /* 60 */
0, /* 61 */
Tcl_SetListObj, /* 62 */
0, /* 63 */
Tcl_SetObjLength, /* 64 */
Tcl_SetStringObj, /* 65 */
0, /* 66 */
0, /* 67 */
Tcl_AllowExceptions, /* 68 */
Tcl_AppendElement, /* 69 */
Tcl_AppendResult, /* 70 */
Tcl_AsyncCreate, /* 71 */
Tcl_AsyncDelete, /* 72 */
Tcl_AsyncInvoke, /* 73 */
Tcl_AsyncMark, /* 74 */
Tcl_AsyncReady, /* 75 */
0, /* 76 */
0, /* 77 */
Tcl_BadChannelOption, /* 78 */
Tcl_CallWhenDeleted, /* 79 */
Tcl_CancelIdleCall, /* 80 */
Tcl_Close, /* 81 */
Tcl_CommandComplete, /* 82 */
Tcl_Concat, /* 83 */
Tcl_ConvertElement, /* 84 */
Tcl_ConvertCountedElement, /* 85 */
Tcl_CreateAlias, /* 86 */
Tcl_CreateAliasObj, /* 87 */
Tcl_CreateChannel, /* 88 */
|
| ︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 |
Tcl_UtfToExternalDString, /* 333 */
Tcl_UtfToLower, /* 334 */
Tcl_UtfToTitle, /* 335 */
Tcl_UtfToChar16, /* 336 */
Tcl_UtfToUpper, /* 337 */
Tcl_WriteChars, /* 338 */
Tcl_WriteObj, /* 339 */
| | | | | 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 |
Tcl_UtfToExternalDString, /* 333 */
Tcl_UtfToLower, /* 334 */
Tcl_UtfToTitle, /* 335 */
Tcl_UtfToChar16, /* 336 */
Tcl_UtfToUpper, /* 337 */
Tcl_WriteChars, /* 338 */
Tcl_WriteObj, /* 339 */
Tcl_GetString, /* 340 */
0, /* 341 */
0, /* 342 */
Tcl_AlertNotifier, /* 343 */
Tcl_ServiceModeHook, /* 344 */
Tcl_UniCharIsAlnum, /* 345 */
Tcl_UniCharIsAlpha, /* 346 */
Tcl_UniCharIsDigit, /* 347 */
Tcl_UniCharIsLower, /* 348 */
Tcl_UniCharIsSpace, /* 349 */
|
| ︙ | ︙ | |||
1228 1229 1230 1231 1232 1233 1234 |
Tcl_IsChannelRegistered, /* 414 */
Tcl_CutChannel, /* 415 */
Tcl_SpliceChannel, /* 416 */
Tcl_ClearChannelHandlers, /* 417 */
Tcl_IsChannelExisting, /* 418 */
0, /* 419 */
0, /* 420 */
| | | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
Tcl_IsChannelRegistered, /* 414 */
Tcl_CutChannel, /* 415 */
Tcl_SpliceChannel, /* 416 */
Tcl_ClearChannelHandlers, /* 417 */
Tcl_IsChannelExisting, /* 418 */
0, /* 419 */
0, /* 420 */
0, /* 421 */
Tcl_CreateHashEntry, /* 422 */
Tcl_InitCustomHashTable, /* 423 */
Tcl_InitObjHashTable, /* 424 */
Tcl_CommandTraceInfo, /* 425 */
Tcl_TraceCommand, /* 426 */
Tcl_UntraceCommand, /* 427 */
Tcl_AttemptAlloc, /* 428 */
|
| ︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 |
Tcl_GetEncodingNulLength, /* 683 */
Tcl_GetWideUIntFromObj, /* 684 */
Tcl_DStringToObj, /* 685 */
Tcl_UtfNcmp, /* 686 */
Tcl_UtfNcasecmp, /* 687 */
Tcl_NewWideUIntObj, /* 688 */
Tcl_SetWideUIntObj, /* 689 */
| < < < < < < < < < < < < | | 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 |
Tcl_GetEncodingNulLength, /* 683 */
Tcl_GetWideUIntFromObj, /* 684 */
Tcl_DStringToObj, /* 685 */
Tcl_UtfNcmp, /* 686 */
Tcl_UtfNcasecmp, /* 687 */
Tcl_NewWideUIntObj, /* 688 */
Tcl_SetWideUIntObj, /* 689 */
TclUnusedStubEntry, /* 690 */
};
/* !END!: Do not edit above this line. */
|
Changes to generic/tclStubLib.c.
| ︙ | ︙ | |||
113 114 115 116 117 118 119 |
count += !ISDIGIT(*p++);
}
if (count == 1) {
const char *q = actualVersion;
p = version;
while (*p && (*p == *q)) {
| | < | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
count += !ISDIGIT(*p++);
}
if (count == 1) {
const char *q = actualVersion;
p = version;
while (*p && (*p == *q)) {
p++; q++;
}
if (*p || ISDIGIT(*q)) {
/* Construct error message */
stubsPtr->tcl_PkgRequireEx(interp, tclName, version, 1, NULL);
return NULL;
}
} else {
|
| ︙ | ︙ |
Changes to generic/tclStubLibTbl.c.
1 2 3 4 5 6 | /* * tclStubLibTbl.c -- * * Stub object that will be statically linked into extensions that want * to access Tcl. * | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /* * tclStubLibTbl.c -- * * Stub object that will be statically linked into extensions that want * to access Tcl. * * Copyright (c) 1998-1999 by Scriptics Corporation. * Copyright (c) 1998 Paul Duffin. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" MODULE_SCOPE void *tclStubsHandle; /* *---------------------------------------------------------------------- * * TclInitStubTable -- * * Initialize the stub table, using the structure pointed at * by the "version" argument. |
| ︙ | ︙ |
Changes to generic/tclTest.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | #ifndef USE_TCL_STUBS # define USE_TCL_STUBS #endif #define TCLBOOLWARNING(boolPtr) /* needed here because we compile with -Wc++-compat */ #include "tclInt.h" #include "tclOO.h" #include <math.h> | < | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#ifndef USE_TCL_STUBS
# define USE_TCL_STUBS
#endif
#define TCLBOOLWARNING(boolPtr) /* needed here because we compile with -Wc++-compat */
#include "tclInt.h"
#include "tclOO.h"
#include <math.h>
/*
* Required for Testregexp*Cmd
*/
#include "tclRegexp.h"
/*
* Required for the TestChannelCmd and TestChannelEventCmd
*/
#include "tclIO.h"
#include "tclUuid.h"
/*
* Declare external functions used in Windows tests.
*/
#ifdef __cplusplus
extern "C" {
#endif
DLLEXPORT int Tcltest_Init(Tcl_Interp *interp);
DLLEXPORT int Tcltest_SafeInit(Tcl_Interp *interp);
#ifdef __cplusplus
}
#endif
/*
* Dynamic string shared by TestdcallCmd and DelCallbackProc; used to collect
* the results of the various deletion callbacks.
|
| ︙ | ︙ | |||
176 177 178 179 180 181 182 | static int AsyncHandlerProc(void *clientData, Tcl_Interp *interp, int code); static Tcl_ThreadCreateType AsyncThreadProc(void *); static void CleanupTestSetassocdataTests( void *clientData, Tcl_Interp *interp); static void CmdDelProc1(void *clientData); static void CmdDelProc2(void *clientData); | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | < | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | < | | | | | | | | | | | | < < | | | | | | | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
static int AsyncHandlerProc(void *clientData,
Tcl_Interp *interp, int code);
static Tcl_ThreadCreateType AsyncThreadProc(void *);
static void CleanupTestSetassocdataTests(
void *clientData, Tcl_Interp *interp);
static void CmdDelProc1(void *clientData);
static void CmdDelProc2(void *clientData);
static Tcl_CmdProc CmdProc1;
static Tcl_CmdProc CmdProc2;
static Tcl_CmdObjTraceProc CmdTraceDeleteProc;
static Tcl_CmdObjTraceProc CmdTraceProc;
static Tcl_ObjCmdProc CreatedCommandProc;
static Tcl_ObjCmdProc CreatedCommandProc2;
static void DelCallbackProc(void *clientData,
Tcl_Interp *interp);
static Tcl_ObjCmdProc DelCmdProc;
static void DelDeleteProc(void *clientData);
static void EncodingFreeProc(void *clientData);
static int EncodingToUtfProc(void *clientData,
const char *src, int srcLen, int flags,
Tcl_EncodingState *statePtr, char *dst,
int dstLen, int *srcReadPtr, int *dstWrotePtr,
int *dstCharsPtr);
static int EncodingFromUtfProc(void *clientData,
const char *src, int srcLen, int flags,
Tcl_EncodingState *statePtr, char *dst,
int dstLen, int *srcReadPtr, int *dstWrotePtr,
int *dstCharsPtr);
static void ExitProcEven(void *clientData);
static void ExitProcOdd(void *clientData);
static Tcl_ObjCmdProc GetTimesCmd;
static Tcl_ResolveCompiledVarProc InterpCompiledVarResolver;
static void MainLoop(void);
static Tcl_CmdProc NoopCmd;
static Tcl_ObjCmdProc NoopObjCmd;
static Tcl_CmdObjTraceProc TraceProc;
static void ObjTraceDeleteProc(void *clientData);
static void PrintParse(Tcl_Interp *interp, Tcl_Parse *parsePtr);
static Tcl_FreeProc SpecialFree;
static int StaticInitProc(Tcl_Interp *interp);
static Tcl_ObjCmdProc TestasyncCmd;
static Tcl_ObjCmdProc TestbumpinterpepochCmd;
static Tcl_ObjCmdProc TestbytestringCmd;
static Tcl_ObjCmdProc TestsetbytearraylengthCmd;
static Tcl_ObjCmdProc TestpurebytesobjCmd;
static Tcl_ObjCmdProc TeststringbytesCmd;
static Tcl_ObjCmdProc2 Testcmdobj2Cmd;
static Tcl_ObjCmdProc TestcmdinfoCmd;
static Tcl_ObjCmdProc TestcmdtokenCmd;
static Tcl_ObjCmdProc TestcmdtraceCmd;
static Tcl_ObjCmdProc TestconcatobjCmd;
static Tcl_ObjCmdProc TestcreatecommandCmd;
static Tcl_ObjCmdProc TestdcallCmd;
static Tcl_ObjCmdProc TestdelCmd;
static Tcl_ObjCmdProc TestdelassocdataCmd;
static Tcl_ObjCmdProc TestdoubledigitsCmd;
static Tcl_ObjCmdProc TestdstringCmd;
static Tcl_ObjCmdProc TestencodingCmd;
static Tcl_ObjCmdProc TestevalexCmd;
static Tcl_ObjCmdProc TestevalobjvCmd;
static Tcl_ObjCmdProc TesteventCmd;
static int TesteventProc(Tcl_Event *event, int flags);
static int TesteventDeleteProc(Tcl_Event *event,
void *clientData);
static Tcl_ObjCmdProc TestexithandlerCmd;
static Tcl_ObjCmdProc TestexprlongCmd;
static Tcl_ObjCmdProc TestexprlongobjCmd;
static Tcl_ObjCmdProc TestexprdoubleCmd;
static Tcl_ObjCmdProc TestexprdoubleobjCmd;
static Tcl_ObjCmdProc TestexprparserCmd;
static Tcl_ObjCmdProc TestexprstringCmd;
static Tcl_ObjCmdProc TestfileCmd;
static Tcl_ObjCmdProc TestfilelinkCmd;
static Tcl_ObjCmdProc TestfeventCmd;
static Tcl_ObjCmdProc TestgetassocdataCmd;
static Tcl_ObjCmdProc TestgetintCmd;
static Tcl_ObjCmdProc TestlongsizeCmd;
static Tcl_ObjCmdProc TestgetplatformCmd;
static Tcl_ObjCmdProc TestgetvarfullnameCmd;
static Tcl_ObjCmdProc TestinterpdeleteCmd;
static Tcl_ObjCmdProc TestlinkCmd;
static Tcl_ObjCmdProc TestlinkarrayCmd;
static Tcl_ObjCmdProc TestlistrepCmd;
static Tcl_ObjCmdProc TestlocaleCmd;
static Tcl_ObjCmdProc TestmainthreadCmd;
static Tcl_ObjCmdProc TestmsbObjCmd;
static Tcl_ObjCmdProc TestsetmainloopCmd;
static Tcl_ObjCmdProc TestexitmainloopCmd;
static Tcl_ObjCmdProc TestpanicCmd;
static Tcl_ObjCmdProc TestparseargsCmd;
static Tcl_ObjCmdProc TestparserCmd;
static Tcl_ObjCmdProc TestparsevarCmd;
static Tcl_ObjCmdProc TestparsevarnameCmd;
static Tcl_ObjCmdProc TestpreferstableCmd;
static Tcl_ObjCmdProc TestprintCmd;
static Tcl_ObjCmdProc TestregexpCmd;
static Tcl_ObjCmdProc TestreturnCmd;
static void TestregexpXflags(const char *string,
size_t length, int *cflagsPtr, int *eflagsPtr);
static Tcl_ObjCmdProc TestsetassocdataCmd;
static Tcl_ObjCmdProc TestsetCmd;
static Tcl_ObjCmdProc Testset2Cmd;
static Tcl_ObjCmdProc TestseterrorcodeCmd;
static Tcl_ObjCmdProc TestsetobjerrorcodeCmd;
static Tcl_ObjCmdProc TestsetplatformCmd;
static Tcl_ObjCmdProc TestSizeCmd;
static Tcl_ObjCmdProc TeststaticlibraryCmd;
static Tcl_ObjCmdProc TesttranslatefilenameCmd;
static Tcl_ObjCmdProc TestfstildeexpandCmd;
static Tcl_ObjCmdProc TestuniClassCmd;
static Tcl_ObjCmdProc TestupvarCmd;
static Tcl_ObjCmdProc2 TestWrongNumArgsCmd;
static Tcl_ObjCmdProc TestGetIndexFromObjStructCmd;
static Tcl_ObjCmdProc TestChannelCmd;
static Tcl_ObjCmdProc TestChannelEventCmd;
static Tcl_ObjCmdProc TestSocketCmd;
static Tcl_ObjCmdProc TestFilesystemCmd;
static Tcl_ObjCmdProc TestSimpleFilesystemCmd;
static void TestReport(const char *cmd, Tcl_Obj *arg1,
Tcl_Obj *arg2);
static Tcl_Obj * TestReportGetNativePath(Tcl_Obj *pathPtr);
static Tcl_FSStatProc TestReportStat;
static Tcl_FSAccessProc TestReportAccess;
static Tcl_FSOpenFileChannelProc TestReportOpenFileChannel;
static Tcl_FSMatchInDirectoryProc TestReportMatchInDirectory;
static Tcl_FSChdirProc TestReportChdir;
static Tcl_FSLstatProc TestReportLstat;
static Tcl_FSCopyFileProc TestReportCopyFile;
static Tcl_FSDeleteFileProc TestReportDeleteFile;
static Tcl_FSRenameFileProc TestReportRenameFile;
static Tcl_FSCreateDirectoryProc TestReportCreateDirectory;
static Tcl_FSCopyDirectoryProc TestReportCopyDirectory;
static Tcl_FSRemoveDirectoryProc TestReportRemoveDirectory;
static int TestReportLoadFile(Tcl_Interp *interp, Tcl_Obj *pathPtr,
Tcl_LoadHandle *handlePtr, Tcl_FSUnloadFileProc **unloadProcPtr);
static Tcl_FSLinkProc TestReportLink;
static Tcl_FSFileAttrStringsProc TestReportFileAttrStrings;
static Tcl_FSFileAttrsGetProc TestReportFileAttrsGet;
static Tcl_FSFileAttrsSetProc TestReportFileAttrsSet;
static Tcl_FSUtimeProc TestReportUtime;
static Tcl_FSNormalizePathProc TestReportNormalizePath;
static Tcl_FSPathInFilesystemProc TestReportInFilesystem;
static Tcl_FSFreeInternalRepProc TestReportFreeInternalRep;
static Tcl_FSDupInternalRepProc TestReportDupInternalRep;
static Tcl_ObjCmdProc TestServiceModeCmd;
static Tcl_FSStatProc SimpleStat;
static Tcl_FSAccessProc SimpleAccess;
static Tcl_FSOpenFileChannelProc SimpleOpenFileChannel;
static Tcl_FSListVolumesProc SimpleListVolumes;
static Tcl_FSPathInFilesystemProc SimplePathInFilesystem;
static Tcl_Obj * SimpleRedirect(Tcl_Obj *pathPtr);
static Tcl_FSMatchInDirectoryProc SimpleMatchInDirectory;
static Tcl_ObjCmdProc TestUtfNextCmd;
static Tcl_ObjCmdProc TestUtfPrevCmd;
static Tcl_ObjCmdProc TestNumUtfCharsCmd;
static Tcl_ObjCmdProc TestGetUniCharCmd;
static Tcl_ObjCmdProc TestFindFirstCmd;
static Tcl_ObjCmdProc TestFindLastCmd;
static Tcl_ObjCmdProc TestHashSystemHashCmd;
static Tcl_ObjCmdProc TestGetIntForIndexCmd;
static Tcl_ObjCmdProc TestLutilCmd;
static Tcl_NRPostProc NREUnwind_callback;
static Tcl_ObjCmdProc TestNREUnwind;
static Tcl_ObjCmdProc TestNRELevels;
static Tcl_ObjCmdProc TestInterpResolverCmd;
#if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL)
static Tcl_ObjCmdProc TestcpuidCmd;
#endif
static Tcl_ObjCmdProc TestApplyLambdaCmd;
#ifdef _WIN32
static Tcl_ObjCmdProc TestHandleCountCmd;
static Tcl_ObjCmdProc TestAppVerifierPresentCmd;
#endif
static const Tcl_Filesystem testReportingFilesystem = {
"reporting",
sizeof(Tcl_Filesystem),
TCL_FILESYSTEM_VERSION_1,
TestReportInFilesystem, /* path in */
|
| ︙ | ︙ | |||
428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
NULL,
/* No load - fallback on core implementation */
NULL,
/* We don't need a getcwd or chdir - fallback on Tcl's versions */
NULL,
NULL
};
/*
*----------------------------------------------------------------------
*
* Tcltest_Init --
*
* This procedure performs application-specific initialization. Most
| > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
NULL,
/* No load - fallback on core implementation */
NULL,
/* We don't need a getcwd or chdir - fallback on Tcl's versions */
NULL,
NULL
};
/*
*----------------------------------------------------------------------
*
* Tcltest_Init --
*
* This procedure performs application-specific initialization. Most
|
| ︙ | ︙ | |||
565 566 567 568 569 570 571 |
if (Tcl_OOInitStubs(interp) == NULL) {
return TCL_ERROR;
}
/*
* Create additional commands and math functions for testing Tcl.
*/
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | | 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 |
if (Tcl_OOInitStubs(interp) == NULL) {
return TCL_ERROR;
}
/*
* Create additional commands and math functions for testing Tcl.
*/
Tcl_CreateObjCommand(interp, "gettimes", GetTimesCmd, NULL, NULL);
Tcl_CreateCommand(interp, "noop", NoopCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "noop", NoopObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testpurebytesobj", TestpurebytesobjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testsetbytearraylength", TestsetbytearraylengthCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testbytestring", TestbytestringCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "teststringbytes", TeststringbytesCmd, NULL, NULL);
Tcl_CreateObjCommand2(interp, "testwrongnumargs", TestWrongNumArgsCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfilesystem", TestFilesystemCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testsimplefilesystem", TestSimpleFilesystemCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetindexfromobjstruct",
TestGetIndexFromObjStructCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testasync", TestasyncCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testbumpinterpepoch",
TestbumpinterpepochCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testchannel", TestChannelCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testchannelevent", TestChannelEventCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testcmdtoken", TestcmdtokenCmd, NULL,
NULL);
Tcl_CreateObjCommand2(interp, "testcmdobj2", Testcmdobj2Cmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testcmdinfo", TestcmdinfoCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "testcmdtrace", TestcmdtraceCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testconcatobj", TestconcatobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testcreatecommand", TestcreatecommandCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testdcall", TestdcallCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testdel", TestdelCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testdelassocdata", TestdelassocdataCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testdoubledigits", TestdoubledigitsCmd,
NULL, NULL);
Tcl_DStringInit(&dstring);
Tcl_CreateObjCommand(interp, "testdstring", TestdstringCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "testencoding", TestencodingCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "testevalex", TestevalexCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testevalobjv", TestevalobjvCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testevent", TesteventCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexithandler", TestexithandlerCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexprlong", TestexprlongCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexprlongobj", TestexprlongobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexprdouble", TestexprdoubleCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexprdoubleobj", TestexprdoubleobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexprparser", TestexprparserCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexprstring", TestexprstringCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfevent", TestfeventCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "testfilelink", TestfilelinkCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfile", TestfileCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testhashsystemhash",
TestHashSystemHashCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetassocdata", TestgetassocdataCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetint", TestgetintCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testlongsize", TestlongsizeCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetplatform", TestgetplatformCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetvarfullname",
TestgetvarfullnameCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testinterpdelete", TestinterpdeleteCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testlink", TestlinkCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testlinkarray", TestlinkarrayCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testlistrep", TestlistrepCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testlocale", TestlocaleCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "testmsb", TestmsbObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testpanic", TestpanicCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testparseargs", TestparseargsCmd,NULL,NULL);
Tcl_CreateObjCommand(interp, "testparser", TestparserCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testparsevar", TestparsevarCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testparsevarname", TestparsevarnameCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testpreferstable", TestpreferstableCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testprint", TestprintCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testregexp", TestregexpCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testreturn", TestreturnCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testservicemode", TestServiceModeCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testsetassocdata", TestsetassocdataCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testsetnoerr", TestsetCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testseterr", TestsetCmd,
INT2PTR(TCL_LEAVE_ERR_MSG), NULL);
Tcl_CreateObjCommand(interp, "testset2", Testset2Cmd,
INT2PTR(TCL_LEAVE_ERR_MSG), NULL);
Tcl_CreateObjCommand(interp, "testseterrorcode", TestseterrorcodeCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testsetobjerrorcode",
TestsetobjerrorcodeCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testutfnext",
TestUtfNextCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testutfprev",
TestUtfPrevCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testnumutfchars",
TestNumUtfCharsCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetunichar",
TestGetUniCharCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testfindfirst",
TestFindFirstCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testfindlast",
TestFindLastCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testgetintforindex",
TestGetIntForIndexCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testsetplatform", TestsetplatformCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testsize", TestSizeCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testsocket", TestSocketCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "teststaticlibrary", TeststaticlibraryCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testtranslatefilename",
TesttranslatefilenameCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testfstildeexpand",
TestfstildeexpandCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testupvar", TestupvarCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testuniclass", TestuniClassCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testmainthread", TestmainthreadCmd, NULL,
NULL);
Tcl_CreateObjCommand(interp, "testsetmainloop", TestsetmainloopCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testexitmainloop", TestexitmainloopCmd,
NULL, NULL);
#if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL)
Tcl_CreateObjCommand(interp, "testcpuid", TestcpuidCmd,
NULL, NULL);
#endif
Tcl_CreateObjCommand(interp, "testnreunwind", TestNREUnwind,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testnrelevels", TestNRELevels,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testinterpresolver", TestInterpResolverCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testapplylambda", TestApplyLambdaCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testlutil", TestLutilCmd,
NULL, NULL);
#if defined(_WIN32)
Tcl_CreateObjCommand(interp, "testhandlecount", TestHandleCountCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testappverifierpresent",
TestAppVerifierPresentCmd, NULL, NULL);
#endif
if (TclObjTest_Init(interp) != TCL_OK) {
return TCL_ERROR;
}
if (Procbodytest_Init(interp) != TCL_OK) {
|
| ︙ | ︙ | |||
805 806 807 808 809 810 811 |
/*
* And finally add any platform specific test commands.
*/
return TclplatformtestInit(interp);
}
| | | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 |
/*
* And finally add any platform specific test commands.
*/
return TclplatformtestInit(interp);
}
/*
*----------------------------------------------------------------------
*
* Tcltest_SafeInit --
*
* This procedure performs application-specific initialization. Most
* applications, especially those that incorporate additional packages,
|
| ︙ | ︙ | |||
834 835 836 837 838 839 840 |
Tcl_Interp *interp) /* Interpreter for application. */
{
if (TestCommonInit(interp) != TCL_OK) {
return TCL_ERROR;
}
return Procbodytest_SafeInit(interp);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 822 823 824 825 826 827 828 829 830 831 832 833 834 835 |
Tcl_Interp *interp) /* Interpreter for application. */
{
if (TestCommonInit(interp) != TCL_OK) {
return TCL_ERROR;
}
return Procbodytest_SafeInit(interp);
}
/*
*----------------------------------------------------------------------
*
* TestasyncCmd --
*
* This procedure implements the "testasync" command. It is used
|
| ︙ | ︙ | |||
908 909 910 911 912 913 914 |
*----------------------------------------------------------------------
*/
static int
TestasyncCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 |
*----------------------------------------------------------------------
*/
static int
TestasyncCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
TestAsyncHandler *asyncPtr, *prevPtr;
int id, code;
static int nextId = 1;
if (objc < 2) {
|
| ︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 |
return TCL_ERROR;
}
return TCL_OK;
}
static int
AsyncHandlerProc(
| | | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 |
return TCL_ERROR;
}
return TCL_OK;
}
static int
AsyncHandlerProc(
void *clientData, /* If of TestAsyncHandler structure.
* in global list. */
Tcl_Interp *interp, /* Interpreter in which command was
* executed, or NULL. */
int code) /* Current return code from command. */
{
TestAsyncHandler *asyncPtr;
int id = PTR2INT(clientData);
const char *listArgv[4];
char *cmd;
char string[TCL_INTEGER_SPACE];
Tcl_MutexLock(&asyncTestMutex);
for (asyncPtr = firstHandler; asyncPtr != NULL;
asyncPtr = asyncPtr->nextPtr) {
|
| ︙ | ︙ | |||
1085 1086 1087 1088 1089 1090 1091 | * Invokes Tcl_AsyncMark on the handler * *---------------------------------------------------------------------- */ static Tcl_ThreadCreateType AsyncThreadProc( | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 |
* Invokes Tcl_AsyncMark on the handler
*
*----------------------------------------------------------------------
*/
static Tcl_ThreadCreateType
AsyncThreadProc(
void *clientData) /* Parameter is the id of a
* TestAsyncHandler, defined above. */
{
TestAsyncHandler *asyncPtr;
int id = PTR2INT(clientData);
Tcl_Sleep(1);
Tcl_MutexLock(&asyncTestMutex);
for (asyncPtr = firstHandler; asyncPtr != NULL;
asyncPtr = asyncPtr->nextPtr) {
if (asyncPtr->id == id) {
Tcl_AsyncMark(asyncPtr->handler);
break;
}
}
Tcl_MutexUnlock(&asyncTestMutex);
Tcl_ExitThread(TCL_OK);
TCL_THREAD_CREATE_RETURN;
}
static int
TestbumpinterpepochCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *)interp;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
iPtr->compileEpoch++;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Testcmdobj2 --
*
* Mock up to test the Tcl_CreateObjCommand2 functionality
*
* Results:
* Standard Tcl result.
*
* Side effects:
* Sets interpreter result to number of arguments, first arg, last arg.
*
*----------------------------------------------------------------------
*/
static int
Testcmdobj2Cmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *resultObj;
resultObj = Tcl_NewListObj(0, NULL);
Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewWideIntObj(objc));
if (objc > 1) {
Tcl_ListObjAppendElement(interp, resultObj, objv[1]);
Tcl_ListObjAppendElement(interp, resultObj, objv[objc-1]);
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TestcmdinfoCmd --
*
* This procedure implements the "testcmdinfo" command. It is used to
* test Tcl_GetCommandInfo, Tcl_SetCommandInfo, and command creation and
|
| ︙ | ︙ | |||
1144 1145 1146 1147 1148 1149 1150 |
*----------------------------------------------------------------------
*/
static int
TestcmdinfoCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 |
*----------------------------------------------------------------------
*/
static int
TestcmdinfoCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const subcmds[] = {
"call", "call2", "create", "delete", "get", "modify", NULL
};
enum options {
CMDINFO_CALL, CMDINFO_CALL2, CMDINFO_CREATE,
CMDINFO_DELETE, CMDINFO_GET, CMDINFO_MODIFY
} idx;
Tcl_CmdInfo info;
Tcl_Obj **cmdObjv;
Tcl_Size cmdObjc;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "command arg");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], subcmds, "option", 0,
&idx) != TCL_OK) {
return TCL_ERROR;
}
switch (idx) {
case CMDINFO_CALL:
case CMDINFO_CALL2:
if (Tcl_ListObjGetElements(interp, objv[2], &cmdObjc, &cmdObjv) != TCL_OK) {
return TCL_ERROR;
}
if (cmdObjc == 0) {
Tcl_AppendResult(interp, "No command name given", (char *)NULL);
return TCL_ERROR;
}
if (Tcl_GetCommandInfo(interp, Tcl_GetString(cmdObjv[0]), &info) == 0) {
return TCL_ERROR;
}
if (idx == CMDINFO_CALL) {
/*
* Note when calling through the old 32-bit API, it is the caller's
* responsibility to check that number of arguments is <= INT_MAX.
* We do not do that here just so we can test what happens if the
* caller mistakenly passes more arguments.
*/
return info.objProc(info.objClientData, interp, cmdObjc, cmdObjv);
} else {
return info.objProc2(info.objClientData2, interp, cmdObjc, cmdObjv);
}
case CMDINFO_CREATE:
Tcl_CreateCommand(interp, Tcl_GetString(objv[2]), CmdProc1,
(void *)"original", CmdDelProc1);
break;
case CMDINFO_DELETE:
Tcl_DStringInit(&delString);
Tcl_DeleteCommand(interp, Tcl_GetString(objv[2]));
Tcl_DStringResult(interp, &delString);
break;
case CMDINFO_GET:
if (Tcl_GetCommandInfo(interp, Tcl_GetString(objv[2]), &info) ==0) {
Tcl_AppendResult(interp, "??", (char *)NULL);
return TCL_OK;
}
if (info.proc == CmdProc1) {
Tcl_AppendResult(interp, "CmdProc1", " ",
(char *)info.clientData, (char *)NULL);
} else if (info.proc == CmdProc2) {
Tcl_AppendResult(interp, "CmdProc2", " ",
(char *)info.clientData, (char *)NULL);
} else {
Tcl_AppendResult(interp, "unknown", (char *)NULL);
}
if (info.deleteProc == CmdDelProc1) {
|
| ︙ | ︙ | |||
1213 1214 1215 1216 1217 1218 1219 |
info.isNativeObjectProc));
return TCL_ERROR;
}
break;
case CMDINFO_MODIFY:
info.proc = CmdProc2;
info.clientData = (void *) "new_command_data";
| < < | | | | | | | | | | | 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 |
info.isNativeObjectProc));
return TCL_ERROR;
}
break;
case CMDINFO_MODIFY:
info.proc = CmdProc2;
info.clientData = (void *) "new_command_data";
info.objProc = NULL;
info.objClientData = NULL;
info.deleteProc = CmdDelProc2;
info.deleteData = (void *) "new_delete_data";
info.namespacePtr = NULL;
info.objProc2 = NULL;
info.objClientData2 = NULL;
if (Tcl_SetCommandInfo(interp, Tcl_GetString(objv[2]), &info) == 0) {
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(0));
} else {
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(1));
}
break;
}
return TCL_OK;
}
static int
CmdProc0(
void *clientData, /* String to return. */
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
TestCommandTokenRef *refPtr = (TestCommandTokenRef *) clientData;
Tcl_AppendResult(interp, "CmdProc1 ", refPtr->value, (char *)NULL);
return TCL_OK;
}
static int
CmdProc1(
void *clientData, /* String to return. */
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*argc*/,
TCL_UNUSED(const char **) /*argv*/)
{
Tcl_AppendResult(interp, "CmdProc1 ", (char *)clientData, (char *)NULL);
return TCL_OK;
}
static int
CmdProc2(
void *clientData, /* String to return. */
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*argc*/,
TCL_UNUSED(const char **) /*argv*/)
{
Tcl_AppendResult(interp, "CmdProc2 ", (char *)clientData, (char *)NULL);
return TCL_OK;
}
static void
CmdDelProc0(
void *clientData) /* String to save. */
{
TestCommandTokenRef *thisRefPtr, *prevRefPtr = NULL;
TestCommandTokenRef *refPtr = (TestCommandTokenRef *) clientData;
int id = refPtr->id;
for (thisRefPtr = firstCommandTokenRef; refPtr != NULL;
thisRefPtr = thisRefPtr->nextPtr) {
if (thisRefPtr->id == id) {
if (prevRefPtr != NULL) {
prevRefPtr->nextPtr = thisRefPtr->nextPtr;
} else {
firstCommandTokenRef = thisRefPtr->nextPtr;
}
break;
}
prevRefPtr = thisRefPtr;
}
Tcl_Free(refPtr);
}
static void
CmdDelProc1(
void *clientData) /* String to save. */
{
Tcl_DStringInit(&delString);
Tcl_DStringAppend(&delString, "CmdDelProc1 ", -1);
Tcl_DStringAppend(&delString, (char *)clientData, -1);
}
static void
CmdDelProc2(
void *clientData) /* String to save. */
{
Tcl_DStringInit(&delString);
Tcl_DStringAppend(&delString, "CmdDelProc2 ", -1);
Tcl_DStringAppend(&delString, (char *)clientData, -1);
}
/*
|
| ︙ | ︙ | |||
1328 1329 1330 1331 1332 1333 1334 |
*----------------------------------------------------------------------
*/
static int
TestcmdtokenCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 |
*----------------------------------------------------------------------
*/
static int
TestcmdtokenCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
TestCommandTokenRef *refPtr;
int id;
char buf[30];
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "option arg");
return TCL_ERROR;
}
if (strcmp(Tcl_GetString(objv[1]), "create") == 0) {
refPtr = (TestCommandTokenRef *)Tcl_Alloc(sizeof(TestCommandTokenRef));
refPtr->token = Tcl_CreateObjCommand(interp, Tcl_GetString(objv[2]), CmdProc0,
refPtr, CmdDelProc0);
refPtr->id = nextCommandTokenRefId;
refPtr->value = "original";
nextCommandTokenRefId++;
refPtr->nextPtr = firstCommandTokenRef;
firstCommandTokenRef = refPtr;
snprintf(buf, sizeof(buf), "%d", refPtr->id);
|
| ︙ | ︙ | |||
1412 1413 1414 1415 1416 1417 1418 |
*----------------------------------------------------------------------
*/
static int
TestcmdtraceCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | | | | | | | | | | | | | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 |
*----------------------------------------------------------------------
*/
static int
TestcmdtraceCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
Tcl_DString buffer;
int result;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "option script");
return TCL_ERROR;
}
if (strcmp(Tcl_GetString(objv[1]), "tracetest") == 0) {
Tcl_DStringInit(&buffer);
cmdTrace = Tcl_CreateObjTrace(interp, 50000, 0, CmdTraceProc, &buffer, NULL);
result = Tcl_EvalEx(interp, Tcl_GetString(objv[2]), TCL_INDEX_NONE, 0);
if (result == TCL_OK) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), (char *)NULL);
}
Tcl_DeleteTrace(interp, cmdTrace);
Tcl_DStringFree(&buffer);
} else if (strcmp(Tcl_GetString(objv[1]), "deletetest") == 0) {
/*
* Create a command trace then eval a script to check whether it is
* called. Note that this trace procedure removes itself as a further
* check of the robustness of the trace proc calling code in
* TclNRExecuteByteCode.
*/
cmdTrace = Tcl_CreateObjTrace(interp, 50000, 0, CmdTraceDeleteProc, NULL, NULL);
Tcl_EvalEx(interp, Tcl_GetString(objv[2]), TCL_INDEX_NONE, 0);
} else if (strcmp(Tcl_GetString(objv[1]), "leveltest") == 0) {
Interp *iPtr = (Interp *) interp;
Tcl_DStringInit(&buffer);
cmdTrace = Tcl_CreateObjTrace(interp, iPtr->numLevels + 4, 0, CmdTraceProc,
&buffer, NULL);
result = Tcl_EvalEx(interp, Tcl_GetString(objv[2]), TCL_INDEX_NONE, 0);
if (result == TCL_OK) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), (char *)NULL);
}
Tcl_DeleteTrace(interp, cmdTrace);
Tcl_DStringFree(&buffer);
} else if (strcmp(Tcl_GetString(objv[1]), "resulttest") == 0) {
/* Create an object-based trace, then eval a script. This is used
* to test return codes other than TCL_OK from the trace engine.
*/
static int deleteCalled;
deleteCalled = 0;
cmdTrace = Tcl_CreateObjTrace(interp, 50000,
TCL_ALLOW_INLINE_COMPILATION, TraceProc,
&deleteCalled, ObjTraceDeleteProc);
result = Tcl_EvalEx(interp, Tcl_GetString(objv[2]), TCL_INDEX_NONE, 0);
Tcl_DeleteTrace(interp, cmdTrace);
if (!deleteCalled) {
Tcl_AppendResult(interp, "Delete wasn't called", (char *)NULL);
return TCL_ERROR;
} else {
return result;
}
} else if (strcmp(Tcl_GetString(objv[1]), "doubletest") == 0) {
Tcl_Trace t1, t2;
Tcl_DStringInit(&buffer);
t1 = Tcl_CreateObjTrace(interp, 1, 0, CmdTraceProc, &buffer, NULL);
t2 = Tcl_CreateObjTrace(interp, 50000, 0, CmdTraceProc, &buffer, NULL);
result = Tcl_EvalEx(interp, Tcl_GetString(objv[2]), TCL_INDEX_NONE, 0);
if (result == TCL_OK) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, Tcl_DStringValue(&buffer), (char *)NULL);
}
Tcl_DeleteTrace(interp, t2);
Tcl_DeleteTrace(interp, t1);
Tcl_DStringFree(&buffer);
} else {
Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[1]),
"\": must be tracetest, deletetest, doubletest or resulttest", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
static int
CmdTraceProc(
void *clientData, /* Pointer to buffer in which the
* command and arguments are appended.
* Accumulates test result. */
TCL_UNUSED(Tcl_Interp *),
TCL_UNUSED(int) /*level*/,
const char *command, /* The command being traced (after
* substitutions). */
TCL_UNUSED(Tcl_Command) /*cmdProc*/,
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
Tcl_DString *bufPtr = (Tcl_DString *) clientData;
Tcl_Size i;
Tcl_DStringAppendElement(bufPtr, command);
Tcl_DStringStartSublist(bufPtr);
for (i = 0; i < objc; i++) {
Tcl_DStringAppendElement(bufPtr, Tcl_GetString(objv[i]));
}
Tcl_DStringEndSublist(bufPtr);
return TCL_OK;
}
static int
CmdTraceDeleteProc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*level*/,
TCL_UNUSED(const char *) /*command*/,
TCL_UNUSED(Tcl_Command),
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
/*
* Remove ourselves to test whether calling Tcl_DeleteTrace within a trace
* callback causes the for loop in TclNRExecuteByteCode that calls traces to
* reference freed memory.
*/
Tcl_DeleteTrace(interp, cmdTrace);
return TCL_OK;
}
static int
TraceProc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
TCL_UNUSED(int) /*level*/,
const char *command,
TCL_UNUSED(Tcl_Command),
TCL_UNUSED(int) /*objc*/,
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *word = Tcl_GetString(objv[0]);
if (!strcmp(word, "Error")) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(command, -1));
return TCL_ERROR;
} else if (!strcmp(word, "Break")) {
|
| ︙ | ︙ | |||
1574 1575 1576 1577 1578 1579 1580 |
}
}
static void
ObjTraceDeleteProc(
void *clientData)
{
| | | | 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 |
}
}
static void
ObjTraceDeleteProc(
void *clientData)
{
int *intPtr = (int *) clientData;
*intPtr = 1; /* Record that the trace was deleted */
}
/*
*----------------------------------------------------------------------
*
* TestcreatecommandCmd --
*
|
| ︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 |
*----------------------------------------------------------------------
*/
static int
TestcreatecommandCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | | < | | | | < | | 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 |
*----------------------------------------------------------------------
*/
static int
TestcreatecommandCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument strings. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option");
return TCL_ERROR;
}
if (strcmp(Tcl_GetString(objv[1]), "create") == 0) {
Tcl_CreateObjCommand(interp, "test_ns_basic::createdcommand",
CreatedCommandProc, NULL, NULL);
} else if (strcmp(Tcl_GetString(objv[1]), "delete") == 0) {
Tcl_DeleteCommand(interp, "test_ns_basic::createdcommand");
} else if (strcmp(Tcl_GetString(objv[1]), "create2") == 0) {
Tcl_CreateObjCommand(interp, "value:at:",
CreatedCommandProc2, NULL, NULL);
} else if (strcmp(Tcl_GetString(objv[1]), "delete2") == 0) {
Tcl_DeleteCommand(interp, "value:at:");
} else {
Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[1]),
"\": must be create, delete, create2, or delete2", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
static int
CreatedCommandProc(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
Tcl_CmdInfo info;
int found;
found = Tcl_GetCommandInfo(interp, "test_ns_basic::createdcommand",
&info);
if (!found) {
Tcl_AppendResult(interp, "CreatedCommandProc could not get command info for test_ns_basic::createdcommand",
(char *)NULL);
return TCL_ERROR;
}
Tcl_AppendResult(interp, "CreatedCommandProc in ",
info.namespacePtr->fullName, (char *)NULL);
return TCL_OK;
}
static int
CreatedCommandProc2(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
Tcl_CmdInfo info;
int found;
found = Tcl_GetCommandInfo(interp, "value:at:", &info);
if (!found) {
Tcl_AppendResult(interp, "CreatedCommandProc2 could not get command info for test_ns_basic::createdcommand",
(char *)NULL);
return TCL_ERROR;
}
Tcl_AppendResult(interp, "CreatedCommandProc2 in ",
info.namespacePtr->fullName, (char *)NULL);
return TCL_OK;
}
|
| ︙ | ︙ | |||
1694 1695 1696 1697 1698 1699 1700 |
*----------------------------------------------------------------------
*/
static int
TestdcallCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 |
*----------------------------------------------------------------------
*/
static int
TestdcallCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
Tcl_Size i;
int id;
delInterp = Tcl_CreateInterp();
Tcl_DStringInit(&delString);
|
| ︙ | ︙ | |||
1718 1719 1720 1721 1722 1723 1724 |
INT2PTR(id));
}
}
Tcl_DeleteInterp(delInterp);
Tcl_DStringResult(interp, &delString);
return TCL_OK;
}
| | | | | 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 |
INT2PTR(id));
}
}
Tcl_DeleteInterp(delInterp);
Tcl_DStringResult(interp, &delString);
return TCL_OK;
}
/*
* The deletion callback used by TestdcallCmd:
*/
static void
DelCallbackProc(
void *clientData, /* Numerical value to append to delString. */
Tcl_Interp *interp) /* Interpreter being deleted. */
{
int id = PTR2INT(clientData);
char buffer[TCL_INTEGER_SPACE];
TclFormatInt(buffer, id);
Tcl_DStringAppendElement(&delString, buffer);
if (interp != delInterp) {
Tcl_DStringAppendElement(&delString, "bogus interpreter argument!");
}
|
| ︙ | ︙ | |||
1759 1760 1761 1762 1763 1764 1765 |
*----------------------------------------------------------------------
*/
static int
TestdelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 |
*----------------------------------------------------------------------
*/
static int
TestdelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
DelCmd *dPtr;
Tcl_Interp *child;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "interp name delcmdname");
return TCL_ERROR;
}
child = Tcl_GetChild(interp, Tcl_GetString(objv[1]));
if (child == NULL) {
return TCL_ERROR;
}
dPtr = (DelCmd *)Tcl_Alloc(sizeof(DelCmd));
dPtr->interp = interp;
dPtr->deleteCmd = (char *)Tcl_Alloc(strlen(Tcl_GetString(objv[3])) + 1);
strcpy(dPtr->deleteCmd, Tcl_GetString(objv[3]));
Tcl_CreateObjCommand(child, Tcl_GetString(objv[2]), DelCmdProc, dPtr,
DelDeleteProc);
return TCL_OK;
}
static int
DelCmdProc(
void *clientData, /* String result to return. */
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objv*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
DelCmd *dPtr = (DelCmd *) clientData;
Tcl_AppendResult(interp, dPtr->deleteCmd, (char *)NULL);
Tcl_Free(dPtr->deleteCmd);
Tcl_Free(dPtr);
return TCL_OK;
}
static void
DelDeleteProc(
void *clientData) /* String command to evaluate. */
{
DelCmd *dPtr = (DelCmd *)clientData;
Tcl_EvalEx(dPtr->interp, dPtr->deleteCmd, TCL_INDEX_NONE, 0);
Tcl_ResetResult(dPtr->interp);
Tcl_Free(dPtr->deleteCmd);
Tcl_Free(dPtr);
|
| ︙ | ︙ | |||
1834 1835 1836 1837 1838 1839 1840 |
*----------------------------------------------------------------------
*/
static int
TestdelassocdataCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 |
*----------------------------------------------------------------------
*/
static int
TestdelassocdataCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "data_key");
return TCL_ERROR;
}
Tcl_DeleteAssocData(interp, Tcl_GetString(objv[1]));
|
| ︙ | ︙ | |||
1869 1870 1871 1872 1873 1874 1875 |
*
*-----------------------------------------------------------------------------
*/
static int
TestdoubledigitsCmd(
TCL_UNUSED(void *),
| | | | | 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 |
*
*-----------------------------------------------------------------------------
*/
static int
TestdoubledigitsCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj* const objv[]) /* Parameter vector */
{
static const char *const options[] = {
"shortest",
"e",
"f",
NULL
};
|
| ︙ | ︙ | |||
1894 1895 1896 1897 1898 1899 1900 |
int status;
int ndigits;
int type;
int decpt;
int signum;
char *str;
char *endPtr;
| | | | | 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 |
int status;
int ndigits;
int type;
int decpt;
int signum;
char *str;
char *endPtr;
Tcl_Obj* strObj;
Tcl_Obj* retval;
if (objc < 4 || objc > 5) {
Tcl_WrongNumArgs(interp, 1, objv, "fpval ndigits type ?shorten?");
return TCL_ERROR;
}
status = Tcl_GetDoubleFromObj(interp, objv[1], &d);
if (status != TCL_OK) {
doubleType = Tcl_GetObjType("double");
if (Tcl_FetchInternalRep(objv[1], doubleType)
&& isnan(objv[1]->internalRep.doubleValue)) {
status = TCL_OK;
memcpy(&d, &(objv[1]->internalRep.doubleValue), sizeof(double));
}
}
if (status != TCL_OK
|| Tcl_GetIntFromObj(interp, objv[2], &ndigits) != TCL_OK
|| Tcl_GetIndexFromObj(interp, objv[3], options, "conversion type",
|
| ︙ | ︙ | |||
1957 1958 1959 1960 1961 1962 1963 |
*----------------------------------------------------------------------
*/
static int
TestdstringCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 |
*----------------------------------------------------------------------
*/
static int
TestdstringCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
int count;
if (objc < 2) {
wrongNumArgs:
Tcl_WrongNumArgs(interp, 1, objv, "option ?args?");
return TCL_ERROR;
}
if (strcmp(Tcl_GetString(objv[1]), "append") == 0) {
if (objc != 4) {
goto wrongNumArgs;
}
if (Tcl_GetIntFromObj(interp, objv[3], &count) != TCL_OK) {
return TCL_ERROR;
}
Tcl_DStringAppend(&dstring, Tcl_GetString(objv[2]), count);
} else if (strcmp(Tcl_GetString(objv[1]), "element") == 0) {
if (objc != 3) {
goto wrongNumArgs;
}
|
| ︙ | ︙ | |||
2002 2003 2004 2005 2006 2007 2008 |
} else if (strcmp(Tcl_GetString(objv[1]), "gresult") == 0) {
if (objc != 3) {
goto wrongNumArgs;
}
if (strcmp(Tcl_GetString(objv[2]), "staticsmall") == 0) {
Tcl_AppendResult(interp, "short", (char *)NULL);
} else if (strcmp(Tcl_GetString(objv[2]), "staticlarge") == 0) {
| < < | < < < < < < > | | | > | > | < > > | | | | | | > > > > > > | | | | | < < < < < < < < | | | | | | < < < < < > | < | | < < < < < < | < < < | < | > < < < < < > | > | > > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 |
} else if (strcmp(Tcl_GetString(objv[1]), "gresult") == 0) {
if (objc != 3) {
goto wrongNumArgs;
}
if (strcmp(Tcl_GetString(objv[2]), "staticsmall") == 0) {
Tcl_AppendResult(interp, "short", (char *)NULL);
} else if (strcmp(Tcl_GetString(objv[2]), "staticlarge") == 0) {
Tcl_AppendResult(interp, "first0 first1 first2 first3 first4 first5 first6 first7 first8 first9\nsecond0 second1 second2 second3 second4 second5 second6 second7 second8 second9\nthird0 third1 third2 third3 third4 third5 third6 third7 third8 third9\nfourth0 fourth1 fourth2 fourth3 fourth4 fourth5 fourth6 fourth7 fourth8 fourth9\nfifth0 fifth1 fifth2 fifth3 fifth4 fifth5 fifth6 fifth7 fifth8 fifth9\nsixth0 sixth1 sixth2 sixth3 sixth4 sixth5 sixth6 sixth7 sixth8 sixth9\nseventh0 seventh1 seventh2 seventh3 seventh4 seventh5 seventh6 seventh7 seventh8 seventh9\n", (char *)NULL);
} else if (strcmp(Tcl_GetString(objv[2]), "free") == 0) {
char *s = (char *)Tcl_Alloc(100);
strcpy(s, "This is a malloc-ed string");
Tcl_SetResult(interp, s, TCL_DYNAMIC);
} else if (strcmp(Tcl_GetString(objv[2]), "special") == 0) {
char *s = (char *)Tcl_Alloc(100) + 16;
strcpy(s, "This is a specially-allocated string");
Tcl_SetResult(interp, s, SpecialFree);
} else {
Tcl_AppendResult(interp, "bad gresult option \"", Tcl_GetString(objv[2]),
"\": must be staticsmall, staticlarge, free, or special",
(char *)NULL);
return TCL_ERROR;
}
Tcl_DStringGetResult(interp, &dstring);
} else if (strcmp(Tcl_GetString(objv[1]), "length") == 0) {
if (objc != 2) {
goto wrongNumArgs;
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(Tcl_DStringLength(&dstring)));
} else if (strcmp(Tcl_GetString(objv[1]), "result") == 0) {
if (objc != 2) {
goto wrongNumArgs;
}
Tcl_DStringResult(interp, &dstring);
} else if (strcmp(Tcl_GetString(objv[1]), "toobj") == 0) {
if (objc != 2) {
goto wrongNumArgs;
}
Tcl_SetObjResult(interp, Tcl_DStringToObj(&dstring));
} else if (strcmp(Tcl_GetString(objv[1]), "trunc") == 0) {
if (objc != 3) {
goto wrongNumArgs;
}
if (Tcl_GetIntFromObj(interp, objv[2], &count) != TCL_OK) {
return TCL_ERROR;
}
Tcl_DStringSetLength(&dstring, count);
} else if (strcmp(Tcl_GetString(objv[1]), "start") == 0) {
if (objc != 2) {
goto wrongNumArgs;
}
Tcl_DStringStartSublist(&dstring);
} else {
Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[1]),
"\": must be append, element, end, free, get, gresult, length, "
"result, start, toobj, or trunc", (char *)NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
* The procedure below is used as a special freeProc to test how well
* Tcl_DStringGetResult handles freeProc's other than free.
*/
static void SpecialFree(
#if TCL_MAJOR_VERSION > 8
void *blockPtr /* Block to free. */
#else
char *blockPtr /* Block to free. */
#endif
) {
Tcl_Free(((char *)blockPtr) - 16);
}
/*
*------------------------------------------------------------------------
*
* UtfTransformFn --
*
* Implements a direct call into Tcl_UtfToExternal and Tcl_ExternalToUtf
* as otherwise there is no script level command that directly exercises
* these functions (i/o command cannot test all combinations)
* The arguments at the script level are roughly those of the above
* functions:
* encodingname srcbytes flags state dstlen ?srcreadvar? ?dstwrotevar? ?dstcharsvar?
*
* Results:
* TCL_OK or TCL_ERROR. This indicates any errors running the test, NOT the
* result of Tcl_UtfToExternal or Tcl_ExternalToUtf.
*
* Side effects:
*
* The result in the interpreter is a list of the return code from the
* Tcl_UtfToExternal/Tcl_ExternalToUtf functions, the encoding state, and
* an encoded binary string of length dstLen. Note the string is the
* entire output buffer, not just the part containing the decoded
* portion. This allows for additional checks at test script level.
*
* If any of the srcreadvar, dstwrotevar and dstcharsvar are specified and
* not empty, they are treated as names of variables where the *srcRead,
* *dstWrote and *dstChars output from the functions are stored.
*
* The function also checks internally whether nuls are correctly
* appended as requested but the TCL_ENCODING_NO_TERMINATE flag
* and that no buffer overflows occur.
*------------------------------------------------------------------------
*/
typedef int
UtfTransformFn(Tcl_Interp *interp, Tcl_Encoding encoding, const char *src,
Tcl_Size srcLen, int flags, Tcl_EncodingState *statePtr, char *dst,
Tcl_Size dstLen, int *srcReadPtr, int *dstWrotePtr, int *dstCharsPtr);
static int UtfExtWrapper(
Tcl_Interp *interp, UtfTransformFn *transformer, int objc, Tcl_Obj *const objv[])
{
Tcl_Encoding encoding;
Tcl_EncodingState encState, *encStatePtr;
Tcl_Size srcLen, bufLen;
const unsigned char *bytes;
unsigned char *bufPtr;
int srcRead, dstLen, dstWrote, dstChars;
Tcl_Obj *srcReadVar, *dstWroteVar, *dstCharsVar;
int result;
int flags;
Tcl_Obj **flagObjs;
Tcl_Size nflags;
static const struct {
const char *flagKey;
int flag;
} flagMap[] = {
{"start", TCL_ENCODING_START},
{"end", TCL_ENCODING_END},
{"noterminate", TCL_ENCODING_NO_TERMINATE},
{"charlimit", TCL_ENCODING_CHAR_LIMIT},
{"tcl8", TCL_ENCODING_PROFILE_TCL8},
{"strict", TCL_ENCODING_PROFILE_STRICT},
{"replace", TCL_ENCODING_PROFILE_REPLACE},
{NULL, 0}
};
Tcl_Size i;
Tcl_WideInt wide;
if (objc < 7 || objc > 10) {
Tcl_WrongNumArgs(interp, 2, objv,
"encoding srcbytes flags state dstlen ?srcreadvar? ?dstwrotevar? ?dstcharsvar?");
return TCL_ERROR;
}
if (Tcl_GetEncodingFromObj(interp, objv[2], &encoding) != TCL_OK) {
return TCL_ERROR;
}
/* Flags may be specified as list of integers and keywords */
flags = 0;
if (Tcl_ListObjGetElements(interp, objv[4], &nflags, &flagObjs) != TCL_OK) {
|
| ︙ | ︙ | |||
2230 2231 2232 2233 2234 2235 2236 |
encStatePtr = &encState;
} else if (Tcl_GetCharLength(objv[5]) == 0) {
encStatePtr = NULL;
} else {
return TCL_ERROR;
}
| | > > > > > > > | > > > > > > > > > > > > | | > | | < | | | | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < | < < < < < < < | | < < | | > | | | 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 |
encStatePtr = &encState;
} else if (Tcl_GetCharLength(objv[5]) == 0) {
encStatePtr = NULL;
} else {
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[6], &dstLen) != TCL_OK) {
Tcl_FreeEncoding(encoding);
return TCL_ERROR;
}
srcReadVar = NULL;
dstWroteVar = NULL;
dstCharsVar = NULL;
if (objc > 7) {
/* Has caller requested srcRead? */
if (Tcl_GetCharLength(objv[7])) {
srcReadVar = objv[7];
}
if (objc > 8) {
/* Ditto for dstWrote */
if (Tcl_GetCharLength(objv[8])) {
dstWroteVar = objv[8];
}
if (objc > 9) {
if (Tcl_GetCharLength(objv[9])) {
dstCharsVar = objv[9];
}
}
}
}
if (flags & TCL_ENCODING_CHAR_LIMIT) {
/* Caller should have specified the dest char limit */
Tcl_Obj *valueObj;
if (dstCharsVar == NULL ||
(valueObj = Tcl_ObjGetVar2(interp, dstCharsVar, NULL, 0)) == NULL
) {
Tcl_SetResult(interp,
"dstCharsVar must be specified with integer value if "
"TCL_ENCODING_CHAR_LIMIT set in flags.", TCL_STATIC);
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, valueObj, &dstChars) != TCL_OK) {
return TCL_ERROR;
}
} else {
dstChars = 0; /* Only used for output */
}
/* Set up output buffer */
bufLen = dstLen + 4; /* 4 -> overflow detection */
bufPtr = (unsigned char *) Tcl_Alloc(bufLen);
memset(bufPtr, 0xFF, dstLen); /* Need to check nul terminator */
memmove(bufPtr + dstLen, "\xAB\xCD\xEF\xAB", 4); /* overflow detection */
bytes = Tcl_GetByteArrayFromObj(objv[3], &srcLen); /* Last! to avoid shimmering */
result = (*transformer)(interp, encoding, (const char *)bytes, srcLen, flags,
encStatePtr, (char *)bufPtr, dstLen,
srcReadVar ? &srcRead : NULL,
&dstWrote,
dstCharsVar ? &dstChars : NULL);
if (memcmp(bufPtr + bufLen - 4, "\xAB\xCD\xEF\xAB", 4)) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("%s wrote past output buffer",
transformer == Tcl_ExternalToUtf ?
"Tcl_ExternalToUtf" : "Tcl_UtfToExternal"));
result = TCL_ERROR;
} else if (result != TCL_ERROR) {
Tcl_Obj *resultObjs[3];
switch (result) {
case TCL_OK:
resultObjs[0] = Tcl_NewStringObj("ok", TCL_INDEX_NONE);
break;
|
| ︙ | ︙ | |||
2353 2354 2355 2356 2357 2358 2359 |
resultObjs[0] = Tcl_NewStringObj("nospace", TCL_INDEX_NONE);
break;
default:
resultObjs[0] = Tcl_NewIntObj(result);
break;
}
result = TCL_OK;
| | | < | | | > > > > > > | | < < < < < < < < < | < | < | 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 |
resultObjs[0] = Tcl_NewStringObj("nospace", TCL_INDEX_NONE);
break;
default:
resultObjs[0] = Tcl_NewIntObj(result);
break;
}
result = TCL_OK;
resultObjs[1] =
encStatePtr ? Tcl_NewWideIntObj((Tcl_WideInt)(size_t)encState) : Tcl_NewObj();
resultObjs[2] = Tcl_NewByteArrayObj(bufPtr, dstLen);
if (srcReadVar) {
if (Tcl_ObjSetVar2(interp, srcReadVar, NULL, Tcl_NewIntObj(srcRead),
TCL_LEAVE_ERR_MSG) == NULL) {
result = TCL_ERROR;
}
}
if (dstWroteVar) {
if (Tcl_ObjSetVar2(interp, dstWroteVar, NULL, Tcl_NewIntObj(dstWrote),
TCL_LEAVE_ERR_MSG) == NULL) {
result = TCL_ERROR;
}
}
if (dstCharsVar) {
if (Tcl_ObjSetVar2(interp, dstCharsVar, NULL, Tcl_NewIntObj(dstChars),
TCL_LEAVE_ERR_MSG) == NULL) {
result = TCL_ERROR;
}
}
Tcl_SetObjResult(interp, Tcl_NewListObj(3, resultObjs));
}
Tcl_Free(bufPtr);
Tcl_FreeEncoding(encoding); /* Free returned reference */
return result;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2409 2410 2411 2412 2413 2414 2415 |
*----------------------------------------------------------------------
*/
static int
TestencodingCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | < < | < < | 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 |
*----------------------------------------------------------------------
*/
static int
TestencodingCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Encoding encoding;
Tcl_Size length;
const char *string;
TclEncoding *encodingPtr;
static const char *const optionStrings[] = {
"create", "delete", "nullength",
"Tcl_ExternalToUtf", "Tcl_UtfToExternal", NULL
};
enum options {
ENC_CREATE, ENC_DELETE, ENC_NULLENGTH,
ENC_EXTTOUTF, ENC_UTFTOEXT
} index;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "command ?args?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2487 2488 2489 2490 2491 2492 2493 |
break;
case ENC_NULLENGTH:
if (objc > 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?encoding?");
return TCL_ERROR;
}
| | | | | < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 |
break;
case ENC_NULLENGTH:
if (objc > 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?encoding?");
return TCL_ERROR;
}
encoding =
Tcl_GetEncoding(interp, objc == 2 ? NULL : Tcl_GetString(objv[2]));
if (encoding == NULL) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp,
Tcl_NewIntObj(Tcl_GetEncodingNulLength(encoding)));
Tcl_FreeEncoding(encoding);
break;
case ENC_EXTTOUTF:
return UtfExtWrapper(interp,Tcl_ExternalToUtf,objc,objv);
case ENC_UTFTOEXT:
return UtfExtWrapper(interp,Tcl_UtfToExternal,objc,objv);
}
return TCL_OK;
}
static int
EncodingToUtfProc(
void *clientData, /* TclEncoding structure. */
TCL_UNUSED(const char *) /*src*/,
int srcLen, /* Source string length in bytes. */
TCL_UNUSED(int) /*flags*/,
TCL_UNUSED(Tcl_EncodingState *),
char *dst, /* Output buffer. */
int dstLen, /* The maximum length of output buffer. */
int *srcReadPtr, /* Filled with number of bytes read. */
int *dstWrotePtr, /* Filled with number of bytes stored. */
int *dstCharsPtr) /* Filled with number of chars stored. */
{
int len;
TclEncoding *encodingPtr;
encodingPtr = (TclEncoding *) clientData;
Tcl_EvalEx(encodingPtr->interp, encodingPtr->toUtfCmd, TCL_INDEX_NONE, TCL_EVAL_GLOBAL);
len = strlen(Tcl_GetStringResult(encodingPtr->interp));
if (len > dstLen) {
len = dstLen;
}
memcpy(dst, Tcl_GetStringResult(encodingPtr->interp), len);
Tcl_ResetResult(encodingPtr->interp);
*srcReadPtr = srcLen;
*dstWrotePtr = len;
*dstCharsPtr = len;
return TCL_OK;
}
static int
EncodingFromUtfProc(
void *clientData, /* TclEncoding structure. */
TCL_UNUSED(const char *) /*src*/,
int srcLen, /* Source string length in bytes. */
TCL_UNUSED(int) /*flags*/,
TCL_UNUSED(Tcl_EncodingState *),
char *dst, /* Output buffer. */
int dstLen, /* The maximum length of output buffer. */
int *srcReadPtr, /* Filled with number of bytes read. */
int *dstWrotePtr, /* Filled with number of bytes stored. */
int *dstCharsPtr) /* Filled with number of chars stored. */
{
int len;
TclEncoding *encodingPtr;
encodingPtr = (TclEncoding *) clientData;
Tcl_EvalEx(encodingPtr->interp, encodingPtr->fromUtfCmd, TCL_INDEX_NONE, TCL_EVAL_GLOBAL);
len = strlen(Tcl_GetStringResult(encodingPtr->interp));
if (len > dstLen) {
len = dstLen;
}
memcpy(dst, Tcl_GetStringResult(encodingPtr->interp), len);
Tcl_ResetResult(encodingPtr->interp);
*srcReadPtr = srcLen;
*dstWrotePtr = len;
*dstCharsPtr = len;
return TCL_OK;
}
static void
EncodingFreeProc(
void *clientData) /* ClientData associated with type. */
{
TclEncoding *encodingPtr = (TclEncoding *)clientData;
Tcl_Free(encodingPtr->toUtfCmd);
Tcl_Free(encodingPtr->fromUtfCmd);
Tcl_Free(encodingPtr);
}
|
| ︙ | ︙ | |||
2623 2624 2625 2626 2627 2628 2629 |
*----------------------------------------------------------------------
*/
static int
TestevalexCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 |
*----------------------------------------------------------------------
*/
static int
TestevalexCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int flags;
Tcl_Size length;
const char *script;
flags = 0;
if (objc == 3) {
|
| ︙ | ︙ | |||
2669 2670 2671 2672 2673 2674 2675 |
*----------------------------------------------------------------------
*/
static int
TestevalobjvCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 |
*----------------------------------------------------------------------
*/
static int
TestevalobjvCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int evalGlobal;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "global word ?word ...?");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[1], &evalGlobal) != TCL_OK) {
return TCL_ERROR;
}
return Tcl_EvalObjv(interp, objc-2, objv+2,
(evalGlobal) ? TCL_EVAL_GLOBAL : 0);
}
/*
|
| ︙ | ︙ | |||
2718 2719 2720 2721 2722 2723 2724 |
*----------------------------------------------------------------------
*/
static int
TesteventCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
| | | | 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 |
*----------------------------------------------------------------------
*/
static int
TesteventCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const objv[]) /* Parameter vector */
{
static const char *const subcommands[] = { /* Possible subcommands */
"queue", "delete", NULL
};
int subCmdIndex; /* Index of the chosen subcommand */
static const char *const positions[] = { /* Possible queue positions */
"head", "tail", "mark", NULL
|
| ︙ | ︙ | |||
2852 2853 2854 2855 2856 2857 2858 |
*
*----------------------------------------------------------------------
*/
static int
TesteventDeleteProc(
Tcl_Event *event, /* Event to examine */
| | | 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 |
*
*----------------------------------------------------------------------
*/
static int
TesteventDeleteProc(
Tcl_Event *event, /* Event to examine */
void *clientData) /* Tcl_Obj containing the name of the event(s)
* to remove */
{
TestEvent *ev; /* Event to examine */
const char *evNameStr;
Tcl_Obj *targetName; /* Name of the event(s) to delete */
const char *targetNameStr;
|
| ︙ | ︙ | |||
2897 2898 2899 2900 2901 2902 2903 |
*----------------------------------------------------------------------
*/
static int
TestexithandlerCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 |
*----------------------------------------------------------------------
*/
static int
TestexithandlerCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
int value;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "create|delete value");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2925 2926 2927 2928 2929 2930 2931 |
return TCL_ERROR;
}
return TCL_OK;
}
static void
ExitProcOdd(
| | | | | | | | 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 |
return TCL_ERROR;
}
return TCL_OK;
}
static void
ExitProcOdd(
void *clientData) /* Integer value to print. */
{
char buf[16 + TCL_INTEGER_SPACE];
int len;
snprintf(buf, sizeof(buf), "odd %d\n", (int)PTR2INT(clientData));
len = strlen(buf);
if (len != (int) write(1, buf, len)) {
Tcl_Panic("ExitProcOdd: unable to write to stdout");
}
}
static void
ExitProcEven(
void *clientData) /* Integer value to print. */
{
char buf[16 + TCL_INTEGER_SPACE];
int len;
snprintf(buf, sizeof(buf), "even %d\n", (int)PTR2INT(clientData));
len = strlen(buf);
if (len != (int) write(1, buf, len)) {
Tcl_Panic("ExitProcEven: unable to write to stdout");
}
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2972 2973 2974 2975 2976 2977 2978 |
*----------------------------------------------------------------------
*/
static int
TestexprlongCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 |
*----------------------------------------------------------------------
*/
static int
TestexprlongCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
long exprResult;
char buf[4 + TCL_INTEGER_SPACE];
int result;
if (objc != 2) {
|
| ︙ | ︙ | |||
3014 3015 3016 3017 3018 3019 3020 |
*----------------------------------------------------------------------
*/
static int
TestexprlongobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 |
*----------------------------------------------------------------------
*/
static int
TestexprlongobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument objects. */
{
long exprResult;
char buf[4 + TCL_INTEGER_SPACE];
int result;
if (objc != 2) {
|
| ︙ | ︙ | |||
3056 3057 3058 3059 3060 3061 3062 |
*----------------------------------------------------------------------
*/
static int
TestexprdoubleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 |
*----------------------------------------------------------------------
*/
static int
TestexprdoubleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
double exprResult;
char buf[4 + TCL_DOUBLE_SPACE];
int result;
if (objc != 2) {
|
| ︙ | ︙ | |||
3099 3100 3101 3102 3103 3104 3105 |
*----------------------------------------------------------------------
*/
static int
TestexprdoubleobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 |
*----------------------------------------------------------------------
*/
static int
TestexprdoubleobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument objects. */
{
double exprResult;
char buf[4 + TCL_DOUBLE_SPACE];
int result;
if (objc != 2) {
|
| ︙ | ︙ | |||
3141 3142 3143 3144 3145 3146 3147 |
*----------------------------------------------------------------------
*/
static int
TestexprstringCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 |
*----------------------------------------------------------------------
*/
static int
TestexprstringCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "expression");
return TCL_ERROR;
}
return Tcl_ExprString(interp, Tcl_GetString(objv[1]));
}
|
| ︙ | ︙ | |||
3172 3173 3174 3175 3176 3177 3178 |
*----------------------------------------------------------------------
*/
static int
TestfilelinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 |
*----------------------------------------------------------------------
*/
static int
TestfilelinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_Obj *contents;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "source ?target?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3239 3240 3241 3242 3243 3244 3245 |
*----------------------------------------------------------------------
*/
static int
TestgetassocdataCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 |
*----------------------------------------------------------------------
*/
static int
TestgetassocdataCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
char *res;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "data_key");
return TCL_ERROR;
|
| ︙ | ︙ | |||
3276 3277 3278 3279 3280 3281 3282 |
*----------------------------------------------------------------------
*/
static int
TestgetplatformCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 |
*----------------------------------------------------------------------
*/
static int
TestgetplatformCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
static const char *const platformStrings[] = { "unix", "mac", "windows" };
TclPlatformType *platform;
platform = TclGetPlatform();
|
| ︙ | ︙ | |||
3315 3316 3317 3318 3319 3320 3321 |
*----------------------------------------------------------------------
*/
static int
TestinterpdeleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 |
*----------------------------------------------------------------------
*/
static int
TestinterpdeleteCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
Tcl_Interp *childToDelete;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "path");
return TCL_ERROR;
|
| ︙ | ︙ | |||
3354 3355 3356 3357 3358 3359 3360 |
*----------------------------------------------------------------------
*/
static int
TestlinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < < | > | < < | | | | 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 |
*----------------------------------------------------------------------
*/
static int
TestlinkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
static int intVar = 43;
static int boolVar = 4;
static double realVar = 1.23;
static Tcl_WideInt wideVar = 79;
static char *stringVar = NULL;
static char charVar = '@';
static unsigned char ucharVar = 130;
static short shortVar = 3000;
static unsigned short ushortVar = 60000;
static unsigned int uintVar = 0xBEEFFEED;
static long longVar = 123456789L;
static unsigned long ulongVar = 3456789012UL;
static float floatVar = 4.5;
static Tcl_WideUInt uwideVar = 123;
static int created = 0;
char buffer[2*TCL_DOUBLE_SPACE];
int writable, flag;
Tcl_Obj *tmp;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg arg arg arg arg arg arg arg arg arg arg"
" arg arg?");
return TCL_ERROR;
}
if (strcmp(Tcl_GetString(objv[1]), "create") == 0) {
if (objc != 16) {
Tcl_WrongNumArgs(interp, 2, objv, "intRO realRO boolRO stringRO wideRO charRO ucharRO shortRO"
" ushortRO uintRO longRO ulongRO floatRO uwideRO");
return TCL_ERROR;
}
if (created) {
Tcl_UnlinkVar(interp, "int");
Tcl_UnlinkVar(interp, "real");
Tcl_UnlinkVar(interp, "bool");
Tcl_UnlinkVar(interp, "string");
Tcl_UnlinkVar(interp, "wide");
Tcl_UnlinkVar(interp, "char");
Tcl_UnlinkVar(interp, "uchar");
Tcl_UnlinkVar(interp, "short");
Tcl_UnlinkVar(interp, "ushort");
Tcl_UnlinkVar(interp, "uint");
Tcl_UnlinkVar(interp, "long");
Tcl_UnlinkVar(interp, "ulong");
Tcl_UnlinkVar(interp, "float");
Tcl_UnlinkVar(interp, "uwide");
}
created = 1;
if (Tcl_GetBooleanFromObj(interp, objv[2], &writable) != TCL_OK) {
return TCL_ERROR;
}
flag = writable ? 0 : TCL_LINK_READ_ONLY;
if (Tcl_LinkVar(interp, "int", &intVar,
TCL_LINK_INT | flag) != TCL_OK) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 |
return TCL_ERROR;
}
flag = writable ? 0 : TCL_LINK_READ_ONLY;
if (Tcl_LinkVar(interp, "uwide", &uwideVar,
TCL_LINK_WIDE_UINT | flag) != TCL_OK) {
return TCL_ERROR;
}
} else if (strcmp(Tcl_GetString(objv[1]), "delete") == 0) {
Tcl_UnlinkVar(interp, "int");
Tcl_UnlinkVar(interp, "real");
Tcl_UnlinkVar(interp, "bool");
Tcl_UnlinkVar(interp, "string");
Tcl_UnlinkVar(interp, "wide");
Tcl_UnlinkVar(interp, "char");
| > | 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 |
return TCL_ERROR;
}
flag = writable ? 0 : TCL_LINK_READ_ONLY;
if (Tcl_LinkVar(interp, "uwide", &uwideVar,
TCL_LINK_WIDE_UINT | flag) != TCL_OK) {
return TCL_ERROR;
}
} else if (strcmp(Tcl_GetString(objv[1]), "delete") == 0) {
Tcl_UnlinkVar(interp, "int");
Tcl_UnlinkVar(interp, "real");
Tcl_UnlinkVar(interp, "bool");
Tcl_UnlinkVar(interp, "string");
Tcl_UnlinkVar(interp, "wide");
Tcl_UnlinkVar(interp, "char");
|
| ︙ | ︙ | |||
3579 3580 3581 3582 3583 3584 3585 |
if (objc != 16) {
Tcl_WrongNumArgs(interp, 2, objv, "intValue realValue boolValue stringValue wideValue"
" charValue ucharValue shortValue ushortValue uintValue"
" longValue ulongValue floatValue uwideValue");
return TCL_ERROR;
}
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 |
if (objc != 16) {
Tcl_WrongNumArgs(interp, 2, objv, "intValue realValue boolValue stringValue wideValue"
" charValue ucharValue shortValue ushortValue uintValue"
" longValue ulongValue floatValue uwideValue");
return TCL_ERROR;
}
if (Tcl_GetString(objv[2])[0] != 0) {
if (Tcl_GetIntFromObj(interp, objv[2], &intVar) != TCL_OK) {
return TCL_ERROR;
}
}
if (Tcl_GetString(objv[3])[0] != 0) {
if (Tcl_GetDoubleFromObj(interp, objv[3], &realVar) != TCL_OK) {
return TCL_ERROR;
}
}
if (Tcl_GetString(objv[4])[0] != 0) {
if (Tcl_GetBooleanFromObj(interp, objv[4], &boolVar) != TCL_OK) {
return TCL_ERROR;
}
}
if (Tcl_GetString(objv[5])[0] != 0) {
if (stringVar != NULL) {
Tcl_Free(stringVar);
}
if (strcmp(Tcl_GetString(objv[5]), "-") == 0) {
stringVar = NULL;
} else {
stringVar = (char *)Tcl_Alloc(strlen(Tcl_GetString(objv[5])) + 1);
strcpy(stringVar, Tcl_GetString(objv[5]));
}
}
if (Tcl_GetString(objv[6])[0] != 0) {
tmp = Tcl_NewStringObj(Tcl_GetString(objv[6]), -1);
if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) {
Tcl_DecrRefCount(tmp);
return TCL_ERROR;
}
Tcl_DecrRefCount(tmp);
}
if (Tcl_GetString(objv[7])[0]) {
if (Tcl_GetIntFromObj(interp, objv[7], &v) != TCL_OK) {
return TCL_ERROR;
}
charVar = (char) v;
}
if (Tcl_GetString(objv[8])[0]) {
if (Tcl_GetIntFromObj(interp, objv[8], &v) != TCL_OK) {
return TCL_ERROR;
}
ucharVar = (unsigned char) v;
}
if (Tcl_GetString(objv[9])[0]) {
if (Tcl_GetIntFromObj(interp, objv[9], &v) != TCL_OK) {
return TCL_ERROR;
}
shortVar = (short) v;
}
if (Tcl_GetString(objv[10])[0]) {
if (Tcl_GetIntFromObj(interp, objv[10], &v) != TCL_OK) {
return TCL_ERROR;
}
ushortVar = (unsigned short) v;
}
if (Tcl_GetString(objv[11])[0]) {
if (Tcl_GetIntFromObj(interp, objv[11], &v) != TCL_OK) {
return TCL_ERROR;
}
uintVar = (unsigned int) v;
}
if (Tcl_GetString(objv[12])[0]) {
if (Tcl_GetIntFromObj(interp, objv[12], &v) != TCL_OK) {
return TCL_ERROR;
}
longVar = (long) v;
}
if (Tcl_GetString(objv[13])[0]) {
if (Tcl_GetIntFromObj(interp, objv[13], &v) != TCL_OK) {
return TCL_ERROR;
}
ulongVar = (unsigned long) v;
}
if (Tcl_GetString(objv[14])[0]) {
double d;
if (Tcl_GetDoubleFromObj(interp, objv[14], &d) != TCL_OK) {
return TCL_ERROR;
}
floatVar = (float) d;
}
if (Tcl_GetString(objv[15])[0]) {
Tcl_WideInt w;
tmp = Tcl_NewStringObj(Tcl_GetString(objv[15]), -1);
if (Tcl_GetWideIntFromObj(interp, tmp, &w) != TCL_OK) {
Tcl_DecrRefCount(tmp);
return TCL_ERROR;
}
Tcl_DecrRefCount(tmp);
uwideVar = (Tcl_WideUInt)w;
}
} else if (strcmp(Tcl_GetString(objv[1]), "update") == 0) {
int v;
if (objc != 16) {
Tcl_WrongNumArgs(interp, 2, objv, "intValue realValue boolValue stringValue wideValue"
" charValue ucharValue shortValue ushortValue uintValue"
" longValue ulongValue floatValue uwideValue");
return TCL_ERROR;
}
if (Tcl_GetString(objv[2])[0] != 0) {
if (Tcl_GetIntFromObj(interp, objv[2], &intVar) != TCL_OK) {
return TCL_ERROR;
}
Tcl_UpdateLinkedVar(interp, "int");
}
if (Tcl_GetString(objv[3])[0] != 0) {
if (Tcl_GetDoubleFromObj(interp, objv[3], &realVar) != TCL_OK) {
return TCL_ERROR;
}
Tcl_UpdateLinkedVar(interp, "real");
}
if (Tcl_GetString(objv[4])[0] != 0) {
if (Tcl_GetIntFromObj(interp, objv[4], &boolVar) != TCL_OK) {
return TCL_ERROR;
}
Tcl_UpdateLinkedVar(interp, "bool");
}
if (Tcl_GetString(objv[5])[0] != 0) {
if (stringVar != NULL) {
Tcl_Free(stringVar);
}
if (strcmp(Tcl_GetString(objv[5]), "-") == 0) {
stringVar = NULL;
} else {
stringVar = (char *)Tcl_Alloc(strlen(Tcl_GetString(objv[5])) + 1);
strcpy(stringVar, Tcl_GetString(objv[5]));
}
Tcl_UpdateLinkedVar(interp, "string");
}
if (Tcl_GetString(objv[6])[0] != 0) {
tmp = Tcl_NewStringObj(Tcl_GetString(objv[6]), -1);
if (Tcl_GetWideIntFromObj(interp, tmp, &wideVar) != TCL_OK) {
Tcl_DecrRefCount(tmp);
return TCL_ERROR;
}
Tcl_DecrRefCount(tmp);
Tcl_UpdateLinkedVar(interp, "wide");
}
if (Tcl_GetString(objv[7])[0]) {
if (Tcl_GetIntFromObj(interp, objv[7], &v) != TCL_OK) {
return TCL_ERROR;
}
charVar = (char) v;
Tcl_UpdateLinkedVar(interp, "char");
}
if (Tcl_GetString(objv[8])[0]) {
if (Tcl_GetIntFromObj(interp, objv[8], &v) != TCL_OK) {
return TCL_ERROR;
}
ucharVar = (unsigned char) v;
Tcl_UpdateLinkedVar(interp, "uchar");
}
if (Tcl_GetString(objv[9])[0]) {
if (Tcl_GetIntFromObj(interp, objv[9], &v) != TCL_OK) {
return TCL_ERROR;
}
shortVar = (short) v;
Tcl_UpdateLinkedVar(interp, "short");
}
if (Tcl_GetString(objv[10])[0]) {
if (Tcl_GetIntFromObj(interp, objv[10], &v) != TCL_OK) {
return TCL_ERROR;
}
ushortVar = (unsigned short) v;
Tcl_UpdateLinkedVar(interp, "ushort");
}
if (Tcl_GetString(objv[11])[0]) {
if (Tcl_GetIntFromObj(interp, objv[11], &v) != TCL_OK) {
return TCL_ERROR;
}
uintVar = (unsigned int) v;
Tcl_UpdateLinkedVar(interp, "uint");
}
if (Tcl_GetString(objv[12])[0]) {
if (Tcl_GetIntFromObj(interp, objv[12], &v) != TCL_OK) {
return TCL_ERROR;
}
longVar = (long) v;
Tcl_UpdateLinkedVar(interp, "long");
}
if (Tcl_GetString(objv[13])[0]) {
if (Tcl_GetIntFromObj(interp, objv[13], &v) != TCL_OK) {
return TCL_ERROR;
}
ulongVar = (unsigned long) v;
Tcl_UpdateLinkedVar(interp, "ulong");
}
if (Tcl_GetString(objv[14])[0]) {
double d;
if (Tcl_GetDoubleFromObj(interp, objv[14], &d) != TCL_OK) {
return TCL_ERROR;
}
floatVar = (float) d;
Tcl_UpdateLinkedVar(interp, "float");
}
if (Tcl_GetString(objv[15])[0]) {
Tcl_WideInt w;
tmp = Tcl_NewStringObj(Tcl_GetString(objv[15]), -1);
if (Tcl_GetWideIntFromObj(interp, tmp, &w) != TCL_OK) {
Tcl_DecrRefCount(tmp);
return TCL_ERROR;
}
Tcl_DecrRefCount(tmp);
|
| ︙ | ︙ | |||
3801 3802 3803 3804 3805 3806 3807 | } /* *---------------------------------------------------------------------- * * TestlinkarrayCmd -- * | | | | | | | | < | 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 |
}
/*
*----------------------------------------------------------------------
*
* TestlinkarrayCmd --
*
* This function is invoked to process the "testlinkarray" Tcl command.
* It is used to test the 'Tcl_LinkArray' function.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Creates, deletes, and invokes variable links.
*
*----------------------------------------------------------------------
*/
static int
TestlinkarrayCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const LinkOption[] = {
"update", "remove", "create", NULL
};
enum LinkOptionEnum { LINK_UPDATE, LINK_REMOVE, LINK_CREATE } optionIndex;
static const char *const LinkType[] = {
"char", "uchar", "short", "ushort", "int", "uint", "long", "ulong",
"wide", "uwide", "float", "double", "string", "char*", "binary", NULL
};
/* all values after TCL_LINK_CHARS_ARRAY are used as arrays (see below) */
static const int LinkTypes[] = {
TCL_LINK_CHAR, TCL_LINK_UCHAR,
TCL_LINK_SHORT, TCL_LINK_USHORT, TCL_LINK_INT, TCL_LINK_UINT,
TCL_LINK_LONG, TCL_LINK_ULONG, TCL_LINK_WIDE_INT, TCL_LINK_WIDE_UINT,
TCL_LINK_FLOAT, TCL_LINK_DOUBLE, TCL_LINK_STRING, TCL_LINK_CHARS,
TCL_LINK_BINARY
};
int typeIndex, readonly, size;
Tcl_Size i, length;
char *name, *arg;
Tcl_WideInt addr;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option args");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3921 3922 3923 3924 3925 3926 3927 | } /* *---------------------------------------------------------------------- * * TestlistrepCmd -- * | | | | | | | 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 |
}
/*
*----------------------------------------------------------------------
*
* TestlistrepCmd --
*
* This function is invoked to generate a list object with a specific
* internal representation.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
TestlistrepCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
/* Subcommands supported by this command */
static const char *const subcommands[] = {
"new",
"describe",
"config",
"validate",
|
| ︙ | ︙ | |||
3960 3961 3962 3963 3964 3965 3966 |
} cmdIndex;
Tcl_Obj *resultObj = NULL;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?");
return TCL_ERROR;
}
| | > | | > | | | | | | | 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 |
} cmdIndex;
Tcl_Obj *resultObj = NULL;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(
interp, objv[1], subcommands, "command", 0, &cmdIndex)
!= TCL_OK) {
return TCL_ERROR;
}
switch (cmdIndex) {
case LISTREP_NEW:
if (objc < 3 || objc > 5) {
Tcl_WrongNumArgs(interp, 2, objv, "length ?leadSpace endSpace?");
return TCL_ERROR;
} else {
Tcl_WideUInt length;
Tcl_WideUInt leadSpace = 0;
Tcl_WideUInt endSpace = 0;
if (Tcl_GetWideUIntFromObj(interp, objv[2], &length) != TCL_OK) {
return TCL_ERROR;
}
if (objc > 3) {
if (Tcl_GetWideUIntFromObj(interp, objv[3], &leadSpace) != TCL_OK) {
return TCL_ERROR;
}
if (objc > 4) {
if (Tcl_GetWideUIntFromObj(interp, objv[4], &endSpace)
!= TCL_OK) {
return TCL_ERROR;
}
}
}
resultObj = TclListTestObj(length, leadSpace, endSpace);
if (resultObj == NULL) {
Tcl_AppendResult(interp, "List capacity exceeded", (char *)NULL);
return TCL_ERROR;
}
}
break;
case LISTREP_DESCRIBE:
#define APPEND_FIELD(targetObj_, structPtr_, fld_) \
do { \
Tcl_ListObjAppendElement( \
interp, (targetObj_), Tcl_NewStringObj(#fld_, -1)); \
Tcl_ListObjAppendElement( \
interp, (targetObj_), Tcl_NewWideIntObj((structPtr_)->fld_)); \
} while (0)
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "object");
return TCL_ERROR;
} else {
Tcl_Obj **objs;
Tcl_Size nobjs;
|
| ︙ | ︙ | |||
4049 4050 4051 4052 4053 4054 4055 |
case LISTREP_CONFIG:
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, "object");
return TCL_ERROR;
}
resultObj = Tcl_NewListObj(2, NULL);
| | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 |
case LISTREP_CONFIG:
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, "object");
return TCL_ERROR;
}
resultObj = Tcl_NewListObj(2, NULL);
Tcl_ListObjAppendElement(
NULL, resultObj, Tcl_NewStringObj("LIST_SPAN_THRESHOLD", -1));
Tcl_ListObjAppendElement(
NULL, resultObj, Tcl_NewWideIntObj(LIST_SPAN_THRESHOLD));
break;
case LISTREP_VALIDATE:
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "object");
return TCL_ERROR;
}
TclListObjValidate(interp, objv[2]); /* Panics if invalid */
resultObj = Tcl_NewObj();
break;
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TestlocaleCmd --
*
* This procedure implements the "testlocale" command. It is used
|
| ︙ | ︙ | |||
4272 4273 4274 4275 4276 4277 4278 |
*----------------------------------------------------------------------
*/
static int
TestlocaleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 |
*----------------------------------------------------------------------
*/
static int
TestlocaleCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
int index;
const char *locale;
static const char *const optionStrings[] = {
"ctype", "numeric", "time", "collate", "monetary",
"all", NULL
};
|
| ︙ | ︙ | |||
4331 4332 4333 4334 4335 4336 4337 | * Releases storage. * *---------------------------------------------------------------------- */ static void CleanupTestSetassocdataTests( | | | 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 |
* Releases storage.
*
*----------------------------------------------------------------------
*/
static void
CleanupTestSetassocdataTests(
void *clientData, /* Data to be released. */
TCL_UNUSED(Tcl_Interp *))
{
Tcl_Free(clientData);
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
4358 4359 4360 4361 4362 4363 4364 |
*----------------------------------------------------------------------
*/
static int
TestmsbObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 |
*----------------------------------------------------------------------
*/
static int
TestmsbObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_WideInt w = 0;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "integer");
return TCL_ERROR;
}
if (TCL_OK != Tcl_GetWideIntFromObj(interp, objv[1], &w)) {
return TCL_ERROR;
}
if (w <= 0) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("argument must be positive",-1));
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(TclMSB((unsigned long long)w)));
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
4400 4401 4402 4403 4404 4405 4406 |
*----------------------------------------------------------------------
*/
static int
TestparserCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 |
*----------------------------------------------------------------------
*/
static int
TestparserCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
const char *script;
Tcl_Size dummy;
Tcl_Size length;
Tcl_Parse parse;
if (objc != 3) {
|
| ︙ | ︙ | |||
4457 4458 4459 4460 4461 4462 4463 |
*----------------------------------------------------------------------
*/
static int
TestexprparserCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 |
*----------------------------------------------------------------------
*/
static int
TestexprparserCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
const char *script;
Tcl_Size dummy;
Tcl_Size length;
Tcl_Parse parse;
if (objc != 3) {
|
| ︙ | ︙ | |||
4606 4607 4608 4609 4610 4611 4612 |
*----------------------------------------------------------------------
*/
static int
TestparsevarCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 |
*----------------------------------------------------------------------
*/
static int
TestparsevarCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
const char *value, *name, *termPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "varName");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
4647 4648 4649 4650 4651 4652 4653 |
*----------------------------------------------------------------------
*/
static int
TestparsevarnameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 |
*----------------------------------------------------------------------
*/
static int
TestparsevarnameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
const char *script;
int append;
Tcl_Size length, dummy;
Tcl_Parse parse;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "script length append");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
4696 4697 4698 4699 4700 4701 4702 | /* *---------------------------------------------------------------------- * * TestpreferstableCmd -- * * This procedure implements the "testpreferstable" command. It is * used for being able to test the "package" command even when the | | | | 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 |
/*
*----------------------------------------------------------------------
*
* TestpreferstableCmd --
*
* This procedure implements the "testpreferstable" command. It is
* used for being able to test the "package" command even when the
* environment variable TCL_PKG_PREFER_LATEST is set in your environment.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
TestpreferstableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
Interp *iPtr = (Interp *) interp;
iPtr->packagePrefer = PKG_PREFER_STABLE;
return TCL_OK;
}
|
| ︙ | ︙ | |||
4741 4742 4743 4744 4745 4746 4747 |
*----------------------------------------------------------------------
*/
static int
TestprintCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 |
*----------------------------------------------------------------------
*/
static int
TestprintCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_WideInt argv1 = 0;
size_t argv2;
long argv3;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "format wideint");
|
| ︙ | ︙ | |||
4783 4784 4785 4786 4787 4788 4789 |
*----------------------------------------------------------------------
*/
static int
TestregexpCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < | | 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 |
*----------------------------------------------------------------------
*/
static int
TestregexpCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int indices, match, about;
Tcl_Size stringLength, i, ii;
int hasxflags, cflags, eflags;
Tcl_RegExp regExpr;
const char *string;
Tcl_Obj *objPtr;
Tcl_RegExpInfo info;
static const char *const options[] = {
"-indices", "-nocase", "-about", "-expanded",
|
| ︙ | ︙ | |||
4944 4945 4946 4947 4948 4949 4950 |
Tcl_RegExpGetInfo(regExpr, &info);
for (i = 0; i < objc; i++) {
Tcl_Size start, end;
Tcl_Obj *newPtr, *varPtr, *valuePtr;
varPtr = objv[i];
| | | 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 |
Tcl_RegExpGetInfo(regExpr, &info);
for (i = 0; i < objc; i++) {
Tcl_Size start, end;
Tcl_Obj *newPtr, *varPtr, *valuePtr;
varPtr = objv[i];
ii = ((cflags®_EXPECT) && i == objc-1) ? TCL_INDEX_NONE : i;
if (indices) {
Tcl_Obj *objs[2];
if (ii == TCL_INDEX_NONE) {
TclRegExpRangeUniChar(regExpr, ii, &start, &end);
} else if (ii > info.nsubs) {
start = TCL_INDEX_NONE;
|
| ︙ | ︙ | |||
5015 5016 5017 5018 5019 5020 5021 | * regexec flags word, as appropriate. * *---------------------------------------------------------------------- */ static void TestregexpXflags( | | | | 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 |
* regexec flags word, as appropriate.
*
*----------------------------------------------------------------------
*/
static void
TestregexpXflags(
const char *string, /* The string of flags. */
size_t length, /* The length of the string in bytes. */
int *cflagsPtr, /* compile flags word */
int *eflagsPtr) /* exec flags word */
{
size_t i;
int cflags, eflags;
cflags = *cflagsPtr;
|
| ︙ | ︙ | |||
5108 5109 5110 5111 5112 5113 5114 |
*----------------------------------------------------------------------
*/
static int
TestreturnCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
| | | 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 |
*----------------------------------------------------------------------
*/
static int
TestreturnCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
return TCL_RETURN;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
5136 5137 5138 5139 5140 5141 5142 |
*----------------------------------------------------------------------
*/
static int
TestsetassocdataCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 |
*----------------------------------------------------------------------
*/
static int
TestsetassocdataCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
char *buf, *oldData;
Tcl_InterpDeleteProc *procPtr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data_key data_item");
|
| ︙ | ︙ | |||
5186 5187 5188 5189 5190 5191 5192 |
*----------------------------------------------------------------------
*/
static int
TestsetplatformCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 |
*----------------------------------------------------------------------
*/
static int
TestsetplatformCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
Tcl_Size length;
TclPlatformType *platform;
platform = TclGetPlatform();
|
| ︙ | ︙ | |||
5214 5215 5216 5217 5218 5219 5220 |
return TCL_ERROR;
}
return TCL_OK;
}
static int
TestSizeCmd(
| | | | | | 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 |
return TCL_ERROR;
}
return TCL_OK;
}
static int
TestSizeCmd(
TCL_UNUSED(void *), /* Unused */
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const * objv) /* Parameter vector */
{
if (objc != 2) {
goto syntax;
}
if (strcmp(Tcl_GetString(objv[1]), "st_mtime") == 0) {
Tcl_StatBuf *statPtr;
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sizeof(statPtr->st_mtime)));
|
| ︙ | ︙ | |||
5245 5246 5247 5248 5249 5250 5251 | * This procedure implements the "teststaticlibrary" command. * It is used to test the procedure Tcl_StaticLibrary. * * Results: * A standard Tcl result. * * Side effects: | | | | | 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 |
* This procedure implements the "teststaticlibrary" command.
* It is used to test the procedure Tcl_StaticLibrary.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* When the package given by objv[1] is loaded into an interpreter,
* variable "x" in that interpreter is set to "loaded".
*
*----------------------------------------------------------------------
*/
static int
TeststaticlibraryCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
int safe, loaded;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "prefix safe loaded");
return TCL_ERROR;
}
if (Tcl_GetBooleanFromObj(interp, objv[2], &safe) != TCL_OK) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
5305 5306 5307 5308 5309 5310 5311 |
*----------------------------------------------------------------------
*/
static int
TesttranslatefilenameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 |
*----------------------------------------------------------------------
*/
static int
TesttranslatefilenameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
Tcl_DString buffer;
const char *result;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "path");
|
| ︙ | ︙ | |||
5331 5332 5333 5334 5335 5336 5337 | /* *---------------------------------------------------------------------- * * TestfstildeexpandCmd -- * * This procedure implements the "testfstildeexpand" command. * It is used to test the Tcl_FSTildeExpand command. It differs | | | | | 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 |
/*
*----------------------------------------------------------------------
*
* TestfstildeexpandCmd --
*
* This procedure implements the "testfstildeexpand" command.
* It is used to test the Tcl_FSTildeExpand command. It differs
* from the script level "file tildeexpand" tests because of a
* slightly different code path.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
TestfstildeexpandCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_DString buffer;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "PATH");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
5384 5385 5386 5387 5388 5389 5390 |
*----------------------------------------------------------------------
*/
static int
TestupvarCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < | | | 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 |
*----------------------------------------------------------------------
*/
static int
TestupvarCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
int flags = 0;
if ((objc != 5) && (objc != 6)) {
Tcl_WrongNumArgs(interp, 1, objv, "level name ?name2? dest global");
return TCL_ERROR;
}
if (objc == 5) {
if (strcmp(Tcl_GetString(objv[4]), "global") == 0) {
flags = TCL_GLOBAL_ONLY;
} else if (strcmp(Tcl_GetString(objv[4]), "namespace") == 0) {
flags = TCL_NAMESPACE_ONLY;
}
return Tcl_UpVar2(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), NULL, Tcl_GetString(objv[3]), flags);
} else {
if (strcmp(Tcl_GetString(objv[5]), "global") == 0) {
flags = TCL_GLOBAL_ONLY;
} else if (strcmp(Tcl_GetString(objv[5]), "namespace") == 0) {
flags = TCL_NAMESPACE_ONLY;
}
return Tcl_UpVar2(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]),
(Tcl_GetString(objv[3])[0] == 0) ? NULL : Tcl_GetString(objv[3]), Tcl_GetString(objv[4]),
flags);
}
}
/*
*----------------------------------------------------------------------
*
* TestuniClassCmd --
|
| ︙ | ︙ | |||
5435 5436 5437 5438 5439 5440 5441 |
*----------------------------------------------------------------------
*/
static int
TestuniClassCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 |
*----------------------------------------------------------------------
*/
static int
TestuniClassCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "integer");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
5487 5488 5489 5490 5491 5492 5493 |
}
if (Tcl_UniCharIsPunct(value)) {
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj("punct", -1));
}
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
| | | 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 |
}
if (Tcl_UniCharIsPunct(value)) {
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj("punct", -1));
}
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TestseterrorcodeCmd --
*
* This procedure implements the "testseterrorcodeCmd". This tests up to
* five elements passed to the Tcl_SetErrorCode command.
|
| ︙ | ︙ | |||
5510 5511 5512 5513 5514 5515 5516 |
*----------------------------------------------------------------------
*/
static int
TestseterrorcodeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | < | < | < | < | 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 |
*----------------------------------------------------------------------
*/
static int
TestseterrorcodeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
if (objc > 6) {
Tcl_AppendResult(interp, "too many args", (char *)NULL);
return TCL_ERROR;
}
switch (objc) {
case 1:
Tcl_SetErrorCode(interp, "NONE", (char *)NULL);
break;
case 2:
Tcl_SetErrorCode(interp, Tcl_GetString(objv[1]), (char *)NULL);
break;
case 3:
Tcl_SetErrorCode(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), (char *)NULL);
break;
case 4:
Tcl_SetErrorCode(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), Tcl_GetString(objv[3]), (char *)NULL);
break;
case 5:
Tcl_SetErrorCode(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), Tcl_GetString(objv[3]), Tcl_GetString(objv[4]), (char *)NULL);
break;
case 6:
Tcl_SetErrorCode(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), Tcl_GetString(objv[3]), Tcl_GetString(objv[4]),
Tcl_GetString(objv[5]), (char *)NULL);
}
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
5566 5567 5568 5569 5570 5571 5572 |
*----------------------------------------------------------------------
*/
static int
TestsetobjerrorcodeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 |
*----------------------------------------------------------------------
*/
static int
TestsetobjerrorcodeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_SetObjErrorCode(interp, Tcl_ConcatObj(objc - 1, objv + 1));
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
5594 5595 5596 5597 5598 5599 5600 |
*----------------------------------------------------------------------
*/
static int
TestfeventCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 |
*----------------------------------------------------------------------
*/
static int
TestfeventCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
static Tcl_Interp *interp2 = NULL;
int code;
Tcl_Channel chan;
if (objc < 2) {
|
| ︙ | ︙ | |||
5664 5665 5666 5667 5668 5669 5670 |
*----------------------------------------------------------------------
*/
static int
TestpanicCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
| | | | | > < < < | | | 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 |
*----------------------------------------------------------------------
*/
static int
TestpanicCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
/*
* Put the arguments into a var args structure
* Append all of the arguments together separated by spaces
*/
Tcl_Obj *list = Tcl_NewListObj(objc-1, objv+1);
Tcl_Panic("%s", Tcl_GetString(list));
Tcl_DecrRefCount(list);
return TCL_OK;
}
static int
TestfileCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* The argument objects. */
{
int force, i, result;
Tcl_Obj *error = NULL;
const char *subcmd;
Tcl_Size j;
if (objc < 3) {
return TCL_ERROR;
}
force = 0;
i = 2;
if (strcmp(Tcl_GetString(objv[2]), "-force") == 0) {
force = 1;
i = 3;
}
if (objc - i > 2) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
5729 5730 5731 5732 5733 5734 5735 |
} else if (strcmp(subcmd, "mkdir") == 0) {
result = TclpObjCreateDirectory(objv[i]);
} else if (strcmp(subcmd, "cpdir") == 0) {
result = TclpObjCopyDirectory(objv[i], objv[i + 1], &error);
} else if (strcmp(subcmd, "rmdir") == 0) {
result = TclpObjRemoveDirectory(objv[i], force, &error);
} else {
| < | | 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 |
} else if (strcmp(subcmd, "mkdir") == 0) {
result = TclpObjCreateDirectory(objv[i]);
} else if (strcmp(subcmd, "cpdir") == 0) {
result = TclpObjCopyDirectory(objv[i], objv[i + 1], &error);
} else if (strcmp(subcmd, "rmdir") == 0) {
result = TclpObjRemoveDirectory(objv[i], force, &error);
} else {
result = TCL_ERROR;
goto end;
}
if (result != TCL_OK) {
if (error != NULL) {
if (Tcl_GetString(error)[0] != '\0') {
Tcl_AppendResult(interp, Tcl_GetString(error), " ", (char *)NULL);
}
Tcl_DecrRefCount(error);
}
Tcl_AppendResult(interp, Tcl_ErrnoId(), (char *)NULL);
}
|
| ︙ | ︙ | |||
5769 5770 5771 5772 5773 5774 5775 |
*----------------------------------------------------------------------
*/
static int
TestgetvarfullnameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 |
*----------------------------------------------------------------------
*/
static int
TestgetvarfullnameCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
const char *name, *arg;
int flags = 0;
Tcl_Namespace *namespacePtr;
Tcl_CallFrame *framePtr;
Tcl_Var variable;
|
| ︙ | ︙ | |||
5843 5844 5845 5846 5847 5848 5849 |
*----------------------------------------------------------------------
*/
static int
GetTimesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The current interpreter. */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 |
*----------------------------------------------------------------------
*/
static int
GetTimesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* The current interpreter. */
TCL_UNUSED(int) /*cobjc*/,
TCL_UNUSED(Tcl_Obj *const *) /*cobjv*/)
{
Interp *iPtr = (Interp *) interp;
int i, n;
double timePer;
Tcl_Time start, stop;
Tcl_Obj *objPtr, **objv;
const char *s;
char newString[TCL_INTEGER_SPACE];
/* alloc & free 100000 times */
fprintf(stderr, "alloc & free 100000 6 word items\n");
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
objPtr = (Tcl_Obj *)Tcl_Alloc(sizeof(Tcl_Obj));
Tcl_Free(objPtr);
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per alloc+free\n", timePer/100000);
/* alloc 5000 times */
fprintf(stderr, "alloc 5000 6 word items\n");
objv = (Tcl_Obj **)Tcl_Alloc(5000 * sizeof(Tcl_Obj *));
Tcl_GetTime(&start);
for (i = 0; i < 5000; i++) {
objv[i] = (Tcl_Obj *)Tcl_Alloc(sizeof(Tcl_Obj));
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per alloc\n", timePer/5000);
/* free 5000 times */
fprintf(stderr, "free 5000 6 word items\n");
Tcl_GetTime(&start);
for (i = 0; i < 5000; i++) {
Tcl_Free(objv[i]);
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per free\n", timePer/5000);
/* Tcl_NewObj 5000 times */
fprintf(stderr, "Tcl_NewObj 5000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 5000; i++) {
objv[i] = Tcl_NewObj();
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per Tcl_NewObj\n", timePer/5000);
/* Tcl_DecrRefCount 5000 times */
fprintf(stderr, "Tcl_DecrRefCount 5000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 5000; i++) {
objPtr = objv[i];
Tcl_DecrRefCount(objPtr);
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per Tcl_DecrRefCount\n", timePer/5000);
Tcl_Free(objv);
/* TclGetString 100000 times */
fprintf(stderr, "Tcl_GetStringFromObj of \"12345\" 100000 times\n");
objPtr = Tcl_NewStringObj("12345", -1);
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
(void) TclGetString(objPtr);
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per Tcl_GetStringFromObj of \"12345\"\n",
timePer/100000);
/* Tcl_GetIntFromObj 100000 times */
fprintf(stderr, "Tcl_GetIntFromObj of \"12345\" 100000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
if (Tcl_GetIntFromObj(interp, objPtr, &n) != TCL_OK) {
return TCL_ERROR;
}
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per Tcl_GetIntFromObj of \"12345\"\n",
timePer/100000);
Tcl_DecrRefCount(objPtr);
/* Tcl_GetInt 100000 times */
fprintf(stderr, "Tcl_GetInt of \"12345\" 100000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
if (Tcl_GetInt(interp, "12345", &n) != TCL_OK) {
return TCL_ERROR;
}
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per Tcl_GetInt of \"12345\"\n",
timePer/100000);
/* snprintf 100000 times */
fprintf(stderr, "snprintf of 12345 100000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
snprintf(newString, sizeof(newString), "%d", 12345);
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per snprintf of 12345\n",
timePer/100000);
/* hashtable lookup 100000 times */
fprintf(stderr, "hashtable lookup of \"gettimes\" 100000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
(void) Tcl_FindHashEntry(&iPtr->globalNsPtr->cmdTable, "gettimes");
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per hashtable lookup of \"gettimes\"\n",
timePer/100000);
/* Tcl_SetVar 100000 times */
fprintf(stderr, "Tcl_SetVar2 of \"12345\" 100000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
s = Tcl_SetVar2(interp, "a", NULL, "12345", TCL_LEAVE_ERR_MSG);
if (s == NULL) {
return TCL_ERROR;
}
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per Tcl_SetVar of a to \"12345\"\n",
timePer/100000);
/* Tcl_GetVar 100000 times */
fprintf(stderr, "Tcl_GetVar of a==\"12345\" 100000 times\n");
Tcl_GetTime(&start);
for (i = 0; i < 100000; i++) {
s = Tcl_GetVar2(interp, "a", NULL, TCL_LEAVE_ERR_MSG);
if (s == NULL) {
return TCL_ERROR;
}
}
Tcl_GetTime(&stop);
timePer = (stop.sec - start.sec)*1000000 + (stop.usec - start.usec);
fprintf(stderr, " %.3f usec per Tcl_GetVar of a==\"12345\"\n",
timePer/100000);
Tcl_ResetResult(interp);
return TCL_OK;
}
|
| ︙ | ︙ | |||
6022 6023 6024 6025 6026 6027 6028 |
*----------------------------------------------------------------------
*/
static int
NoopCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
| | | | 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 |
*----------------------------------------------------------------------
*/
static int
NoopCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
TCL_UNUSED(int) /*argc*/,
TCL_UNUSED(const char **) /*argv*/)
{
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
6049 6050 6051 6052 6053 6054 6055 |
*----------------------------------------------------------------------
*/
static int
NoopObjCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
| | < | | | 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 |
*----------------------------------------------------------------------
*/
static int
NoopObjCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TeststringbytesCmd --
* Returns bytearray value of the bytes in argument string rep
*
* Results:
* Returns the TCL_OK result code.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
TeststringbytesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_Size n;
const unsigned char *p;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "value");
return TCL_ERROR;
|
| ︙ | ︙ | |||
6115 6116 6117 6118 6119 6120 6121 |
*----------------------------------------------------------------------
*/
static int
TestpurebytesobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 |
*----------------------------------------------------------------------
*/
static int
TestpurebytesobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
Tcl_Obj *objPtr;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?string?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
6162 6163 6164 6165 6166 6167 6168 |
*----------------------------------------------------------------------
*/
static int
TestsetbytearraylengthCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 |
*----------------------------------------------------------------------
*/
static int
TestsetbytearraylengthCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
int n;
Tcl_Obj *obj = NULL;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "value length");
return TCL_ERROR;
}
if (TCL_OK != Tcl_GetIntFromObj(interp, objv[2], &n)) {
return TCL_ERROR;
}
obj = objv[1];
if (Tcl_IsShared(obj)) {
obj = Tcl_DuplicateObj(obj);
}
if (Tcl_SetByteArrayLength(obj, n) == NULL) {
|
| ︙ | ︙ | |||
6211 6212 6213 6214 6215 6216 6217 |
*----------------------------------------------------------------------
*/
static int
TestbytestringCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 |
*----------------------------------------------------------------------
*/
static int
TestbytestringCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* The argument objects. */
{
struct {
#ifndef TCL_NO_DEPRECATED
int n; /* On purpose, not Tcl_Size, in order to demonstrate what happens */
#else
Tcl_Size n;
#endif
|
| ︙ | ︙ | |||
6254 6255 6256 6257 6258 6259 6260 |
* Implements the "testset{err,noerr}" cmds that are used when testing
* Tcl_Set/GetVar C Api with/without TCL_LEAVE_ERR_MSG flag
*
* Results:
* A standard Tcl result.
*
* Side effects:
| | | | 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 |
* Implements the "testset{err,noerr}" cmds that are used when testing
* Tcl_Set/GetVar C Api with/without TCL_LEAVE_ERR_MSG flag
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Variables may be set.
*
*----------------------------------------------------------------------
*/
static int
TestsetCmd(
void *data, /* Additional flags for Get/SetVar2. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
int flags = (int)PTR2INT(data);
const char *value;
if (objc == 2) {
Tcl_AppendResult(interp, "before get", (char *)NULL);
|
| ︙ | ︙ | |||
6295 6296 6297 6298 6299 6300 6301 |
return TCL_ERROR;
}
}
static int
Testset2Cmd(
void *data, /* Additional flags for Get/SetVar2. */
Tcl_Interp *interp, /* Current interpreter. */
| | | < | < | 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 |
return TCL_ERROR;
}
}
static int
Testset2Cmd(
void *data, /* Additional flags for Get/SetVar2. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
int flags = (int)PTR2INT(data);
const char *value;
if (objc == 3) {
Tcl_AppendResult(interp, "before get", (char *)NULL);
value = Tcl_GetVar2(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), flags);
if (value == NULL) {
return TCL_ERROR;
}
Tcl_AppendElement(interp, value);
return TCL_OK;
} else if (objc == 4) {
Tcl_AppendResult(interp, "before set", (char *)NULL);
value = Tcl_SetVar2(interp, Tcl_GetString(objv[1]), Tcl_GetString(objv[2]), Tcl_GetString(objv[3]), flags);
if (value == NULL) {
return TCL_ERROR;
}
Tcl_AppendElement(interp, value);
return TCL_OK;
} else {
Tcl_WrongNumArgs(interp, 1, objv, "varName elemName ?newValue??");
|
| ︙ | ︙ | |||
6346 6347 6348 6349 6350 6351 6352 |
*----------------------------------------------------------------------
*/
static int
TestmainthreadCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 |
*----------------------------------------------------------------------
*/
static int
TestmainthreadCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv)
{
if (objc == 1) {
Tcl_Obj *idObj = Tcl_NewWideIntObj((Tcl_WideInt)(size_t)Tcl_GetCurrentThread());
Tcl_SetObjResult(interp, idObj);
return TCL_OK;
} else {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
}
/*
*----------------------------------------------------------------------
*
* MainLoop --
*
* A main loop set by TestsetmainloopCmd below.
*
|
| ︙ | ︙ | |||
6385 6386 6387 6388 6389 6390 6391 |
{
while (!exitMainLoop) {
Tcl_DoOneEvent(0);
}
fprintf(stdout,"Exit MainLoop\n");
fflush(stdout);
}
| | | 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 |
{
while (!exitMainLoop) {
Tcl_DoOneEvent(0);
}
fprintf(stdout,"Exit MainLoop\n");
fflush(stdout);
}
/*
*----------------------------------------------------------------------
*
* TestsetmainloopCmd --
*
* Implements the "testsetmainloop" cmd that is used to test the
* 'Tcl_SetMainLoop' API.
|
| ︙ | ︙ | |||
6407 6408 6409 6410 6411 6412 6413 |
*----------------------------------------------------------------------
*/
static int
TestsetmainloopCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
| | | | 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 |
*----------------------------------------------------------------------
*/
static int
TestsetmainloopCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
exitMainLoop = 0;
Tcl_SetMainLoop(MainLoop);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TestexitmainloopCmd --
*
* Implements the "testexitmainloop" cmd that is used to test the
* 'Tcl_SetMainLoop' API.
|
| ︙ | ︙ | |||
6436 6437 6438 6439 6440 6441 6442 |
*----------------------------------------------------------------------
*/
static int
TestexitmainloopCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
| | | 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 |
*----------------------------------------------------------------------
*/
static int
TestexitmainloopCmd(
TCL_UNUSED(void *),
TCL_UNUSED(Tcl_Interp *),
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
exitMainLoop = 1;
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
6464 6465 6466 6467 6468 6469 6470 |
*----------------------------------------------------------------------
*/
static int
TestChannelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for result. */
| | | | 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 |
*----------------------------------------------------------------------
*/
static int
TestChannelCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for result. */
int objc, /* Count of additional args. */
Tcl_Obj *const *objv) /* Additional args. */
{
const char *cmdName; /* Sub command. */
Tcl_HashTable *hTblPtr; /* Hash table of channels. */
Tcl_HashSearch hSearch; /* Search variable. */
Tcl_HashEntry *hPtr; /* Search variable. */
Channel *chanPtr; /* The actual channel. */
ChannelState *statePtr; /* state info for channel */
Tcl_Channel chan; /* The opaque type. */
Tcl_Size len; /* Length of subcommand string. */
int IOQueued; /* How much IO is queued inside channel? */
char buf[TCL_INTEGER_SPACE];/* For snprintf. */
int mode; /* rw mode of the channel */
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?additional args..?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
6497 6498 6499 6500 6501 6502 6503 | * Locate channel, remove from the list. */ TestChannel **nextPtrPtr, *curPtr; chan = (Tcl_Channel) NULL; for (nextPtrPtr = &firstDetached, curPtr = firstDetached; | | | > | > > | 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 |
* Locate channel, remove from the list.
*/
TestChannel **nextPtrPtr, *curPtr;
chan = (Tcl_Channel) NULL;
for (nextPtrPtr = &firstDetached, curPtr = firstDetached;
curPtr != NULL;
nextPtrPtr = &(curPtr->nextPtr), curPtr = curPtr->nextPtr) {
if (strcmp(Tcl_GetString(objv[2]), Tcl_GetChannelName(curPtr->chan)) == 0) {
*nextPtrPtr = curPtr->nextPtr;
curPtr->nextPtr = NULL;
chan = curPtr->chan;
Tcl_Free(curPtr);
break;
}
}
} else {
chan = Tcl_GetChannel(interp, Tcl_GetString(objv[2]), &mode);
}
if (chan == (Tcl_Channel) NULL) {
return TCL_ERROR;
}
chanPtr = (Channel *)chan;
statePtr = chanPtr->state;
chanPtr = statePtr->topChanPtr;
chan = (Tcl_Channel) chanPtr;
} else {
statePtr = NULL;
chan = NULL;
}
if ((cmdName[0] == 's') && (strncmp(cmdName, "setchannelerror", len) == 0)) {
Tcl_Obj *msg = objv[3];
Tcl_IncrRefCount(msg);
Tcl_SetChannelError(chan, msg);
Tcl_DecrRefCount(msg);
Tcl_GetChannelError(chan, &msg);
Tcl_SetObjResult(interp, msg);
Tcl_DecrRefCount(msg);
return TCL_OK;
}
if ((cmdName[0] == 's') && (strncmp(cmdName, "setchannelerrorinterp", len) == 0)) {
Tcl_Obj *msg = objv[3];
Tcl_IncrRefCount(msg);
Tcl_SetChannelErrorInterp(interp, msg);
Tcl_DecrRefCount(msg);
Tcl_GetChannelErrorInterp(interp, &msg);
|
| ︙ | ︙ | |||
6794 6795 6796 6797 6798 6799 6800 |
if ((cmdName[0] == 'o') && (strncmp(cmdName, "open", len) == 0)) {
hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_OK;
}
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
| | | | 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 |
if ((cmdName[0] == 'o') && (strncmp(cmdName, "open", len) == 0)) {
hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_OK;
}
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
hPtr != NULL;
hPtr = Tcl_NextHashEntry(&hSearch)) {
Tcl_AppendElement(interp, (char *)Tcl_GetHashKey(hTblPtr, hPtr));
}
return TCL_OK;
}
if ((cmdName[0] == 'o') &&
(strncmp(cmdName, "outputbuffered", len) == 0)) {
|
| ︙ | ︙ | |||
6832 6833 6834 6835 6836 6837 6838 |
if ((cmdName[0] == 'r') && (strncmp(cmdName, "readable", len) == 0)) {
hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_OK;
}
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
| | | | | 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 |
if ((cmdName[0] == 'r') && (strncmp(cmdName, "readable", len) == 0)) {
hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_OK;
}
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
hPtr != NULL;
hPtr = Tcl_NextHashEntry(&hSearch)) {
chanPtr = (Channel *)Tcl_GetHashValue(hPtr);
statePtr = chanPtr->state;
if (statePtr->flags & TCL_READABLE) {
Tcl_AppendElement(interp, (char *)Tcl_GetHashKey(hTblPtr, hPtr));
}
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
6891 6892 6893 6894 6895 6896 6897 |
if ((cmdName[0] == 'w') && (strncmp(cmdName, "writable", len) == 0)) {
hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_OK;
}
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) {
| | | 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 |
if ((cmdName[0] == 'w') && (strncmp(cmdName, "writable", len) == 0)) {
hTblPtr = (Tcl_HashTable *) Tcl_GetAssocData(interp, "tclIO", NULL);
if (hTblPtr == NULL) {
return TCL_OK;
}
for (hPtr = Tcl_FirstHashEntry(hTblPtr, &hSearch);
hPtr != NULL; hPtr = Tcl_NextHashEntry(&hSearch)) {
chanPtr = (Channel *)Tcl_GetHashValue(hPtr);
statePtr = chanPtr->state;
if (statePtr->flags & TCL_WRITABLE) {
Tcl_AppendElement(interp, (char *)Tcl_GetHashKey(hTblPtr, hPtr));
}
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
6957 6958 6959 6960 6961 6962 6963 |
*----------------------------------------------------------------------
*/
static int
TestChannelEventCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 |
*----------------------------------------------------------------------
*/
static int
TestChannelEventCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
Tcl_Obj *resultListPtr;
Channel *chanPtr;
ChannelState *statePtr; /* state info for channel */
EventScriptRecord *esPtr, *prevEsPtr, *nextEsPtr;
const char *cmd;
int index, i, mask;
Tcl_Size len;
if ((objc < 3) || (objc > 5)) {
Tcl_WrongNumArgs(interp, 1, objv, "channel cmd ?arg1? ?arg2?");
return TCL_ERROR;
}
chanPtr = (Channel *)Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
if (chanPtr == NULL) {
return TCL_ERROR;
}
statePtr = chanPtr->state;
cmd = Tcl_GetStringFromObj(objv[2], &len);
if ((cmd[0] == 'a') && (strncmp(cmd, "add", len) == 0)) {
|
| ︙ | ︙ | |||
7026 7027 7028 7029 7030 7031 7032 |
}
if (index < 0) {
Tcl_AppendResult(interp, "bad event index: ", Tcl_GetString(objv[3]),
": must be nonnegative", (char *)NULL);
return TCL_ERROR;
}
for (i = 0, esPtr = statePtr->scriptRecordPtr;
| | | | > | | 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 |
}
if (index < 0) {
Tcl_AppendResult(interp, "bad event index: ", Tcl_GetString(objv[3]),
": must be nonnegative", (char *)NULL);
return TCL_ERROR;
}
for (i = 0, esPtr = statePtr->scriptRecordPtr;
(i < index) && (esPtr != NULL);
i++, esPtr = esPtr->nextPtr) {
/* Empty loop body. */
}
if (esPtr == NULL) {
Tcl_AppendResult(interp, "bad event index ", Tcl_GetString(objv[3]),
": out of range", (char *)NULL);
return TCL_ERROR;
}
if (esPtr == statePtr->scriptRecordPtr) {
statePtr->scriptRecordPtr = esPtr->nextPtr;
} else {
for (prevEsPtr = statePtr->scriptRecordPtr;
(prevEsPtr != NULL) &&
(prevEsPtr->nextPtr != esPtr);
prevEsPtr = prevEsPtr->nextPtr) {
/* Empty loop body. */
}
if (prevEsPtr == NULL) {
Tcl_Panic("TestChannelEventCmd: damaged event script list");
}
prevEsPtr->nextPtr = esPtr->nextPtr;
}
|
| ︙ | ︙ | |||
7063 7064 7065 7066 7067 7068 7069 |
if ((cmd[0] == 'l') && (strncmp(cmd, "list", len) == 0)) {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "channel list");
return TCL_ERROR;
}
resultListPtr = Tcl_GetObjResult(interp);
for (esPtr = statePtr->scriptRecordPtr;
| | | | | | | | | | 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 |
if ((cmd[0] == 'l') && (strncmp(cmd, "list", len) == 0)) {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "channel list");
return TCL_ERROR;
}
resultListPtr = Tcl_GetObjResult(interp);
for (esPtr = statePtr->scriptRecordPtr;
esPtr != NULL;
esPtr = esPtr->nextPtr) {
if (esPtr->mask) {
Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
(esPtr->mask == TCL_READABLE) ? "readable" : "writable", -1));
} else {
Tcl_ListObjAppendElement(interp, resultListPtr,
Tcl_NewStringObj("none", -1));
}
Tcl_ListObjAppendElement(interp, resultListPtr, esPtr->scriptPtr);
}
Tcl_SetObjResult(interp, resultListPtr);
return TCL_OK;
}
if ((cmd[0] == 'r') && (strncmp(cmd, "removeall", len) == 0)) {
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "channel removeall");
return TCL_ERROR;
}
for (esPtr = statePtr->scriptRecordPtr;
esPtr != NULL;
esPtr = nextEsPtr) {
nextEsPtr = esPtr->nextPtr;
Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
TclChannelEventScriptInvoker, esPtr);
Tcl_DecrRefCount(esPtr->scriptPtr);
Tcl_Free(esPtr);
}
statePtr->scriptRecordPtr = NULL;
return TCL_OK;
}
if ((cmd[0] == 's') && (strncmp(cmd, "set", len) == 0)) {
if (objc != 5) {
Tcl_WrongNumArgs(interp, 1, objv, "channel delete index event");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[3], &index) == TCL_ERROR) {
return TCL_ERROR;
}
if (index < 0) {
Tcl_AppendResult(interp, "bad event index: ", Tcl_GetString(objv[3]),
": must be nonnegative", (char *)NULL);
return TCL_ERROR;
}
for (i = 0, esPtr = statePtr->scriptRecordPtr;
(i < index) && (esPtr != NULL);
i++, esPtr = esPtr->nextPtr) {
/* Empty loop body. */
}
if (esPtr == NULL) {
Tcl_AppendResult(interp, "bad event index ", Tcl_GetString(objv[3]),
": out of range", (char *)NULL);
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
7168 7169 7170 7171 7172 7173 7174 |
* process. */
};
static int
TestSocketCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for result. */
| | | | | | 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 |
* process. */
};
static int
TestSocketCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Interpreter for result. */
int objc, /* Count of additional args. */
Tcl_Obj *const *objv) /* Additional args. */
{
const char *cmdName; /* Sub command. */
Tcl_Size len; /* Length of subcommand string. */
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?additional args..?");
return TCL_ERROR;
}
cmdName = Tcl_GetStringFromObj(objv[1], &len);
if ((cmdName[0] == 't') && (strncmp(cmdName, "testflags", len) == 0)) {
Tcl_Channel hChannel;
int modePtr;
int testMode;
TcpState *statePtr;
/* Set test value in the socket driver
*/
/* Check for argument "channel name"
*/
if (objc < 4) {
Tcl_WrongNumArgs(interp, 2, objv, "channel flags");
return TCL_ERROR;
}
hChannel = Tcl_GetChannel(interp, Tcl_GetString(objv[2]), &modePtr);
if ( NULL == hChannel ) {
Tcl_AppendResult(interp, "unknown channel:", Tcl_GetString(objv[2]), (char *)NULL);
return TCL_ERROR;
}
statePtr = (TcpState *)Tcl_GetChannelInstanceData(hChannel);
if ( NULL == statePtr) {
Tcl_AppendResult(interp, "No channel instance data:", Tcl_GetString(objv[2]),
(char *)NULL);
return TCL_ERROR;
}
if (Tcl_GetBooleanFromObj(interp, objv[3], &testMode) != TCL_OK) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
7226 7227 7228 7229 7230 7231 7232 | /* *---------------------------------------------------------------------- * * TestServiceModeCmd -- * * This procedure implements the "testservicemode" command which gets or | | | | | | | | | | | | 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 |
/*
*----------------------------------------------------------------------
*
* TestServiceModeCmd --
*
* This procedure implements the "testservicemode" command which gets or
* sets the current Tcl ServiceMode. There are several tests which open
* a file and assign various handlers to it. For these tests to be
* deterministic it is important that file events not be processed until
* all of the handlers are in place.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* May change the ServiceMode setting.
*
*----------------------------------------------------------------------
*/
static int
TestServiceModeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Arguments. */
{
int newmode, oldmode;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?newmode?");
return TCL_ERROR;
}
oldmode = (Tcl_GetServiceMode() != TCL_SERVICE_NONE);
if (objc == 2) {
if (Tcl_GetIntFromObj(interp, objv[1], &newmode) == TCL_ERROR) {
return TCL_ERROR;
}
if (newmode == 0) {
Tcl_SetServiceMode(TCL_SERVICE_NONE);
} else {
Tcl_SetServiceMode(TCL_SERVICE_ALL);
}
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(oldmode));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TestWrongNumArgsCmd --
*
* Test the Tcl_WrongNumArgs function.
*
|
| ︙ | ︙ | |||
7288 7289 7290 7291 7292 7293 7294 |
*/
static int
TestWrongNumArgsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
| | | 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 |
*/
static int
TestWrongNumArgsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size i, length;
const char *msg;
if (objc < 3) {
goto insufArgs;
}
|
| ︙ | ︙ | |||
7339 7340 7341 7342 7343 7344 7345 |
*----------------------------------------------------------------------
*/
static int
TestGetIndexFromObjStructCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | < | < | 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 |
*----------------------------------------------------------------------
*/
static int
TestGetIndexFromObjStructCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *const ary[] = {
"a", "b", "c", "d", "ee", "ff", NULL, NULL
};
int target, flags = 0;
signed char idx[8];
if (objc != 3 && objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "argument targetvalue ?flags?");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[2], &target) != TCL_OK) {
return TCL_ERROR;
}
if ((objc > 3) && (Tcl_GetIntFromObj(interp, objv[3], &flags) != TCL_OK)) {
return TCL_ERROR;
}
memset(idx, 85, sizeof(idx));
if (Tcl_GetIndexFromObjStruct(interp, (Tcl_GetString(objv[1])[0] ? objv[1] : NULL), ary, 2*sizeof(char *),
"dummy", flags, &idx[1]) != TCL_OK) {
return TCL_ERROR;
}
if (idx[0] != 85 || idx[2] != 85) {
Tcl_AppendResult(interp, "Tcl_GetIndexFromObjStruct overwrites bytes near index variable", (char *)NULL);
return TCL_ERROR;
} else if (idx[1] != target) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "%d", idx[1]);
Tcl_AppendResult(interp, "index value comparison failed: got ",
buffer, (char *)NULL);
snprintf(buffer, sizeof(buffer), "%d", target);
|
| ︙ | ︙ | |||
7403 7404 7405 7406 7407 7408 7409 |
*----------------------------------------------------------------------
*/
static int
TestFilesystemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | < | 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 |
*----------------------------------------------------------------------
*/
static int
TestFilesystemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int res, boolVal;
const char *msg;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "boolean");
return TCL_ERROR;
}
if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) {
|
| ︙ | ︙ | |||
7456 7457 7458 7459 7460 7461 7462 |
lastPathPtr = NULL;
return -1;
}
lastPathPtr = NULL;
*clientDataPtr = newPathPtr;
return TCL_OK;
}
| | | | 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 |
lastPathPtr = NULL;
return -1;
}
lastPathPtr = NULL;
*clientDataPtr = newPathPtr;
return TCL_OK;
}
/*
* Simple helper function to extract the native vfs representation of a path
* object, or NULL if no such representation exists.
*/
static Tcl_Obj *
TestReportGetNativePath(
Tcl_Obj *pathPtr)
{
return (Tcl_Obj*) Tcl_FSGetInternalRep(pathPtr, &testReportingFilesystem);
}
static void
TestReportFreeInternalRep(
void *clientData)
{
Tcl_Obj *nativeRep = (Tcl_Obj *) clientData;
|
| ︙ | ︙ | |||
7753 7754 7755 7756 7757 7758 7759 |
const char *str = Tcl_GetString(pathPtr);
if (strncmp(str, "simplefs:/", 10)) {
return -1;
}
return TCL_OK;
}
| | | 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 |
const char *str = Tcl_GetString(pathPtr);
if (strncmp(str, "simplefs:/", 10)) {
return -1;
}
return TCL_OK;
}
/*
* This is a slightly 'hacky' filesystem which is used just to test a few
* important features of the vfs code: (1) that you can load a shared library
* from a vfs, (2) that when copying files from one fs to another, the 'mtime'
* is preserved. (3) that recursive cross-filesystem directory copies have the
* correct behaviour with/without -force.
*
|
| ︙ | ︙ | |||
7775 7776 7777 7778 7779 7780 7781 |
* important features.
*/
static int
TestSimpleFilesystemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | < | | 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 |
* important features.
*/
static int
TestSimpleFilesystemCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int res, boolVal;
const char *msg;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "boolean");
return TCL_ERROR;
}
if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) {
return TCL_ERROR;
}
if (boolVal) {
res = Tcl_FSRegister(interp, &simpleFilesystem);
msg = (res == TCL_OK) ? "registered" : "failed";
} else {
res = Tcl_FSUnregister(&simpleFilesystem);
msg = (res == TCL_OK) ? "unregistered" : "failed";
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(msg , -1));
return res;
}
/*
* Treats a file name 'simplefs:/foo' by using the file 'foo' in the current
* (native) directory.
*/
static Tcl_Obj *
SimpleRedirect(
|
| ︙ | ︙ | |||
7929 7930 7931 7932 7933 7934 7935 |
retVal = Tcl_NewStringObj("simplefs:/", -1);
Tcl_IncrRefCount(retVal);
return retVal;
}
/*
| < < < < | < | | | < | | | 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 |
retVal = Tcl_NewStringObj("simplefs:/", -1);
Tcl_IncrRefCount(retVal);
return retVal;
}
/*
* Used to check operations of Tcl_UtfNext.
*
* Usage: testutfnext -bytestring $bytes
*/
static int
TestUtfNextCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Size numBytes;
char *bytes;
const char *result, *first;
char buffer[32];
static const char tobetested[] = "A\xA0\xC0\xC1\xC2\xD0\xE0\xE8\xF2\xF7\xF8\xFE\xFF";
const char *p = tobetested;
|
| ︙ | ︙ | |||
7968 7969 7970 7971 7972 7973 7974 |
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"testutfnext\" can only handle %" TCL_Z_MODIFIER "u bytes",
sizeof(buffer) - 4));
return TCL_ERROR;
}
memcpy(buffer + 1, bytes, numBytes);
| | < | < | < | < < < < < < | < | | | < | | | 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 |
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"\"testutfnext\" can only handle %" TCL_Z_MODIFIER "u bytes",
sizeof(buffer) - 4));
return TCL_ERROR;
}
memcpy(buffer + 1, bytes, numBytes);
buffer[0] = buffer[numBytes + 1] = buffer[numBytes + 2] = buffer[numBytes + 3] = '\xA0';
first = result = Tcl_UtfNext(buffer + 1);
while ((buffer[0] = *p++) != '\0') {
/* Run Tcl_UtfNext with many more possible bytes at src[-1], all should give the same result */
result = Tcl_UtfNext(buffer + 1);
if (first != result) {
Tcl_AppendResult(interp, "Tcl_UtfNext is not supposed to read src[-1]", (char *)NULL);
return TCL_ERROR;
}
}
p = tobetested;
while ((buffer[numBytes + 1] = *p++) != '\0') {
/* Run Tcl_UtfNext with many more possible bytes at src[end], all should give the same result */
result = Tcl_UtfNext(buffer + 1);
if (first != result) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Tcl_UtfNext is not supposed to read src[end]\n"
"Different result when src[end] is %#x", UCHAR(p[-1])));
return TCL_ERROR;
}
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(first - buffer - 1));
return TCL_OK;
}
/*
* Used to check operations of Tcl_UtfPrev.
*
* Usage: testutfprev $bytes $offset
*/
static int
TestUtfPrevCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Size numBytes, offset;
char *bytes;
const char *result;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "bytes ?offset?");
|
| ︙ | ︙ | |||
8049 8050 8051 8052 8053 8054 8055 |
}
result = Tcl_UtfPrev(bytes + offset, bytes);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result - bytes));
return TCL_OK;
}
/*
| < < < < | | | < | | | < < | < < > | | | | < < | | | < < | | < | < < | | | < | < < < < | | | < | | | < | < < < < < < < < < < < < | | | > > | 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 |
}
result = Tcl_UtfPrev(bytes + offset, bytes);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result - bytes));
return TCL_OK;
}
/*
* Used to check correct string-length determining in Tcl_NumUtfChars
*/
static int
TestNumUtfCharsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc > 1) {
Tcl_Size numBytes, len, limit = TCL_INDEX_NONE;
const char *bytes = Tcl_GetStringFromObj(objv[1], &numBytes);
if (objc > 2) {
if (Tcl_GetIntForIndex(interp, objv[2], numBytes, &limit) != TCL_OK) {
return TCL_ERROR;
}
if (limit > numBytes + 1) {
limit = numBytes + 1;
}
}
len = Tcl_NumUtfChars(bytes, limit);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(len));
}
return TCL_OK;
}
/*
* Used to check correct operation of Tcl_GetUniChar
* testgetunichar STRING INDEX
* This differs from just using "string index" in being a direct
* call to Tcl_GetUniChar without any prior range checking.
*/
static int
TestGetUniCharCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter */
int objc, /* Number of arguments */
Tcl_Obj *const objv[]) /* Argument strings */
{
int index;
int c ;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "STRING INDEX");
return TCL_ERROR;
}
Tcl_GetIntFromObj(interp, objv[2], &index);
c = Tcl_GetUniChar(objv[1], index);
Tcl_SetObjResult(interp, Tcl_NewIntObj(c));
return TCL_OK;
}
/*
* Used to check correct operation of Tcl_UtfFindFirst
*/
static int
TestFindFirstCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc > 1) {
int len = -1;
if (objc > 2) {
(void) Tcl_GetIntFromObj(interp, objv[2], &len);
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindFirst(Tcl_GetString(objv[1]), len), -1));
}
return TCL_OK;
}
/*
* Used to check correct operation of Tcl_UtfFindLast
*/
static int
TestFindLastCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
if (objc > 1) {
int len = -1;
if (objc > 2) {
(void) Tcl_GetIntFromObj(interp, objv[2], &len);
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_UtfFindLast(Tcl_GetString(objv[1]), len), -1));
}
return TCL_OK;
}
static int
TestGetIntForIndexCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Size result;
Tcl_WideInt endvalue;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "index endvalue");
return TCL_ERROR;
}
if (Tcl_GetWideIntFromObj(interp, objv[2], &endvalue) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetIntForIndex(interp, objv[1], endvalue, &result) != TCL_OK) {
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(result));
return TCL_OK;
}
#if defined(HAVE_CPUID) && !defined(MAC_OSX_TCL)
/*
*----------------------------------------------------------------------
*
* TestcpuidCmd --
*
* Retrieves CPU ID information.
|
| ︙ | ︙ | |||
8234 8235 8236 8237 8238 8239 8240 |
*
*----------------------------------------------------------------------
*/
static int
TestcpuidCmd(
TCL_UNUSED(void *),
| | | | | | | | | 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 |
*
*----------------------------------------------------------------------
*/
static int
TestcpuidCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const * objv) /* Parameter vector */
{
int status, index, i;
int regs[4];
Tcl_Obj *regsObjs[4];
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "eax");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[1], &index) != TCL_OK) {
return TCL_ERROR;
}
status = TclWinCPUID(index, regs);
if (status != TCL_OK) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("operation not available", -1));
return status;
}
for (i=0 ; i<4 ; ++i) {
regsObjs[i] = Tcl_NewWideIntObj(regs[i]);
}
Tcl_SetObjResult(interp, Tcl_NewListObj(4, regsObjs));
return TCL_OK;
}
#endif
/*
* Used to do basic checks of the TCL_HASH_KEY_SYSTEM_HASH flag
*/
static int
TestHashSystemHashCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const Tcl_HashKeyType hkType = {
TCL_HASH_KEY_TYPE_VERSION, TCL_HASH_KEY_SYSTEM_HASH,
NULL, NULL, NULL, NULL
};
Tcl_HashTable hash;
Tcl_HashEntry *hPtr;
|
| ︙ | ︙ | |||
8347 8348 8349 8350 8351 8352 8353 |
* Used for testing Tcl_GetInt which is no longer used directly by the
* core very much.
*/
static int
TestgetintCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 |
* Used for testing Tcl_GetInt which is no longer used directly by the
* core very much.
*/
static int
TestgetintCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?args?");
return TCL_ERROR;
} else {
int val, total=0;
|
| ︙ | ︙ | |||
8375 8376 8377 8378 8379 8380 8381 |
/*
* Used for determining sizeof(long) at script level.
*/
static int
TestlongsizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 |
/*
* Used for determining sizeof(long) at script level.
*/
static int
TestlongsizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
if (objc > 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sizeof(long)));
|
| ︙ | ︙ | |||
8417 8418 8419 8420 8421 8422 8423 |
return TCL_OK;
}
static int
TestNREUnwind(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | > | | 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 |
return TCL_OK;
}
static int
TestNREUnwind(
TCL_UNUSED(void *),
Tcl_Interp *interp,
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
/*
* Insure that callbacks effectively run at the proper level during the
* unwinding of the NRE stack.
*/
Tcl_NRAddCallback(interp, NREUnwind_callback, INT2PTR(-1), INT2PTR(-1),
INT2PTR(-1), NULL);
return TCL_OK;
}
static int
TestNRELevels(
TCL_UNUSED(void *),
Tcl_Interp *interp,
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
Interp *iPtr = (Interp *) interp;
static Tcl_Size *refDepth = NULL;
Tcl_Size depth;
Tcl_Obj *levels[6];
Tcl_Size i = 0;
|
| ︙ | ︙ | |||
8490 8491 8492 8493 8494 8495 8496 |
*----------------------------------------------------------------------
*/
static int
TestconcatobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 |
*----------------------------------------------------------------------
*/
static int
TestconcatobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *) /*objv*/)
{
Tcl_Obj *list1Ptr, *list2Ptr, *emptyPtr, *concatPtr, *tmpPtr;
int result = TCL_OK;
Tcl_Size len;
Tcl_Obj *objv[3];
|
| ︙ | ︙ | |||
8807 8808 8809 8810 8811 8812 8813 |
return 1;
}
static int
TestparseargsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 |
return 1;
}
static int
TestparseargsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Arguments. */
{
static int foo = 0;
const char *media = NULL, *color = NULL;
Tcl_Size count = objc;
Tcl_Obj **remObjv, *result[5];
const Tcl_ArgvInfo argTable[] = {
{TCL_ARGV_CONSTANT, "-bool", INT2PTR(1), &foo, "booltest", NULL},
|
| ︙ | ︙ | |||
8859 8860 8861 8862 8863 8864 8865 |
Tcl_Command resolvedCmdPtr = NULL;
/*
* Just do something special on a cmd literal "z" in two cases:
* A) when the caller is a proc "x", and the proc is either in "::" or in "::ns2".
* B) the caller's namespace is "ctx1" or "ctx2"
*/
| | | | | > > | 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 |
Tcl_Command resolvedCmdPtr = NULL;
/*
* Just do something special on a cmd literal "z" in two cases:
* A) when the caller is a proc "x", and the proc is either in "::" or in "::ns2".
* B) the caller's namespace is "ctx1" or "ctx2"
*/
if ( (name[0] == 'z') && (name[1] == '\0') ) {
Namespace *ns2NsPtr = (Namespace *) Tcl_FindNamespace(interp, "::ns2", NULL, 0);
if (procPtr != NULL
&& ((procPtr->cmdPtr->nsPtr == iPtr->globalNsPtr)
|| (ns2NsPtr != NULL && procPtr->cmdPtr->nsPtr == ns2NsPtr)
)
) {
/*
* Case A)
*
* - The context, in which this resolver becomes active, is
* determined by the name of the caller proc, which has to be
* named "x".
*
|
| ︙ | ︙ | |||
8886 8887 8888 8889 8890 8891 8892 | * passed-in cmd literal into a cmd "y", which is taken from * the global namespace (for simplicity). */ const char *callingCmdName = Tcl_GetCommandName(interp, (Tcl_Command) procPtr->cmdPtr); | | | 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 |
* passed-in cmd literal into a cmd "y", which is taken from
* the global namespace (for simplicity).
*/
const char *callingCmdName =
Tcl_GetCommandName(interp, (Tcl_Command) procPtr->cmdPtr);
if ( callingCmdName[0] == 'x' && callingCmdName[1] == '\0' ) {
resolvedCmdPtr = Tcl_FindCommand(interp, "y", NULL, TCL_GLOBAL_ONLY);
}
} else if (callerNsPtr != NULL) {
/*
* Case B)
*
* - The context, in which this resolver becomes active, is
|
| ︙ | ︙ | |||
8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 |
CallFrame *parentFramePtr = varFramePtr->callerPtr;
const char *context = parentFramePtr != NULL ? parentFramePtr->nsPtr->name : "(NULL)";
if (strcmp(context, "ctx1") == 0 && (name[0] == 'z') && (name[1] == '\0')) {
resolvedCmdPtr = Tcl_FindCommand(interp, "y", NULL, TCL_GLOBAL_ONLY);
/* fprintf(stderr, "... y ==> %p\n", resolvedCmdPtr);*/
} else if (strcmp(context, "ctx2") == 0 && (name[0] == 'z') && (name[1] == '\0')) {
resolvedCmdPtr = Tcl_FindCommand(interp, "Y", NULL, TCL_GLOBAL_ONLY);
/*fprintf(stderr, "... Y ==> %p\n", resolvedCmdPtr);*/
}
}
if (resolvedCmdPtr != NULL) {
| > | 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 |
CallFrame *parentFramePtr = varFramePtr->callerPtr;
const char *context = parentFramePtr != NULL ? parentFramePtr->nsPtr->name : "(NULL)";
if (strcmp(context, "ctx1") == 0 && (name[0] == 'z') && (name[1] == '\0')) {
resolvedCmdPtr = Tcl_FindCommand(interp, "y", NULL, TCL_GLOBAL_ONLY);
/* fprintf(stderr, "... y ==> %p\n", resolvedCmdPtr);*/
} else if (strcmp(context, "ctx2") == 0 && (name[0] == 'z') && (name[1] == '\0')) {
resolvedCmdPtr = Tcl_FindCommand(interp, "Y", NULL, TCL_GLOBAL_ONLY);
/*fprintf(stderr, "... Y ==> %p\n", resolvedCmdPtr);*/
}
}
if (resolvedCmdPtr != NULL) {
|
| ︙ | ︙ | |||
8944 8945 8946 8947 8948 8949 8950 |
/*
* Don't resolve the variable; use standard rules.
*/
return TCL_CONTINUE;
}
| | | | 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 |
/*
* Don't resolve the variable; use standard rules.
*/
return TCL_CONTINUE;
}
typedef struct MyResolvedVarInfo {
Tcl_ResolvedVarInfo vInfo; /* This must be the first element. */
Tcl_Var var;
Tcl_Obj *nameObj;
} MyResolvedVarInfo;
static inline void
HashVarFree(
Tcl_Var var)
|
| ︙ | ︙ | |||
8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 |
static Tcl_Var
MyCompiledVarFetch(
Tcl_Interp *interp,
Tcl_ResolvedVarInfo *vinfoPtr)
{
MyResolvedVarInfo *resVarInfo = (MyResolvedVarInfo *) vinfoPtr;
Tcl_Var var = resVarInfo->var;
Interp *iPtr = (Interp *) interp;
Tcl_HashEntry *hPtr;
if (var != NULL) {
if (!(((Var *) var)->flags & VAR_DEAD_HASH)) {
/*
* The cached variable is valid, return it.
*/
return var;
}
/*
* The variable is not valid anymore. Clean it up.
*/
HashVarFree(var);
}
hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) &iPtr->globalNsPtr->varTable,
| > | | 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 |
static Tcl_Var
MyCompiledVarFetch(
Tcl_Interp *interp,
Tcl_ResolvedVarInfo *vinfoPtr)
{
MyResolvedVarInfo *resVarInfo = (MyResolvedVarInfo *) vinfoPtr;
Tcl_Var var = resVarInfo->var;
int isNewVar;
Interp *iPtr = (Interp *) interp;
Tcl_HashEntry *hPtr;
if (var != NULL) {
if (!(((Var *) var)->flags & VAR_DEAD_HASH)) {
/*
* The cached variable is valid, return it.
*/
return var;
}
/*
* The variable is not valid anymore. Clean it up.
*/
HashVarFree(var);
}
hPtr = Tcl_CreateHashEntry((Tcl_HashTable *) &iPtr->globalNsPtr->varTable,
resVarInfo->nameObj, &isNewVar);
if (hPtr) {
var = (Tcl_Var) TclVarHashGetValue(hPtr);
} else {
var = NULL;
}
resVarInfo->var = var;
|
| ︙ | ︙ | |||
9047 9048 9049 9050 9051 9052 9053 |
return TCL_CONTINUE;
}
static int
TestInterpResolverCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 |
return TCL_CONTINUE;
}
static int
TestInterpResolverCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const table[] = {
"down", "up", NULL
};
int idx;
#define RESOLVER_KEY "testInterpResolver"
|
| ︙ | ︙ | |||
9085 9086 9087 9088 9089 9090 9091 |
Tcl_AppendResult(interp, "could not remove the resolver scheme",
(char *)NULL);
return TCL_ERROR;
}
}
return TCL_OK;
}
| | | 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 |
Tcl_AppendResult(interp, "could not remove the resolver scheme",
(char *)NULL);
return TCL_ERROR;
}
}
return TCL_OK;
}
/*
*------------------------------------------------------------------------
*
* TestApplyLambdaCmd --
*
* Implements the Tcl command testapplylambda. This tests the apply
* implementation handling of a lambda where the lambda has a list
|
| ︙ | ︙ | |||
9110 9111 9112 9113 9114 9115 9116 |
*
*------------------------------------------------------------------------
*/
int
TestApplyLambdaCmd(
TCL_UNUSED(void*),
Tcl_Interp *interp, /* Current interpreter. */
| | | 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 |
*
*------------------------------------------------------------------------
*/
int
TestApplyLambdaCmd(
TCL_UNUSED(void*),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int), /* objc. */
TCL_UNUSED(Tcl_Obj *const *)) /* objv. */
{
Tcl_Obj *lambdaObjs[2];
Tcl_Obj *evalObjs[2];
Tcl_Obj *lambdaObj;
int result;
|
| ︙ | ︙ | |||
9163 9164 9165 9166 9167 9168 9169 |
evalObjs[1] = lambdaObj; /* lambdaObj already has a ref count so no need for IncrRef */
result = Tcl_EvalObjv(interp, 2, evalObjs, TCL_EVAL_GLOBAL);
Tcl_DecrRefCount(evalObjs[0]);
Tcl_DecrRefCount(lambdaObj);
return result;
}
| | | | | | | | 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 |
evalObjs[1] = lambdaObj; /* lambdaObj already has a ref count so no need for IncrRef */
result = Tcl_EvalObjv(interp, 2, evalObjs, TCL_EVAL_GLOBAL);
Tcl_DecrRefCount(evalObjs[0]);
Tcl_DecrRefCount(lambdaObj);
return result;
}
/*
*----------------------------------------------------------------------
*
* TestLutilCmd --
*
* This procedure implements the "testlequal" command. It is used to
* test compare two lists for equality using the string representation
* of each element. Implemented in C because script level loops are
* too slow for comparing large (GB count) lists.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
TestLutilCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Arguments. */
{
Tcl_Size nL1, nL2;
Tcl_Obj *l1Obj = NULL;
Tcl_Obj *l2Obj = NULL;
Tcl_Obj **l1Elems;
Tcl_Obj **l2Elems;
static const char *const subcmds[] = {
"equal", "diffindex", NULL
};
enum options {
LUTIL_EQUAL, LUTIL_DIFFINDEX
} idx;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "list1 list2");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], subcmds, "option", 0,
|
| ︙ | ︙ | |||
9259 9260 9261 9262 9263 9264 9265 |
Tcl_DecrRefCount(l1Obj);
}
if (l2Obj) {
Tcl_DecrRefCount(l2Obj);
}
return ret;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 |
Tcl_DecrRefCount(l1Obj);
}
if (l2Obj) {
Tcl_DecrRefCount(l2Obj);
}
return ret;
}
#ifdef _WIN32
/*
*----------------------------------------------------------------------
*
* TestHandleCountCmd --
*
|
| ︙ | ︙ | |||
10063 10064 10065 10066 10067 10068 10069 |
*
*----------------------------------------------------------------------
*/
static int
TestHandleCountCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 |
*
*----------------------------------------------------------------------
*/
static int
TestHandleCountCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Arguments. */
{
DWORD count;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
if (GetProcessHandleCount(GetCurrentProcess(), &count)) {
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(count));
return TCL_OK;
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"GetProcessHandleCount failed", -1));
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* TestAppVerifierPresentCmd --
*
* This procedure implements the "testappverifierpresent" command.
* Result is 1 if the process is running under the Application Verifier,
|
| ︙ | ︙ | |||
10101 10102 10103 10104 10105 10106 10107 |
*
*----------------------------------------------------------------------
*/
static int
TestAppVerifierPresentCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | > | | 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 |
*
*----------------------------------------------------------------------
*/
static int
TestAppVerifierPresentCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Arguments. */
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
static const char * const dlls[] = {
"verifier.dll", "vfbasics.dll", "vfcompat.dll", "vfnet.dll", NULL
};
const char *const *dll;
for (dll = dlls; dll; ++dll) {
if (GetModuleHandleA(*dll) != NULL) {
break;
}
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(*dll != NULL));
return TCL_OK;
}
#endif /* _WIN32 */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/
|
Changes to generic/tclTestABSList.c.
|
| < < < < | < < < < < < | > | | < | | < < | < < < | | | > | | > | | > | | | > | > > | | > | > | | | | | | | < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < | < < < < < < | | | | | | | | | | | < < | < < < | | | | | | | | | | | | | | > | > | > | | | | | | | | | | | > | > < | > | | > < < | | | | | | | | | | | | > > | > | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
// Tcl Abstract List test command: "lstring"
#undef BUILD_tcl
#undef STATIC_BUILD
#ifndef USE_TCL_STUBS
# define USE_TCL_STUBS
#endif
#include <string.h>
#include <limits.h>
#include "tclInt.h"
/*
* Forward references
*/
Tcl_Obj *myNewLStringObj(Tcl_WideInt start,
Tcl_WideInt length);
static void freeRep(Tcl_Obj* alObj);
static Tcl_Obj* my_LStringObjSetElem(Tcl_Interp *interp,
Tcl_Obj *listPtr,
Tcl_Size numIndcies,
Tcl_Obj *const indicies[],
Tcl_Obj *valueObj);
static void DupLStringRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
static Tcl_Size my_LStringObjLength(Tcl_Obj *lstringObjPtr);
static int my_LStringObjIndex(Tcl_Interp *interp,
Tcl_Obj *lstringObj,
Tcl_Size index,
Tcl_Obj **charObjPtr);
static int my_LStringObjRange(Tcl_Interp *interp, Tcl_Obj *lstringObj,
Tcl_Size fromIdx, Tcl_Size toIdx,
Tcl_Obj **newObjPtr);
static int my_LStringObjReverse(Tcl_Interp *interp, Tcl_Obj *srcObj,
Tcl_Obj **newObjPtr);
static int my_LStringReplace(Tcl_Interp *interp,
Tcl_Obj *listObj,
Tcl_Size first,
Tcl_Size numToDelete,
Tcl_Size numToInsert,
Tcl_Obj *const insertObjs[]);
static int my_LStringGetElements(Tcl_Interp *interp,
Tcl_Obj *listPtr,
Tcl_Size *objcptr,
Tcl_Obj ***objvptr);
static void lstringFreeElements(Tcl_Obj* lstringObj);
static void UpdateStringOfLString(Tcl_Obj *objPtr);
/*
* Internal Representation of an lstring type value
*/
typedef struct LString {
char *string; // NULL terminated utf-8 string
Tcl_Size strlen; // num bytes in string
Tcl_Size allocated; // num bytes allocated
Tcl_Obj**elements; // elements array, allocated when GetElements is
// called
} LString;
/*
* AbstractList definition of an lstring type
*/
static const Tcl_ObjType lstringTypes[11] = {
{/*0*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*1*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
NULL, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*2*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
NULL, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*3*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
NULL, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*4*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
NULL, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*5*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
NULL, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*6*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
NULL, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*7*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
NULL, /* Replace */
NULL) /* "in" operator */
},
{/*8*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*9*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
},
{/*10*/
"lstring",
freeRep,
DupLStringRep,
UpdateStringOfLString,
NULL,
TCL_OBJTYPE_V2(
my_LStringObjLength, /* Length */
my_LStringObjIndex, /* Index */
my_LStringObjRange, /* Slice */
my_LStringObjReverse, /* Reverse */
my_LStringGetElements, /* GetElements */
my_LStringObjSetElem, /* SetElement */
my_LStringReplace, /* Replace */
NULL) /* "in" operator */
}
};
/*
*----------------------------------------------------------------------
*
* my_LStringObjIndex --
*
* Implements the AbstractList Index function for the lstring type. The
* Index function returns the value at the index position given. Caller
* is resposible for freeing the Obj.
*
* Results:
* TCL_OK on success. Returns a new Obj, with a 0 refcount in the
* supplied charObjPtr location. Call has ownership of the Obj.
*
* Side effects:
* Obj allocated.
*
*----------------------------------------------------------------------
*/
static int
my_LStringObjIndex(
Tcl_Interp *interp,
Tcl_Obj *lstringObj,
Tcl_Size index,
Tcl_Obj **charObjPtr)
{
LString *lstringRepPtr = (LString*)lstringObj->internalRep.twoPtrValue.ptr1;
(void)interp;
if (index < lstringRepPtr->strlen) {
char cchar[2];
cchar[0] = lstringRepPtr->string[index];
cchar[1] = 0;
*charObjPtr = Tcl_NewStringObj(cchar,1);
} else {
*charObjPtr = NULL;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* my_LStringObjLength --
*
* Implements the AbstractList Length function for the lstring type.
* The Length function returns the number of elements in the list.
*
* Results:
* WideInt number of elements in the list.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static Tcl_Size
my_LStringObjLength(Tcl_Obj *lstringObjPtr)
{
LString *lstringRepPtr = (LString *)lstringObjPtr->internalRep.twoPtrValue.ptr1;
return lstringRepPtr->strlen;
}
/*
*----------------------------------------------------------------------
*
* DupLStringRep --
*
* Replicates the internal representation of the src value, and storing
* it in the copy
*
* Results:
* void
*
* Side effects:
* Modifies the rep of the copyObj.
*
*----------------------------------------------------------------------
*/
static void
DupLStringRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)
{
LString *srcLString = (LString*)srcPtr->internalRep.twoPtrValue.ptr1;
LString *copyLString = (LString*)Tcl_Alloc(sizeof(LString));
memcpy(copyLString, srcLString, sizeof(LString));
copyLString->string = (char*)Tcl_Alloc(srcLString->allocated);
strncpy(copyLString->string, srcLString->string, srcLString->strlen);
copyLString->string[srcLString->strlen] = '\0';
copyLString->elements = NULL;
Tcl_ObjInternalRep itr;
itr.twoPtrValue.ptr1 = copyLString;
itr.twoPtrValue.ptr2 = NULL;
Tcl_StoreInternalRep(copyPtr, srcPtr->typePtr, &itr);
return;
}
/*
*----------------------------------------------------------------------
*
* my_LStringObjSetElem --
*
* Replace the element value at the given (nested) index with the
* valueObj provided. If the lstring obj is shared, a new list is
* created conntaining the modifed element.
*
* Results:
* The modifed lstring is returned, either new or original. If the
* index is invalid, NULL is returned, and an error is added to the
* interp, if provided.
*
* Side effects:
* A new obj may be created.
*
*----------------------------------------------------------------------
*/
static Tcl_Obj*
my_LStringObjSetElem(
Tcl_Interp *interp,
Tcl_Obj *lstringObj,
Tcl_Size numIndicies,
Tcl_Obj *const indicies[],
Tcl_Obj *valueObj)
{
LString *lstringRepPtr = (LString*)lstringObj->internalRep.twoPtrValue.ptr1;
Tcl_Size index;
int status;
Tcl_Obj *returnObj;
if (numIndicies > 1) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("Multiple indicies not supported by lstring."));
return NULL;
}
status = Tcl_GetIntForIndex(interp, indicies[0], lstringRepPtr->strlen, &index);
if (status != TCL_OK) {
return NULL;
}
|
| ︙ | ︙ | |||
445 446 447 448 449 450 451 |
return returnObj;
}
/*
*----------------------------------------------------------------------
*
| | | > | < | | > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
return returnObj;
}
/*
*----------------------------------------------------------------------
*
* my_LStringObjRange --
*
* Creates a new Obj with a slice of the src listPtr.
*
* Results:
* A new Obj is assigned to newObjPtr. Returns TCL_OK
*
* Side effects:
* A new Obj is created.
*
*----------------------------------------------------------------------
*/
static int my_LStringObjRange(
Tcl_Interp *interp,
Tcl_Obj *lstringObj,
Tcl_Size fromIdx,
Tcl_Size toIdx,
Tcl_Obj **newObjPtr)
{
Tcl_Obj *rangeObj;
LString *lstringRepPtr = (LString*)lstringObj->internalRep.twoPtrValue.ptr1;
LString *rangeRep;
Tcl_WideInt len = toIdx - fromIdx + 1;
if (lstringRepPtr->strlen < fromIdx ||
lstringRepPtr->strlen < toIdx) {
Tcl_SetObjResult(interp,
Tcl_ObjPrintf("Range out of bounds "));
return TCL_ERROR;
}
if (len <= 0) {
// Return empty value;
*newObjPtr = Tcl_NewObj();
} else {
|
| ︙ | ︙ | |||
505 506 507 508 509 510 511 |
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
| | | > < < < | | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 |
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* my_LStringObjReverse --
*
* Creates a new Obj with the order of the elements in the lstring
* value reversed, where first is last and last is first, etc.
*
* Results:
* A new Obj is assigned to newObjPtr. Returns TCL_OK
*
* Side effects:
* A new Obj is created.
*
*----------------------------------------------------------------------
*/
static int
my_LStringObjReverse(Tcl_Interp *interp, Tcl_Obj *srcObj, Tcl_Obj **newObjPtr)
{
LString *srcRep = (LString*)srcObj->internalRep.twoPtrValue.ptr1;
Tcl_Obj *revObj;
LString *revRep = (LString*)Tcl_Alloc(sizeof(LString));
Tcl_ObjInternalRep itr;
Tcl_Size len;
char *srcp, *dstp, *endp;
|
| ︙ | ︙ | |||
559 560 561 562 563 564 565 |
*newObjPtr = revObj;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
| | > | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
*newObjPtr = revObj;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* my_LStringReplace --
*
* Delete and/or Insert elements in the list, starting at index first.
* See more details in the comments below. This should not be called with
* a Shared Obj.
*
* Results:
* The value of the listObj is modified.
*
* Side effects:
* The string rep is invalidated.
*
*----------------------------------------------------------------------
*/
static int
my_LStringReplace(
Tcl_Interp *interp,
Tcl_Obj *listObj,
Tcl_Size first,
Tcl_Size numToDelete,
Tcl_Size numToInsert,
Tcl_Obj *const insertObjs[])
{
|
| ︙ | ︙ | |||
633 634 635 636 637 638 639 |
// copy 0 to first-1
if (newStr != oldStr) {
strncpy(newStr, oldStr, first);
}
// move front elements to keep
| | | | | > | | < | | > | | | > | | | | | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
// copy 0 to first-1
if (newStr != oldStr) {
strncpy(newStr, oldStr, first);
}
// move front elements to keep
for(x=0, kx=0; x<newLen && kx<first; kx++, x++) {
newStr[x] = oldStr[kx];
}
// Insert new elements into new string
for(x=first, ix=0; ix<numToInsert; x++, ix++) {
char const *svalue = Tcl_GetString(insertObjs[ix]);
newStr[x] = svalue[0];
}
// Move remaining elements
if ((first+numToDelete) < newLen) {
for(/*x,*/ kx=first+numToDelete; (kx <lstringRep->strlen && x<newLen); x++, kx++) {
newStr[x] = oldStr[kx];
}
}
// Terminate new string.
newStr[newLen] = 0;
if (oldStr != newStr) {
Tcl_Free(oldStr);
}
lstringRep->string = newStr;
lstringRep->strlen = newLen;
/* Changes made to value, string rep and elements array no longer valid */
Tcl_InvalidateStringRep(listObj);
lstringFreeElements(listObj);
return TCL_OK;
}
static const Tcl_ObjType *
my_SetAbstractProc(int ptype)
{
const Tcl_ObjType *typePtr = &lstringTypes[0]; /* default value */
if (4 <= ptype && ptype <= 11) {
/* Table has no entries for the slots upto setfromany */
typePtr = &lstringTypes[(ptype-3)];
}
return typePtr;
}
/*
*----------------------------------------------------------------------
*
* my_NewLStringObj --
*
* Creates a new lstring Obj using the string value of objv[0]
*
* Results:
* results
*
* Side effects:
* side effects
*
*----------------------------------------------------------------------
*/
static Tcl_Obj *
my_NewLStringObj(
Tcl_Interp *interp,
int objc,
Tcl_Obj * const objv[])
{
LString *lstringRepPtr;
Tcl_ObjInternalRep itr;
size_t repSize;
Tcl_Obj *lstringPtr;
const char *string;
static const char* procTypeNames[] = {
"FREEREP", "DUPREP", "UPDATESTRING", "SETFROMANY",
"LENGTH", "INDEX", "SLICE", "REVERSE", "GETELEMENTS",
"SETELEMENT", "REPLACE", NULL
};
int i = 0;
int ptype;
const Tcl_ObjType *lstringTypePtr = &lstringTypes[10];
repSize = sizeof(LString);
lstringRepPtr = (LString*)Tcl_Alloc(repSize);
while (i<objc) {
const char *s = Tcl_GetString(objv[i]);
if (strcmp(s, "-not")==0) {
i++;
if (Tcl_GetIndexFromObj(interp, objv[i], procTypeNames, "proctype", 0, &ptype)==TCL_OK) {
lstringTypePtr = my_SetAbstractProc(ptype);
}
} else if (strcmp(s, "--") == 0) {
// End of options
i++;
break;
} else {
break;
|
| ︙ | ︙ | |||
757 758 759 760 761 762 763 |
}
return lstringPtr;
}
/*
*----------------------------------------------------------------------
*
| | | < > | < | | | > < | | | | | | < | | | | | | > < | | | > | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 |
}
return lstringPtr;
}
/*
*----------------------------------------------------------------------
*
* freeElements --
*
* Free the element array
*
*/
static void
lstringFreeElements(Tcl_Obj* lstringObj)
{
LString *lstringRepPtr = (LString*)lstringObj->internalRep.twoPtrValue.ptr1;
if (lstringRepPtr->elements) {
Tcl_Obj **objptr = lstringRepPtr->elements;
while (objptr < &lstringRepPtr->elements[lstringRepPtr->strlen]) {
Tcl_DecrRefCount(*objptr++);
}
Tcl_Free((char*)lstringRepPtr->elements);
lstringRepPtr->elements = NULL;
}
}
/*
*----------------------------------------------------------------------
*
* freeRep --
*
* Free the value storage of the lstring Obj.
*
* Results:
* void
*
* Side effects:
* Memory free'd.
*
*----------------------------------------------------------------------
*/
static void
freeRep(Tcl_Obj* lstringObj)
{
LString *lstringRepPtr = (LString*)lstringObj->internalRep.twoPtrValue.ptr1;
if (lstringRepPtr->string) {
Tcl_Free(lstringRepPtr->string);
}
lstringFreeElements(lstringObj);
Tcl_Free((char*)lstringRepPtr);
lstringObj->internalRep.twoPtrValue.ptr1 = NULL;
}
/*
*----------------------------------------------------------------------
*
* my_LStringGetElements --
*
* Get the elements of the list in an array.
*
* Results:
* objc, objv return values
*
* Side effects:
* A Tcl_Obj is stored for every element of the abstract list
*
*----------------------------------------------------------------------
*/
static int my_LStringGetElements(Tcl_Interp *interp,
Tcl_Obj *lstringObj,
Tcl_Size *objcptr,
Tcl_Obj ***objvptr)
{
LString *lstringRepPtr = (LString*)lstringObj->internalRep.twoPtrValue.ptr1;
Tcl_Obj **objPtr;
char *cptr = lstringRepPtr->string;
(void)interp;
if (lstringRepPtr->strlen == 0) {
*objcptr = 0;
*objvptr = NULL;
return TCL_OK;
}
if (lstringRepPtr->elements == NULL) {
lstringRepPtr->elements = (Tcl_Obj**)Tcl_Alloc(sizeof(Tcl_Obj*) * lstringRepPtr->strlen);
objPtr=lstringRepPtr->elements;
while (objPtr < &lstringRepPtr->elements[lstringRepPtr->strlen]) {
*objPtr = Tcl_NewStringObj(cptr++,1);
Tcl_IncrRefCount(*objPtr++);
}
}
*objvptr = lstringRepPtr->elements;
*objcptr = lstringRepPtr->strlen;
return TCL_OK;
}
/*
** UpdateStringRep
*/
static void
UpdateStringOfLString(Tcl_Obj *objPtr)
{
# define LOCAL_SIZE 64
int localFlags[LOCAL_SIZE], *flagPtr = NULL;
Tcl_ObjType const *typePtr = objPtr->typePtr;
char *p;
int bytesNeeded = 0;
int llen, i;
/*
* Handle empty list case first, so rest of the routine is simpler.
*/
llen = typePtr->lengthProc(objPtr);
if (llen <= 0) {
Tcl_InitStringRep(objPtr, NULL, 0);
|
| ︙ | ︙ | |||
932 933 934 935 936 937 938 |
Tcl_Free(flagPtr);
}
}
/*
*----------------------------------------------------------------------
*
| | > | | | | | | | | | | | | | | | | | | | | | > > > > > > | | > | | < < < < < < < < < | | | | | | < | < | | < | | | < | | | > < | | > > | < | > > > > > > > > > > > > > > > > > > > > > > > | | | > | | | | | > | > | | | | | | | | < < | < | > > | | | | | < < < | > | | < < < < < < < < | 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 |
Tcl_Free(flagPtr);
}
}
/*
*----------------------------------------------------------------------
*
* lLStringObjCmd --
*
* Script level command that creats an lstring Obj value.
*
* Results:
* Returns and lstring Obj value in the interp results.
*
* Side effects:
* Interp results modified.
*
*----------------------------------------------------------------------
*/
static int
lLStringObjCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj * const objv[])
{
Tcl_Obj *lstringObj;
(void)clientData;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "string");
return TCL_ERROR;
}
lstringObj = my_NewLStringObj(interp, objc-1, &objv[1]);
if (lstringObj) {
Tcl_SetObjResult(interp, lstringObj);
return TCL_OK;
}
return TCL_ERROR;
}
/*
** lgen - Derived from TIP 192 - Lazy Lists
** Generate a list using a command provided as argument(s).
** The command computes the value for a given index.
*/
/*
* Internal rep for the Generate Series
*/
typedef struct LgenSeries {
Tcl_Interp *interp; // used to evaluate gen script
Tcl_Size len; // list length
Tcl_Size nargs; // Number of arguments in genFn including "index"
Tcl_Obj *genFnObj; // The preformed command as a list. Index is set in
// the last element (last argument)
} LgenSeries;
/*
* Evaluate the generation function.
* The provided funtion computes the value for a give index
*/
static Tcl_Obj*
lgen(
Tcl_Obj* objPtr,
Tcl_Size index)
{
LgenSeries *lgenSeriesPtr = (LgenSeries*)objPtr->internalRep.twoPtrValue.ptr1;
Tcl_Obj *elemObj = NULL;
Tcl_Interp *intrp = lgenSeriesPtr->interp;
Tcl_Obj *genCmd = lgenSeriesPtr->genFnObj;
Tcl_Size endidx = lgenSeriesPtr->nargs-1;
if (0 <= index && index < lgenSeriesPtr->len) {
Tcl_Obj *indexObj = Tcl_NewWideIntObj(index);
Tcl_ListObjReplace(intrp, genCmd, endidx, 1, 1, &indexObj);
// EVAL DIRECT to avoid interfering with bytecode compile which may be
// active on the stack
int flags = TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT;
int status = Tcl_EvalObjEx(intrp, genCmd, flags);
elemObj = Tcl_GetObjResult(intrp);
if (status != TCL_OK) {
Tcl_SetObjResult(intrp, Tcl_ObjPrintf(
"Error: %s\nwhile executing %s\n",
elemObj ? Tcl_GetString(elemObj) : "NULL", Tcl_GetString(genCmd)));
return NULL;
}
}
return elemObj;
}
/*
* Abstract List Length function
*/
static Tcl_Size
lgenSeriesObjLength(Tcl_Obj *objPtr)
{
LgenSeries *lgenSeriesRepPtr = (LgenSeries *)objPtr->internalRep.twoPtrValue.ptr1;
return lgenSeriesRepPtr->len;
}
/*
* Abstract List Index function
*/
static int
lgenSeriesObjIndex(
Tcl_Interp *interp,
Tcl_Obj *lgenSeriesObjPtr,
Tcl_Size index,
Tcl_Obj **elemPtr)
{
LgenSeries *lgenSeriesRepPtr;
Tcl_Obj *element;
lgenSeriesRepPtr = (LgenSeries*)lgenSeriesObjPtr->internalRep.twoPtrValue.ptr1;
if (index < 0 || index >= lgenSeriesRepPtr->len) {
*elemPtr = NULL;
return TCL_OK;
}
if (lgenSeriesRepPtr->interp == NULL && interp == NULL) {
return TCL_ERROR;
}
lgenSeriesRepPtr->interp = interp;
element = lgen(lgenSeriesObjPtr, index);
if (element) {
*elemPtr = element;
} else {
return TCL_ERROR;
}
return TCL_OK;
}
/*
** UpdateStringRep
*/
static void
UpdateStringOfLgen(Tcl_Obj *objPtr)
{
LgenSeries *lgenSeriesRepPtr;
Tcl_Obj *element;
Tcl_Size i;
Tcl_Size bytlen;
Tcl_Obj *tmpstr = Tcl_NewObj();
lgenSeriesRepPtr = (LgenSeries*)objPtr->internalRep.twoPtrValue.ptr1;
for (i=0, bytlen=0; i<lgenSeriesRepPtr->len; i++) {
element = lgen(objPtr, i);
if (element) {
if (i) {
Tcl_AppendToObj(tmpstr," ",1);
}
Tcl_AppendObjToObj(tmpstr,element);
}
}
char *str = Tcl_GetStringFromObj(tmpstr, &bytlen);
TclOOM(Tcl_InitStringRep(objPtr, str, bytlen), bytlen+1);
Tcl_DecrRefCount(tmpstr);
return;
}
/*
* ObjType Free Internal Rep function
*/
static void
FreeLgenInternalRep(Tcl_Obj *objPtr)
{
LgenSeries *lgenSeries = (LgenSeries*)objPtr->internalRep.twoPtrValue.ptr1;
if (lgenSeries->genFnObj) {
Tcl_DecrRefCount(lgenSeries->genFnObj);
}
lgenSeries->interp = NULL;
Tcl_Free(lgenSeries);
objPtr->internalRep.twoPtrValue.ptr1 = 0;
}
static void DupLgenSeriesRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr);
/*
* Abstract List ObjType definition
*/
static const Tcl_ObjType lgenType = {
"lgenseries",
FreeLgenInternalRep,
DupLgenSeriesRep,
UpdateStringOfLgen,
NULL, /* SetFromAnyProc */
TCL_OBJTYPE_V2(
lgenSeriesObjLength,
lgenSeriesObjIndex,
NULL, /* slice */
NULL, /* reverse */
NULL, /* get elements */
NULL, /* set element */
NULL, /* replace */
NULL) /* "in" operator */
};
/*
* ObjType Duplicate Internal Rep Function
*/
static void
DupLgenSeriesRep(
Tcl_Obj *srcPtr,
Tcl_Obj *copyPtr)
{
LgenSeries *srcLgenSeries = (LgenSeries*)srcPtr->internalRep.twoPtrValue.ptr1;
Tcl_Size repSize = sizeof(LgenSeries);
LgenSeries *copyLgenSeries = (LgenSeries*)Tcl_Alloc(repSize);
copyLgenSeries->interp = srcLgenSeries->interp;
copyLgenSeries->nargs = srcLgenSeries->nargs;
copyLgenSeries->len = srcLgenSeries->len;
copyLgenSeries->genFnObj = Tcl_DuplicateObj(srcLgenSeries->genFnObj);
Tcl_IncrRefCount(copyLgenSeries->genFnObj);
copyPtr->typePtr = &lgenType;
copyPtr->internalRep.twoPtrValue.ptr1 = copyLgenSeries;
copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
return;
}
/*
* Create a new lgen Tcl_Obj
*/
Tcl_Obj *
newLgenObj(
Tcl_Interp *interp,
int objc,
Tcl_Obj * const objv[])
{
Tcl_WideInt length;
LgenSeries *lGenSeriesRepPtr;
Tcl_Size repSize;
Tcl_Obj *lGenSeriesObj;
if (objc < 2) {
return NULL;
}
if (Tcl_GetWideIntFromObj(NULL, objv[0], &length) != TCL_OK
|| length < 0) {
return NULL;
}
lGenSeriesObj = Tcl_NewObj();
repSize = sizeof(LgenSeries);
lGenSeriesRepPtr = (LgenSeries*)Tcl_Alloc(repSize);
lGenSeriesRepPtr->interp = interp; //Tcl_CreateInterp();
lGenSeriesRepPtr->len = length;
// Allocate array of *obj for cmd + index + args
// objv length cmd arg1 arg2 arg3 ...
// argsv 0 1 2 3 ... index
lGenSeriesRepPtr->nargs = objc;
lGenSeriesRepPtr->genFnObj = Tcl_NewListObj(objc-1, objv+1);
// Addd 0 placeholder for index
Tcl_ListObjAppendElement(interp, lGenSeriesRepPtr->genFnObj, Tcl_NewIntObj(0));
Tcl_IncrRefCount(lGenSeriesRepPtr->genFnObj);
lGenSeriesObj->internalRep.twoPtrValue.ptr1 = lGenSeriesRepPtr;
lGenSeriesObj->internalRep.twoPtrValue.ptr2 = NULL;
lGenSeriesObj->typePtr = &lgenType;
if (length > 0) {
Tcl_InvalidateStringRep(lGenSeriesObj);
} else {
Tcl_InitStringRep(lGenSeriesObj, NULL, 0);
}
return lGenSeriesObj;
}
/*
* The [lgen] command
*/
static int
lGenObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj * const objv[])
{
Tcl_Obj *genObj = newLgenObj(interp, objc-1, &objv[1]);
if (genObj) {
Tcl_SetObjResult(interp, genObj);
return TCL_OK;
}
Tcl_WrongNumArgs(interp, 1, objv, "length cmd ?args?");
return TCL_ERROR;
}
/*
* lgen package init
*/
int Lgen_Init(Tcl_Interp *interp) {
if (Tcl_InitStubs(interp, "9.0-", 0) == NULL) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "lgen", lGenObjCmd, NULL, NULL);
Tcl_PkgProvide(interp, "lgen", "1.0");
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ABSListTest_Init --
*
* Provides Abstract List implemenations via new commands
*
* lstring command
* Usage:
* lstring /string/
*
* Description:
* Creates a list where each character in the string is treated as an
* element. The string is kept as a string, not an actual list. Indexing
* is done by char.
*
* lgen command
* Usage:
* lgen /length/ /cmd/ ?args...?
*
* The /cmd/ should take the last argument as the index value, and return
* a value for that element.
*
* Results:
* The commands listed above are added to the interp.
*
* Side effects:
* New commands defined.
*
*----------------------------------------------------------------------
*/
int Tcl_ABSListTest_Init(Tcl_Interp *interp) {
if (Tcl_InitStubs(interp, "9.0-", 0) == NULL) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "lstring", lLStringObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "lgen", lGenObjCmd, NULL, NULL);
Tcl_PkgProvide(interp, "abstractlisttest", "1.0.0");
return TCL_OK;
}
|
Changes to generic/tclTestObj.c.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 | #endif #include "tclStringRep.h" /* * Forward declarations for functions defined later in this file: */ | | < | < | | | | | | | < | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#endif
#include "tclStringRep.h"
/*
* Forward declarations for functions defined later in this file:
*/
static int CheckIfVarUnset(Tcl_Interp *interp, Tcl_Obj **varPtr, Tcl_Size varIndex);
static int GetVariableIndex(Tcl_Interp *interp,
Tcl_Obj *obj, Tcl_Size *indexPtr);
static void SetVarToObj(Tcl_Obj **varPtr, Tcl_Size varIndex, Tcl_Obj *objPtr);
static Tcl_ObjCmdProc TestbignumobjCmd;
static Tcl_ObjCmdProc TestbooleanobjCmd;
static Tcl_ObjCmdProc TestdoubleobjCmd;
static Tcl_ObjCmdProc TestindexobjCmd;
static Tcl_ObjCmdProc TestintobjCmd;
static Tcl_ObjCmdProc TestlistobjCmd;
static Tcl_ObjCmdProc TestobjCmd;
static Tcl_ObjCmdProc TeststringobjCmd;
static Tcl_ObjCmdProc TestbigdataCmd;
#define VARPTR_KEY "TCLOBJTEST_VARPTR"
#define NUMBER_OF_OBJECT_VARS 20
static void
VarPtrDeleteProc(
void *clientData,
|
| ︙ | ︙ | |||
115 116 117 118 119 120 121 |
return TCL_ERROR;
}
Tcl_SetAssocData(interp, VARPTR_KEY, VarPtrDeleteProc, varPtr);
for (i = 0; i < NUMBER_OF_OBJECT_VARS; i++) {
varPtr[i] = NULL;
}
| | | | | | | | | < < | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
return TCL_ERROR;
}
Tcl_SetAssocData(interp, VARPTR_KEY, VarPtrDeleteProc, varPtr);
for (i = 0; i < NUMBER_OF_OBJECT_VARS; i++) {
varPtr[i] = NULL;
}
Tcl_CreateObjCommand(interp, "testbignumobj", TestbignumobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testbooleanobj", TestbooleanobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testdoubleobj", TestdoubleobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testintobj", TestintobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testindexobj", TestindexobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testlistobj", TestlistobjCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testobj", TestobjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "teststringobj", TeststringobjCmd,
NULL, NULL);
if (sizeof(Tcl_Size) == sizeof(Tcl_WideInt)) {
Tcl_CreateObjCommand(interp, "testbigdata", TestbigdataCmd,
NULL, NULL);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
161 162 163 164 165 166 167 |
*----------------------------------------------------------------------
*/
static int
TestbignumobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
| | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
*----------------------------------------------------------------------
*/
static int
TestbignumobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Argument count */
Tcl_Obj *const objv[]) /* Argument vector */
{
static const char *const subcmds[] = {
"set", "get", "mult10", "div10", "iseven", "radixsize", NULL
};
enum options {
BIGNUM_SET, BIGNUM_GET, BIGNUM_MULT10, BIGNUM_DIV10, BIGNUM_ISEVEN,
BIGNUM_RADIXSIZE
|
| ︙ | ︙ | |||
198 199 200 201 202 203 204 |
case BIGNUM_SET:
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "var value");
return TCL_ERROR;
}
string = Tcl_GetString(objv[3]);
if (mp_init(&bignumValue) != MP_OKAY) {
| | | | | | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
case BIGNUM_SET:
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "var value");
return TCL_ERROR;
}
string = Tcl_GetString(objv[3]);
if (mp_init(&bignumValue) != MP_OKAY) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("error in mp_init", -1));
return TCL_ERROR;
}
if (mp_read_radix(&bignumValue, string, 10) != MP_OKAY) {
mp_clear(&bignumValue);
Tcl_SetObjResult(interp,
Tcl_NewStringObj("error in mp_read_radix", -1));
return TCL_ERROR;
}
/*
* If the object currently bound to the variable with index varIndex
* has ref count 1 (i.e. the object is unshared) we can modify that
* object directly. Otherwise, if RC>1 (i.e. the object is shared),
|
| ︙ | ︙ | |||
248 249 250 251 252 253 254 |
}
if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
&bignumValue) != TCL_OK) {
return TCL_ERROR;
}
if (mp_mul_d(&bignumValue, 10, &bignumValue) != MP_OKAY) {
mp_clear(&bignumValue);
| | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
}
if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
&bignumValue) != TCL_OK) {
return TCL_ERROR;
}
if (mp_mul_d(&bignumValue, 10, &bignumValue) != MP_OKAY) {
mp_clear(&bignumValue);
Tcl_SetObjResult(interp,
Tcl_NewStringObj("error in mp_mul_d", -1));
return TCL_ERROR;
}
if (!Tcl_IsShared(varPtr[varIndex])) {
Tcl_SetBignumObj(varPtr[varIndex], &bignumValue);
} else {
SetVarToObj(varPtr, varIndex, Tcl_NewBignumObj(&bignumValue));
}
|
| ︙ | ︙ | |||
273 274 275 276 277 278 279 |
}
if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
&bignumValue) != TCL_OK) {
return TCL_ERROR;
}
if (mp_div_d(&bignumValue, 10, &bignumValue, NULL) != MP_OKAY) {
mp_clear(&bignumValue);
| | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
}
if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
&bignumValue) != TCL_OK) {
return TCL_ERROR;
}
if (mp_div_d(&bignumValue, 10, &bignumValue, NULL) != MP_OKAY) {
mp_clear(&bignumValue);
Tcl_SetObjResult(interp,
Tcl_NewStringObj("error in mp_div_d", -1));
return TCL_ERROR;
}
if (!Tcl_IsShared(varPtr[varIndex])) {
Tcl_SetBignumObj(varPtr[varIndex], &bignumValue);
} else {
SetVarToObj(varPtr, varIndex, Tcl_NewBignumObj(&bignumValue));
}
|
| ︙ | ︙ | |||
298 299 300 301 302 303 304 |
}
if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
&bignumValue) != TCL_OK) {
return TCL_ERROR;
}
if (mp_mod_2d(&bignumValue, 1, &bignumValue) != MP_OKAY) {
mp_clear(&bignumValue);
| | | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
}
if (Tcl_GetBignumFromObj(interp, varPtr[varIndex],
&bignumValue) != TCL_OK) {
return TCL_ERROR;
}
if (mp_mod_2d(&bignumValue, 1, &bignumValue) != MP_OKAY) {
mp_clear(&bignumValue);
Tcl_SetObjResult(interp,
Tcl_NewStringObj("error in mp_mod_2d", -1));
return TCL_ERROR;
}
if (!Tcl_IsShared(varPtr[varIndex])) {
Tcl_SetBooleanObj(varPtr[varIndex], mp_iszero(&bignumValue));
} else {
SetVarToObj(varPtr, varIndex, Tcl_NewBooleanObj(mp_iszero(&bignumValue)));
}
|
| ︙ | ︙ | |||
360 361 362 363 364 365 366 |
*----------------------------------------------------------------------
*/
static int
TestbooleanobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
*----------------------------------------------------------------------
*/
static int
TestbooleanobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size varIndex;
int boolValue;
const char *subCmd;
Tcl_Obj **varPtr;
if (objc < 3) {
wrongNumArgs:
Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
460 461 462 463 464 465 466 |
*----------------------------------------------------------------------
*/
static int
TestdoubleobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
*----------------------------------------------------------------------
*/
static int
TestdoubleobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size varIndex;
double doubleValue;
const char *subCmd;
Tcl_Obj **varPtr;
if (objc < 3) {
|
| ︙ | ︙ | |||
576 577 578 579 580 581 582 |
*----------------------------------------------------------------------
*/
static int
TestindexobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | < < | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
*----------------------------------------------------------------------
*/
static int
TestindexobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int allowAbbrev, index, setError, i, result;
Tcl_Size index2;
const char **argv;
static const char *const tablePtr[] = {"a", "b", "check", NULL};
/*
* Keep this structure declaration in sync with tclIndexObj.c
*/
struct IndexRep {
void *tablePtr; /* Pointer to the table of strings. */
Tcl_Size offset; /* Offset between table entries. */
Tcl_Size index; /* Selected index into table. */
} *indexRep;
if ((objc == 3) && (strcmp(Tcl_GetString(objv[1]),
"check") == 0)) {
/*
* This code checks to be sure that the results of Tcl_GetIndexFromObj
|
| ︙ | ︙ | |||
668 669 670 671 672 673 674 |
*----------------------------------------------------------------------
*/
static int
TestintobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
*----------------------------------------------------------------------
*/
static int
TestintobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size varIndex;
#if (INT_MAX != LONG_MAX) /* int is not the same size as long */
int i;
#endif
Tcl_WideInt wideValue;
const char *subCmd;
|
| ︙ | ︙ | |||
854 855 856 857 858 859 860 | * * TestlistobjCmd -- * * This function implements the 'testlistobj' command. It is used to * test a few possible corner cases in list object manipulation from * C code that cannot occur at the Tcl level. * | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 |
*
* TestlistobjCmd --
*
* This function implements the 'testlistobj' command. It is used to
* test a few possible corner cases in list object manipulation from
* C code that cannot occur at the Tcl level.
*
* Following new commands are added for 9.0 as regression tests for
* memory leaks and use-after-free. Unlike 8.6, 9.0 has multiple internal
* representations for lists. It has to be ensured that corresponding
* implementations obey the invariants of the C list API. The script
* level tests do not suffice as Tcl list commands do not execute
* the same exact code path as the exported C API.
*
* Note these new commands are only useful when Tcl is compiled with
* TCL_MEM_DEBUG defined.
*
* indexmemcheck - loops calling Tcl_ListObjIndex on each element. This
* is to test that abstract lists returning elements do not depend
* on caller to free them. The test case should check allocated counts
* with the following sequence:
* set before <get memory counts>
* testobj set VARINDEX [list a b c] (or lseq etc.)
* testlistobj indexnoop VARINDEX
* testobj unset VARINDEX
* set after <get memory counts>
* after calling this command AND freeing the passed list. The targeted
* bug is if Tcl_LOI returns a ephemeral Tcl_Obj with no other reference
* resulting in a memory leak. Conversely, the command also checks
* that the Tcl_Obj returned by Tcl_LOI does not have a zero reference
* count since it is supposed to have at least one reference held
* by the list implementation. Returns a message in interp otherwise.
*
* getelementsmemcheck - as above but for Tcl_ListObjGetElements
*
* Results:
* A standard Tcl object result.
*
* Side effects:
* Creates, manipulates and frees list objects.
*
*-----------------------------------------------------------------------------
*/
static int
TestlistobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Tcl interpreter */
int objc, /* Number of arguments */
Tcl_Obj *const objv[]) /* Argument objects */
{
/* Subcommands supported by this command */
static const char* const subcommands[] = {
"set",
"get",
"replace",
"indexmemcheck",
"getelementsmemcheck",
"index",
NULL
};
enum listobjCmdIndex {
LISTOBJ_SET,
LISTOBJ_GET,
LISTOBJ_REPLACE,
LISTOBJ_INDEXMEMCHECK,
LISTOBJ_GETELEMENTSMEMCHECK,
LISTOBJ_INDEX,
} cmdIndex;
Tcl_Size varIndex; /* Variable number converted to binary */
Tcl_Size first; /* First index in the list */
Tcl_Size count; /* Count of elements in a list */
Tcl_Obj **varPtr;
Tcl_Size i, len;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg...?");
return TCL_ERROR;
}
varPtr = GetVarPtr(interp);
if (GetVariableIndex(interp, objv[2], &varIndex) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "command",
0, &cmdIndex) != TCL_OK) {
return TCL_ERROR;
}
switch(cmdIndex) {
case LISTOBJ_SET:
if ((varPtr[varIndex] != NULL) && !Tcl_IsShared(varPtr[varIndex])) {
Tcl_SetListObj(varPtr[varIndex], objc-3, objv+3);
} else {
|
| ︙ | ︙ | |||
963 964 965 966 967 968 969 |
case LISTOBJ_REPLACE:
if (objc < 5) {
Tcl_WrongNumArgs(interp, 2, objv,
"varIndex start count ?element...?");
return TCL_ERROR;
}
if (Tcl_GetIntForIndex(interp, objv[3], TCL_INDEX_NONE, &first) != TCL_OK
| | | 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
case LISTOBJ_REPLACE:
if (objc < 5) {
Tcl_WrongNumArgs(interp, 2, objv,
"varIndex start count ?element...?");
return TCL_ERROR;
}
if (Tcl_GetIntForIndex(interp, objv[3], TCL_INDEX_NONE, &first) != TCL_OK
|| Tcl_GetIntForIndex(interp, objv[4], TCL_INDEX_NONE, &count) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_IsShared(varPtr[varIndex])) {
SetVarToObj(varPtr, varIndex, Tcl_DuplicateObj(varPtr[varIndex]));
}
Tcl_ResetResult(interp);
return Tcl_ListObjReplace(interp, varPtr[varIndex], first, count,
|
| ︙ | ︙ | |||
987 988 989 990 991 992 993 |
}
if (Tcl_ListObjLength(interp, varPtr[varIndex], &len) != TCL_OK) {
return TCL_ERROR;
}
for (i = 0; i < len; ++i) {
Tcl_Obj *objP;
if (Tcl_ListObjIndex(interp, varPtr[varIndex], i, &objP)
| | | 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 |
}
if (Tcl_ListObjLength(interp, varPtr[varIndex], &len) != TCL_OK) {
return TCL_ERROR;
}
for (i = 0; i < len; ++i) {
Tcl_Obj *objP;
if (Tcl_ListObjIndex(interp, varPtr[varIndex], i, &objP)
!= TCL_OK) {
return TCL_ERROR;
}
if (objP->refCount < 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"Tcl_ListObjIndex returned object with ref count < 0",
TCL_INDEX_NONE));
/* Keep looping since we are also looping for leaks */
|
| ︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 |
return TCL_ERROR;
}
if (CheckIfVarUnset(interp, varPtr, varIndex)) {
return TCL_ERROR;
} else {
Tcl_Obj **elems;
if (Tcl_ListObjGetElements(interp, varPtr[varIndex], &len, &elems)
| | | 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
return TCL_ERROR;
}
if (CheckIfVarUnset(interp, varPtr, varIndex)) {
return TCL_ERROR;
} else {
Tcl_Obj **elems;
if (Tcl_ListObjGetElements(interp, varPtr[varIndex], &len, &elems)
!= TCL_OK) {
return TCL_ERROR;
}
for (i = 0; i < len; ++i) {
if (elems[i]->refCount <= 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"Tcl_ListObjGetElements element has ref count <= 0",
TCL_INDEX_NONE));
|
| ︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 | * * Side effects: * Creates and frees objects. * *---------------------------------------------------------------------- */ | | < < < < | | | | | | | | | > | > | | | | | | | > | | < < | > | | 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 |
*
* Side effects:
* Creates and frees objects.
*
*----------------------------------------------------------------------
*/
static Tcl_Size V1TestListObjLength(TCL_UNUSED(Tcl_Obj *)) {
return 100;
}
static int V1TestListObjIndex(
TCL_UNUSED(Tcl_Interp *),
TCL_UNUSED(Tcl_Obj *),
TCL_UNUSED(Tcl_Size),
Tcl_Obj **objPtr)
{
*objPtr = Tcl_NewStringObj("This indexProc should never be accessed (bug: e58d7e19e9)", -1);
return TCL_OK;
}
static const Tcl_ObjType v1TestListType = {
"testlist", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL, /* setFromAnyProc */
offsetof(Tcl_ObjType, indexProc), /* This is a V1 objType, which doesn't have an indexProc */
V1TestListObjLength, /* always return 100, doesn't really matter */
V1TestListObjIndex, /* should never be accessed, because this objType = V1*/
NULL, NULL, NULL, NULL, NULL, NULL
};
static
void
HugeUpdateString(
TCL_UNUSED(Tcl_Obj *))
{
/* Always returns NULL, as an indication that
* room for its string representation cannot be allocated */
return;
}
static const Tcl_ObjType hugeType = {
"huge", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
HugeUpdateString, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
static int
TestobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size varIndex, destIndex;
int i;
const Tcl_ObjType *targetType;
Tcl_Obj **varPtr;
static const char *const subcommands[] = {
"freeallvars", "bug3598580", "buge58d7e19e9",
"types", "objtype", "newobj", "set",
"assign", "convert", "duplicate", "huge",
"invalidateStringRep", "refcount", "type",
NULL
};
enum testobjCmdIndex {
TESTOBJ_FREEALLVARS, TESTOBJ_BUG3598580, TESTOBJ_BUGE58D7E19E9,
TESTOBJ_TYPES, TESTOBJ_OBJTYPE, TESTOBJ_NEWOBJ, TESTOBJ_SET,
TESTOBJ_ASSIGN, TESTOBJ_CONVERT, TESTOBJ_DUPLICATE, TESTOBJ_HUGE,
TESTOBJ_INVALIDATESTRINGREP, TESTOBJ_REFCOUNT, TESTOBJ_TYPE,
} cmdIndex;
if (objc < 2) {
wrongNumArgs:
Tcl_WrongNumArgs(interp, 1, objv, "option arg ?arg ...?");
return TCL_ERROR;
}
varPtr = GetVarPtr(interp);
if (Tcl_GetIndexFromObj(
interp, objv[1], subcommands, "command", 0, &cmdIndex)
!= TCL_OK) {
return TCL_ERROR;
}
switch (cmdIndex) {
case TESTOBJ_FREEALLVARS:
if (objc != 2) {
goto wrongNumArgs;
}
|
| ︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 |
} else {
const char *typeName;
if (objv[2]->typePtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1));
} else {
typeName = objv[2]->typePtr->name;
| | | 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 |
} else {
const char *typeName;
if (objv[2]->typePtr == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("none", -1));
} else {
typeName = objv[2]->typePtr->name;
Tcl_SetObjResult(interp, Tcl_NewStringObj(typeName, -1));
}
}
return TCL_OK;
case TESTOBJ_NEWOBJ:
if (objc != 3) {
goto wrongNumArgs;
}
|
| ︙ | ︙ | |||
1230 1231 1232 1233 1234 1235 1236 |
goto wrongNumArgs;
}
if (GetVariableIndex(interp, objv[2], &varIndex) != TCL_OK) {
return TCL_ERROR;
}
SetVarToObj(varPtr, varIndex, objv[3]);
return TCL_OK;
| | | | < < | < < < < < | 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 |
goto wrongNumArgs;
}
if (GetVariableIndex(interp, objv[2], &varIndex) != TCL_OK) {
return TCL_ERROR;
}
SetVarToObj(varPtr, varIndex, objv[3]);
return TCL_OK;
case TESTOBJ_HUGE: {
if (objc != 2) {
goto wrongNumArgs;
}
Tcl_Obj *hugeObjPtr = Tcl_NewObj();
hugeObjPtr->typePtr = &hugeType;
hugeObjPtr->length = INT_MAX - 1;
hugeObjPtr->bytes = NULL;
Tcl_SetObjResult(interp, hugeObjPtr);
}
return TCL_OK;
|
| ︙ | ︙ | |||
1353 1354 1355 1356 1357 1358 1359 |
*----------------------------------------------------------------------
*/
static int
TeststringobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 |
*----------------------------------------------------------------------
*/
static int
TeststringobjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_UniChar *unicode;
Tcl_Size size, varIndex;
int option, i;
Tcl_Size length;
#define MAX_STRINGS 11
const char *string, *strings[MAX_STRINGS+1];
String *strPtr;
Tcl_Obj **varPtr;
static const char *const options[] = {
"append", "appendstrings", "get", "get2", "length", "length2",
|
| ︙ | ︙ | |||
1529 1530 1531 1532 1533 1534 1535 |
strPtr = (String *)varPtr[varIndex]->internalRep.twoPtrValue.ptr1;
length = strPtr->maxChars;
} else {
length = TCL_INDEX_NONE;
}
Tcl_SetWideIntObj(Tcl_GetObjResult(interp), length);
break;
| | | 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 |
strPtr = (String *)varPtr[varIndex]->internalRep.twoPtrValue.ptr1;
length = strPtr->maxChars;
} else {
length = TCL_INDEX_NONE;
}
Tcl_SetWideIntObj(Tcl_GetObjResult(interp), length);
break;
case 10: { /* range */
Tcl_Size first, last;
if (objc != 5) {
goto wrongNumArgs;
}
if ((Tcl_GetIntForIndex(interp, objv[3], TCL_INDEX_NONE, &first) != TCL_OK)
|| (Tcl_GetIntForIndex(interp, objv[4], TCL_INDEX_NONE, &last) != TCL_OK)) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 | "index value out of range", -1)); return TCL_ERROR; } Tcl_AppendUnicodeToObj(varPtr[varIndex], unicode + length, size - length); Tcl_SetObjResult(interp, varPtr[varIndex]); break; | | | 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 |
"index value out of range", -1));
return TCL_ERROR;
}
Tcl_AppendUnicodeToObj(varPtr[varIndex], unicode + length, size - length);
Tcl_SetObjResult(interp, varPtr[varIndex]);
break;
case 13: /* newunicode*/
unicode = (Tcl_UniChar *)Tcl_Alloc((objc - 3) * sizeof(Tcl_UniChar));
for (i = 0; i < (objc - 3); ++i) {
int val;
if (Tcl_GetIntFromObj(interp, objv[i + 3], &val) != TCL_OK) {
break;
}
unicode[i] = (Tcl_UniChar)val;
|
| ︙ | ︙ | |||
1630 1631 1632 1633 1634 1635 1636 | } /* *------------------------------------------------------------------------ * * TestbigdataCmd -- * | | | | | | | | | | | | | | | | | 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 |
}
/*
*------------------------------------------------------------------------
*
* TestbigdataCmd --
*
* Implements the Tcl command testbigdata
* testbigdata string ?LEN? ?SPLIT? - returns 01234567890123...
* testbigdata bytearray ?LEN? ?SPLIT? - returns {0 1 2 3 4 5 6 7 8 9 0 1 ...}
* testbigdata dict ?SIZE? - returns dict mapping integers to themselves
* If no arguments given, returns the pattern used to generate strings.
* If SPLIT is specified, the character at that position is set to "X".
*
* Results:
* TCL_OK - Success.
* TCL_ERROR - Error.
*
* Side effects:
* Interpreter result holds result or error message.
*
*------------------------------------------------------------------------
*/
static int
TestbigdataCmd (
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const subcmds[] = {
"string", "bytearray", "list", "dict", NULL
};
enum options {
BIGDATA_STRING, BIGDATA_BYTEARRAY, BIGDATA_LIST, BIGDATA_DICT
} idx;
char *s;
unsigned char *p;
Tcl_Size i, len, split;
Tcl_DString ds;
Tcl_Obj *objPtr;
#define PATTERN_LEN 10
|
| ︙ | ︙ | |||
1706 1707 1708 1709 1710 1711 1712 |
switch (idx) {
case BIGDATA_STRING:
Tcl_DStringInit(&ds);
Tcl_DStringSetLength(&ds, len);/* Also stores \0 at index len+1 */
s = Tcl_DStringValue(&ds);
for (i = 0; i < len; ++i) {
| | | | | | 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 |
switch (idx) {
case BIGDATA_STRING:
Tcl_DStringInit(&ds);
Tcl_DStringSetLength(&ds, len);/* Also stores \0 at index len+1 */
s = Tcl_DStringValue(&ds);
for (i = 0; i < len; ++i) {
s[i] = '0' + (i % PATTERN_LEN);
}
if (split >= 0) {
assert(split < len);
s[split] = 'X';
}
Tcl_DStringResult(interp, &ds);
break;
case BIGDATA_BYTEARRAY:
objPtr = Tcl_NewByteArrayObj(NULL, len);
p = Tcl_GetByteArrayFromObj(objPtr, &len);
for (i = 0; i < len; ++i) {
p[i] = '0' + (i % PATTERN_LEN);
}
if (split >= 0) {
assert(split < len);
p[split] = 'X';
}
Tcl_SetObjResult(interp, objPtr);
break;
case BIGDATA_LIST:
for (i = 0; i < PATTERN_LEN; ++i) {
patternObjs[i] = Tcl_NewIntObj(i);
Tcl_IncrRefCount(patternObjs[i]);
}
objPtr = Tcl_NewListObj(len, NULL);
for (i = 0; i < len; ++i) {
Tcl_ListObjAppendElement(
interp, objPtr, patternObjs[i % PATTERN_LEN]);
}
if (split >= 0) {
assert(split < len);
Tcl_Obj *splitMarker = Tcl_NewStringObj("X", 1);
Tcl_ListObjReplace(interp, objPtr, split, 1, 1, &splitMarker);
}
for (i = 0; i < PATTERN_LEN; ++i) {
|
| ︙ | ︙ | |||
1758 1759 1760 1761 1762 1763 1764 |
Tcl_DictObjPut(interp, objPtr, objPtr2, objPtr2);
}
Tcl_SetObjResult(interp, objPtr);
break;
}
return TCL_OK;
}
| | | | | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 |
Tcl_DictObjPut(interp, objPtr, objPtr2, objPtr2);
}
Tcl_SetObjResult(interp, objPtr);
break;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* SetVarToObj --
*
* Utility routine to assign a Tcl_Obj* to a test variable. The
* Tcl_Obj* can be NULL.
*
* Results:
* None.
*
* Side effects:
* This routine handles ref counting details for assignment: i.e. the old
* value's ref count must be decremented (if not NULL) and the new one
|
| ︙ | ︙ | |||
1850 1851 1852 1853 1854 1855 1856 | * Side effects: * Sets the interpreter result to an error message if the variable is * unset (NULL). * *---------------------------------------------------------------------- */ | | < < < < < < < < < < < < < < < < < < < < < < < < | 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 |
* Side effects:
* Sets the interpreter result to an error message if the variable is
* unset (NULL).
*
*----------------------------------------------------------------------
*/
static int
CheckIfVarUnset(
Tcl_Interp *interp, /* Interpreter for error reporting. */
Tcl_Obj ** varPtr,
Tcl_Size varIndex) /* Index of the test variable to check. */
{
if (varIndex < 0 || varPtr[varIndex] == NULL) {
char buf[32 + TCL_INTEGER_SPACE];
snprintf(buf, sizeof(buf), "variable %" TCL_SIZE_MODIFIER "d is unset (NULL)", varIndex);
Tcl_ResetResult(interp);
Tcl_AppendToObj(Tcl_GetObjResult(interp), buf, -1);
return 1;
}
return 0;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclTestProcBodyObj.c.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
/*
* this struct describes an entry in the table of command names and command
* procs
*/
typedef struct {
| | | | | | | | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
/*
* this struct describes an entry in the table of command names and command
* procs
*/
typedef struct {
const char *cmdName; /* command name */
Tcl_ObjCmdProc *proc; /* command proc */
int exportIt; /* if 1, export the command */
} CmdTable;
/*
* Declarations for functions defined in this file.
*/
static Tcl_ObjCmdProc ProcBodyTestProcCmd;
static Tcl_ObjCmdProc ProcBodyTestCheckCmd;
static int ProcBodyTestInitInternal(Tcl_Interp *interp, int isSafe);
static int RegisterCommand(Tcl_Interp* interp,
const char *namesp, const CmdTable *cmdTablePtr);
/*
* List of commands to create when the package is loaded; must go after the
* declarations of the enable command procedure.
*/
static const CmdTable commands[] = {
{ procCommand, ProcBodyTestProcCmd, 1 },
{ checkCommand, ProcBodyTestCheckCmd, 1 },
{ 0, 0, 0 }
};
static const CmdTable safeCommands[] = {
{ procCommand, ProcBodyTestProcCmd, 1 },
{ checkCommand, ProcBodyTestCheckCmd, 1 },
{ 0, 0, 0 }
};
/*
*----------------------------------------------------------------------
*
* Procbodytest_Init --
|
| ︙ | ︙ | |||
133 134 135 136 137 138 139 | * None. * *---------------------------------------------------------------------- */ static int RegisterCommand( | | | | | | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
* None.
*
*----------------------------------------------------------------------
*/
static int
RegisterCommand(
Tcl_Interp* interp, /* the Tcl interpreter for which the operation
* is performed */
const char *namesp, /* the namespace in which the command is
* registered */
const CmdTable *cmdTablePtr)/* the command to register */
{
char buf[128];
if (cmdTablePtr->exportIt) {
snprintf(buf, sizeof(buf), "namespace eval %s { namespace export %s }",
namesp, cmdTablePtr->cmdName);
if (Tcl_EvalEx(interp, buf, TCL_INDEX_NONE, 0) != TCL_OK) {
return TCL_ERROR;
}
}
snprintf(buf, sizeof(buf), "%s::%s", namesp, cmdTablePtr->cmdName);
Tcl_CreateObjCommand(interp, buf, cmdTablePtr->proc, 0, 0);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ProcBodyTestInitInternal --
*
* This function initializes the Loader package.
* The isSafe flag is 1 if the interpreter is safe, 0 otherwise.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
ProcBodyTestInitInternal(
Tcl_Interp *interp, /* the Tcl interpreter for which the package
|
| ︙ | ︙ | |||
192 193 194 195 196 197 198 |
return Tcl_PkgProvideEx(interp, packageName, packageVersion, NULL);
}
/*
*----------------------------------------------------------------------
*
| | | | | | | < | | | | | | | | | | | | | | > | | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
return Tcl_PkgProvideEx(interp, packageName, packageVersion, NULL);
}
/*
*----------------------------------------------------------------------
*
* ProcBodyTestProcCmd --
*
* Implements the "procbodytest::proc" command. Here is the command
* description:
* procbodytest::proc newName argList bodyName
* Looks up a procedure called $bodyName and, if the procedure exists,
* constructs a Tcl_Obj of type "procbody" and calls Tcl_ProcObjCmd.
* Arguments:
* newName the name of the procedure to be created
* argList the argument list for the procedure
* bodyName the name of an existing procedure from which the
* body is to be copied.
* This command can be used to trigger the branches in Tcl_ProcObjCmd that
* construct a proc from a "procbody", for example:
* proc a {x} {return $x}
* a 123
* procbodytest::proc b {x} a
* Note the call to "a 123", which is necessary so that the Proc pointer
* for "a" is filled in by the internal compiler; this is a hack.
*
* Results:
* Returns a standard Tcl code.
*
* Side effects:
* A new procedure is created.
* Leaves an error message in the interp's result on error.
*
*----------------------------------------------------------------------
*/
static int
ProcBodyTestProcCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* the current interpreter */
int objc, /* argument count */
Tcl_Obj *const objv[]) /* arguments */
{
const char *fullName;
Tcl_Command procCmd;
Command *cmdPtr;
Proc *procPtr = NULL;
Tcl_Obj *bodyObjPtr;
Tcl_Obj *myobjv[5];
|
| ︙ | ︙ | |||
259 260 261 262 263 264 265 |
cmdPtr = (Command *) procCmd;
/*
* check that this is a procedure and not a builtin command:
* If a procedure, cmdPtr->objClientData is TclIsProc(cmdPtr).
*/
| | | | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
cmdPtr = (Command *) procCmd;
/*
* check that this is a procedure and not a builtin command:
* If a procedure, cmdPtr->objClientData is TclIsProc(cmdPtr).
*/
if (cmdPtr->objClientData != TclIsProc(cmdPtr)) {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"command \"", fullName, "\" is not a Tcl procedure", (char *)NULL);
return TCL_ERROR;
}
/*
* it is a Tcl procedure: the client data is the Proc structure
*/
procPtr = (Proc *) cmdPtr->objClientData;
if (procPtr == NULL) {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "procedure \"",
fullName, "\" does not have a Proc struct!", (char *)NULL);
return TCL_ERROR;
}
/*
|
| ︙ | ︙ | |||
304 305 306 307 308 309 310 |
return result;
}
/*
*----------------------------------------------------------------------
*
| | | | | | | | | | | | | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
return result;
}
/*
*----------------------------------------------------------------------
*
* ProcBodyTestCheckCmd --
*
* Implements the "procbodytest::check" command. Here is the command
* description:
* procbodytest::check
*
* Performs an internal check that the Tcl_PkgPresent() command returns
* the same version number as was registered when the tcl::procbodytest package
* was provided. Places a boolean in the interp result indicating the
* test outcome.
*
* Results:
* Returns a standard Tcl code.
*
*----------------------------------------------------------------------
*/
static int
ProcBodyTestCheckCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* the current interpreter */
int objc, /* argument count */
Tcl_Obj *const objv[]) /* arguments */
{
const char *version;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
|
| ︙ | ︙ |
Changes to generic/tclThread.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 |
* used for these objects so they can be finalized.
*
* These statics are guarded by the mutex in the caller of
* TclRememberThreadData, e.g., TclpThreadDataKeyInit
*/
typedef struct {
| | | | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
* used for these objects so they can be finalized.
*
* These statics are guarded by the mutex in the caller of
* TclRememberThreadData, e.g., TclpThreadDataKeyInit
*/
typedef struct {
int num; /* Number of objects remembered */
int max; /* Max size of the array */
void **list; /* List of pointers */
} SyncObjRecord;
static SyncObjRecord keyRecord = {0, 0, NULL};
static SyncObjRecord mutexRecord = {0, 0, NULL};
static SyncObjRecord condRecord = {0, 0, NULL};
/*
* Prototypes of functions used only in this file.
*/
static void ForgetSyncObject(void *objPtr, SyncObjRecord *recPtr);
static void RememberSyncObject(void *objPtr,
SyncObjRecord *recPtr);
/*
*----------------------------------------------------------------------
*
* Tcl_GetThreadData --
*
* This function allocates and initializes a chunk of thread local
* storage.
|
| ︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
*
*----------------------------------------------------------------------
*/
void *
TclThreadDataKeyGet(
Tcl_ThreadDataKey *keyPtr) /* Identifier for the data chunk. */
{
#if TCL_THREADS
return TclThreadStorageKeyGet(keyPtr);
#else /* TCL_THREADS */
return *keyPtr;
#endif /* TCL_THREADS */
}
| > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
*
*----------------------------------------------------------------------
*/
void *
TclThreadDataKeyGet(
Tcl_ThreadDataKey *keyPtr) /* Identifier for the data chunk. */
{
#if TCL_THREADS
return TclThreadStorageKeyGet(keyPtr);
#else /* TCL_THREADS */
return *keyPtr;
#endif /* TCL_THREADS */
}
|
| ︙ | ︙ | |||
334 335 336 337 338 339 340 | * Side effects: * Frees up all thread local storage. * *---------------------------------------------------------------------- */ void | | < | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
* Side effects:
* Frees up all thread local storage.
*
*----------------------------------------------------------------------
*/
void
TclFinalizeThreadData(int quick)
{
TclFinalizeThreadDataThread();
#if TCL_THREADS && defined(USE_THREAD_ALLOC)
if (!quick) {
/*
* Quick exit principle makes it useless to terminate allocators
*/
|
| ︙ | ︙ |
Changes to generic/tclThreadAlloc.c.
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
size_t numFree; /* Number of blocks available */
/* All fields below for accounting only */
size_t numRemoves; /* Number of removes from bucket */
size_t numInserts; /* Number of inserts into bucket */
size_t numLocks; /* Number of locks acquired */
| | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
size_t numFree; /* Number of blocks available */
/* All fields below for accounting only */
size_t numRemoves; /* Number of removes from bucket */
size_t numInserts; /* Number of inserts into bucket */
size_t numLocks; /* Number of locks acquired */
size_t totalAssigned; /* Total space assigned to bucket */
} Bucket;
/*
* The following structure defines a cache of buckets and objs, of which there
* will be (at most) one per thread. Any changes need to be reflected in the
* struct AllocCache defined in tclInt.h, possibly also in the initialisation
* code in Tcl_CreateInterp().
|
| ︙ | ︙ | |||
782 783 784 785 786 787 788 |
Block *blockPtr,
int bucket,
size_t reqSize)
{
void *ptr;
blockPtr->magicNum1 = blockPtr->magicNum2 = MAGIC;
| | | 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
Block *blockPtr,
int bucket,
size_t reqSize)
{
void *ptr;
blockPtr->magicNum1 = blockPtr->magicNum2 = MAGIC;
blockPtr->sourceBucket = bucket;
blockPtr->blockReqSize = reqSize;
ptr = ((void *) (blockPtr + 1));
#if RCHECK
((unsigned char *)(ptr))[reqSize] = MAGIC;
#endif
return ptr;
}
|
| ︙ | ︙ | |||
942 943 944 945 946 947 948 949 950 951 952 953 954 955 |
* slight performance enhancement. The value is verified after the lock is
* actually acquired.
*/
if (cachePtr != sharedPtr && sharedPtr->buckets[bucket].numFree > 0) {
LockBucket(cachePtr, bucket);
if (sharedPtr->buckets[bucket].numFree > 0) {
/*
* Either move the entire list or walk the list to find the last
* block to move.
*/
n = bucketInfo[bucket].numMove;
if (n >= sharedPtr->buckets[bucket].numFree) {
| > | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 |
* slight performance enhancement. The value is verified after the lock is
* actually acquired.
*/
if (cachePtr != sharedPtr && sharedPtr->buckets[bucket].numFree > 0) {
LockBucket(cachePtr, bucket);
if (sharedPtr->buckets[bucket].numFree > 0) {
/*
* Either move the entire list or walk the list to find the last
* block to move.
*/
n = bucketInfo[bucket].numMove;
if (n >= sharedPtr->buckets[bucket].numFree) {
|
| ︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 |
blockPtr = blockPtr->nextBlock;
}
cachePtr->buckets[bucket].lastPtr = blockPtr;
blockPtr->nextBlock = NULL;
}
return 1;
}
| | | | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 |
blockPtr = blockPtr->nextBlock;
}
cachePtr->buckets[bucket].lastPtr = blockPtr;
blockPtr->nextBlock = NULL;
}
return 1;
}
/*
*----------------------------------------------------------------------
*
* TclInitThreadAlloc --
*
* Initializes the allocator cache-maintenance structures.
* It is done early and protected during the Tcl_InitSubsystems().
*
* Results:
* None.
*
* Side effects:
* None.
*
|
| ︙ | ︙ |
Added generic/tclThreadJoin.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
/*
* tclThreadJoin.c --
*
* This file implements a platform independent emulation layer for the
* handling of joinable threads. The Windows platform uses this code to
* provide the functionality of joining threads. This code is currently
* not necessary on Unix.
*
* Copyright © 2000 Scriptics Corporation
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
#ifdef _WIN32
/*
* The information about each joinable thread is remembered in a structure as
* defined below.
*/
typedef struct JoinableThread {
Tcl_ThreadId id; /* The id of the joinable thread. */
int result; /* A place for the result after the demise of
* the thread. */
int done; /* Boolean flag. Initialized to 0 and set to 1
* after the exit of the thread. This allows a
* thread requesting a join to detect when
* waiting is not necessary. */
int waitedUpon; /* Boolean flag. Initialized to 0 and set to 1
* by the thread waiting for this one via
* Tcl_JoinThread. Used to lock any other
* thread trying to wait on this one. */
Tcl_Mutex threadMutex; /* The mutex used to serialize access to this
* structure. */
Tcl_Condition cond; /* This is the condition a thread has to wait
* upon to get notified of the end of the
* described thread. It is signaled indirectly
* by Tcl_ExitThread. */
struct JoinableThread *nextThreadPtr;
/* Reference to the next thread in the list of
* joinable threads. */
} JoinableThread;
/*
* The following variable is used to maintain the global list of all joinable
* threads. Usage by a thread is allowed only if the thread acquired the
* 'joinMutex'.
*/
TCL_DECLARE_MUTEX(joinMutex)
static JoinableThread *firstThreadPtr;
/*
*----------------------------------------------------------------------
*
* TclJoinThread --
*
* This procedure waits for the exit of the thread with the specified id
* and returns its result.
*
* Results:
* A standard tcl result signaling the overall success/failure of the
* operation and an integer result delivered by the thread which was
* waited upon.
*
* Side effects:
* Deallocates the memory allocated by TclRememberJoinableThread.
* Removes the data associated to the thread waited upon from the list of
* joinable threads.
*
*----------------------------------------------------------------------
*/
int
TclJoinThread(
Tcl_ThreadId id, /* The id of the thread to wait upon. */
int *result) /* Reference to a location for the result of
* the thread we are waiting upon. */
{
JoinableThread *threadPtr;
/*
* Steps done here:
* i. Acquire the joinMutex and search for the thread.
* ii. Error out if it could not be found.
* iii. If found, switch from exclusive access to the list to exclusive
* access to the thread structure.
* iv. Error out if some other is already waiting.
* v. Skip the waiting part of the thread is already done.
* vi. Wait for the thread to exit, mark it as waited upon too.
* vii. Get the result form the structure,
* viii. switch to exclusive access of the list,
* ix. remove the structure from the list,
* x. then switch back to exclusive access to the structure
* xi. and delete it.
*/
Tcl_MutexLock(&joinMutex);
threadPtr = firstThreadPtr;
while (threadPtr!=NULL && threadPtr->id!=id) {
threadPtr = threadPtr->nextThreadPtr;
}
if (threadPtr == NULL) {
/*
* Thread not found. Either not joinable, or already waited upon and
* exited. Whatever, an error is in order.
*/
Tcl_MutexUnlock(&joinMutex);
return TCL_ERROR;
}
/*
* [1] If we don't lock the structure before giving up exclusive access to
* the list some other thread just completing its wait on the same thread
* can delete the structure from under us, leaving us with a dangling
* pointer.
*/
Tcl_MutexLock(&threadPtr->threadMutex);
Tcl_MutexUnlock(&joinMutex);
/*
* [2] Now that we have the structure mutex any other thread that just
* tries to delete structure will wait at location [3] until we are done
* with the structure. And in that case we are done with it rather quickly
* as 'waitedUpon' will be set and we will have to error out.
*/
if (threadPtr->waitedUpon) {
Tcl_MutexUnlock(&threadPtr->threadMutex);
return TCL_ERROR;
}
/*
* We are waiting now, let other threads recognize this.
*/
threadPtr->waitedUpon = 1;
while (!threadPtr->done) {
Tcl_ConditionWait(&threadPtr->cond, &threadPtr->threadMutex, NULL);
}
/*
* We have to release the structure before trying to access the list again
* or we can run into deadlock with a thread at [1] (see above) because of
* us holding the structure and the other holding the list. There is no
* problem with dangling pointers here as 'waitedUpon == 1' is still valid
* and any other thread will error out and not come to this place. IOW,
* the fact that we are here also means that no other thread came here
* before us and is able to delete the structure.
*/
Tcl_MutexUnlock(&threadPtr->threadMutex);
Tcl_MutexLock(&joinMutex);
/*
* We have to search the list again as its structure may (may, almost
* certainly) have changed while we were waiting. Especially now is the
* time to compute the predecessor in the list. Any earlier result can be
* dangling by now.
*/
if (firstThreadPtr == threadPtr) {
firstThreadPtr = threadPtr->nextThreadPtr;
} else {
JoinableThread *prevThreadPtr = firstThreadPtr;
while (prevThreadPtr->nextThreadPtr != threadPtr) {
prevThreadPtr = prevThreadPtr->nextThreadPtr;
}
prevThreadPtr->nextThreadPtr = threadPtr->nextThreadPtr;
}
Tcl_MutexUnlock(&joinMutex);
/*
* [3] Now that the structure is not part of the list anymore no other
* thread can acquire its mutex from now on. But it is possible that
* another thread is still holding the mutex though, see location [2]. So
* we have to acquire the mutex one more time to wait for that thread to
* finish. We can (and have to) release the mutex immediately.
*/
Tcl_MutexLock(&threadPtr->threadMutex);
Tcl_MutexUnlock(&threadPtr->threadMutex);
/*
* Copy the result to us, finalize the synchronisation objects, then free
* the structure and return.
*/
*result = threadPtr->result;
Tcl_ConditionFinalize(&threadPtr->cond);
Tcl_MutexFinalize(&threadPtr->threadMutex);
Tcl_Free(threadPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclRememberJoinableThread --
*
* This procedure remembers a thread as joinable. Only a call to
* TclJoinThread will remove the structure created (and initialized) here.
* IOW, not waiting upon a joinable thread will cause memory leaks.
*
* Results:
* None.
*
* Side effects:
* Allocates memory, adds it to the global list of all joinable threads.
*
*----------------------------------------------------------------------
*/
void
TclRememberJoinableThread(
Tcl_ThreadId id) /* The thread to remember as joinable */
{
JoinableThread *threadPtr;
threadPtr = (JoinableThread *)Tcl_Alloc(sizeof(JoinableThread));
threadPtr->id = id;
threadPtr->done = 0;
threadPtr->waitedUpon = 0;
threadPtr->threadMutex = (Tcl_Mutex) NULL;
threadPtr->cond = (Tcl_Condition) NULL;
Tcl_MutexLock(&joinMutex);
threadPtr->nextThreadPtr = firstThreadPtr;
firstThreadPtr = threadPtr;
Tcl_MutexUnlock(&joinMutex);
}
/*
*----------------------------------------------------------------------
*
* TclSignalExitThread --
*
* This procedure signals that the specified thread is done with its
* work. If the thread is joinable this signal is propagated to the
* thread waiting upon it.
*
* Results:
* None.
*
* Side effects:
* Modifies the associated structure to hold the result.
*
*----------------------------------------------------------------------
*/
void
TclSignalExitThread(
Tcl_ThreadId id, /* Id of the thread signaling its exit. */
int result) /* The result from the thread. */
{
JoinableThread *threadPtr;
Tcl_MutexLock(&joinMutex);
threadPtr = firstThreadPtr;
while ((threadPtr != NULL) && (threadPtr->id != id)) {
threadPtr = threadPtr->nextThreadPtr;
}
if (threadPtr == NULL) {
/*
* Thread not found. Not joinable. No problem, nothing to do.
*/
Tcl_MutexUnlock(&joinMutex);
return;
}
/*
* Switch over the exclusive access from the list to the structure, then
* store the result, set the flag and notify the waiting thread, provided
* that it exists. The order of lock/unlock ensures that a thread entering
* 'TclJoinThread' will not interfere with us.
*/
Tcl_MutexLock(&threadPtr->threadMutex);
Tcl_MutexUnlock(&joinMutex);
threadPtr->done = 1;
threadPtr->result = result;
if (threadPtr->waitedUpon) {
Tcl_ConditionNotify(&threadPtr->cond);
}
Tcl_MutexUnlock(&threadPtr->threadMutex);
}
#else
TCL_MAC_EMPTY_FILE(generic_tclThreadJoin_c)
#endif /* _WIN32 */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclThreadStorage.c.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
void *key; /* Key into the system TSD structure. The
* collection of Tcl TSD values for a
* particular thread will hang off the
* back-end of this. */
sig_atomic_t counter; /* The number of different Tcl TSDs used
* across *all* threads. This is a strictly
* increasing value. */
| < < < | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
void *key; /* Key into the system TSD structure. The
* collection of Tcl TSD values for a
* particular thread will hang off the
* back-end of this. */
sig_atomic_t counter; /* The number of different Tcl TSDs used
* across *all* threads. This is a strictly
* increasing value. */
Tcl_Mutex mutex; /* Protection for the rest of this structure,
* which holds per-process data. */
} tsdGlobal = { NULL, 0, NULL };
/*
* The type of the data held per thread in a system TSD.
*/
typedef struct {
void **tablePtr; /* The table of Tcl TSDs. */
sig_atomic_t allocated; /* The size of the table in the current
* thread. */
} TSDTable;
/*
* The actual type of Tcl_ThreadDataKey.
*/
|
| ︙ | ︙ | |||
100 101 102 103 104 105 106 |
Tcl_Panic("unable to allocate TSDTable");
}
for (i = 0; i < tsdTablePtr->allocated; ++i) {
tsdTablePtr->tablePtr[i] = NULL;
}
| < < < < | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
Tcl_Panic("unable to allocate TSDTable");
}
for (i = 0; i < tsdTablePtr->allocated; ++i) {
tsdTablePtr->tablePtr[i] = NULL;
}
return tsdTablePtr;
}
static void
TSDTableDelete(
TSDTable *tsdTablePtr)
{
|
| ︙ | ︙ | |||
126 127 128 129 130 131 132 |
Tcl_Free(tsdTablePtr->tablePtr[i]);
}
}
TclpSysFree(tsdTablePtr->tablePtr);
TclpSysFree(tsdTablePtr);
| < < < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
Tcl_Free(tsdTablePtr->tablePtr[i]);
}
}
TclpSysFree(tsdTablePtr->tablePtr);
TclpSysFree(tsdTablePtr);
}
/*
*----------------------------------------------------------------------
*
* TSDTableGrow --
*
|
| ︙ | ︙ | |||
180 181 182 183 184 185 186 | } /* *---------------------------------------------------------------------- * * TclThreadStorageKeyGet -- * | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | } /* *---------------------------------------------------------------------- * * TclThreadStorageKeyGet -- * * This procedure gets the value associated with the passed key. * * Results: * A pointer value associated with the Tcl_ThreadDataKey or NULL. * * Side effects: * None. * |
| ︙ | ︙ | |||
332 333 334 335 336 337 338 | /* *---------------------------------------------------------------------- * * TclFinalizeThreadStorage -- * * This procedure cleans up the thread storage data key for all threads. * IMPORTANT: All Tcl threads must be finalized before calling this! | < < < < < < < < < < < < < < | | < | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
/*
*----------------------------------------------------------------------
*
* TclFinalizeThreadStorage --
*
* This procedure cleans up the thread storage data key for all threads.
* IMPORTANT: All Tcl threads must be finalized before calling this!
*
* Results:
* None.
*
* Side effects:
* Releases the thread data key.
*
*----------------------------------------------------------------------
*/
void
TclFinalizeThreadStorage(void)
{
TclpThreadDeleteKey(tsdGlobal.key);
tsdGlobal.key = NULL;
}
#else /* !TCL_THREADS */
/*
* Stub functions for non-threaded builds
*/
|
| ︙ | ︙ |
Changes to generic/tclThreadTest.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 | static ThreadSpecificData *threadList = NULL; /* * The following bit-values are legal for the "flags" field of the * ThreadSpecificData structure. */ | | | < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | static ThreadSpecificData *threadList = NULL; /* * The following bit-values are legal for the "flags" field of the * ThreadSpecificData structure. */ #define TP_Dying 0x001 /* This thread is being canceled */ /* * An instance of the following structure contains all information that is * passed into a new thread when the thread is created using either the * "thread create" Tcl command or the ThreadCreate() C function. */ |
| ︙ | ︙ | |||
95 96 97 98 99 100 101 |
Tcl_Condition done; /* Signaled when the script completes */
int code; /* Return value of Tcl_Eval */
char *result; /* Result from the script */
char *errorInfo; /* Copy of errorInfo variable */
char *errorCode; /* Copy of errorCode variable */
Tcl_ThreadId srcThreadId; /* Id of sending thread, in case it dies */
Tcl_ThreadId dstThreadId; /* Id of target thread, in case it dies */
| | > | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
Tcl_Condition done; /* Signaled when the script completes */
int code; /* Return value of Tcl_Eval */
char *result; /* Result from the script */
char *errorInfo; /* Copy of errorInfo variable */
char *errorCode; /* Copy of errorCode variable */
Tcl_ThreadId srcThreadId; /* Id of sending thread, in case it dies */
Tcl_ThreadId dstThreadId; /* Id of target thread, in case it dies */
struct ThreadEvent *eventPtr; /* Back pointer */
struct ThreadEventResult *nextPtr; /* List for cleanup */
struct ThreadEventResult *prevPtr;
} ThreadEventResult;
static ThreadEventResult *resultList;
/*
* This is for simple error handling when a thread script exits badly.
*/
static Tcl_ThreadId mainThreadId;
static Tcl_ThreadId errorThreadId;
static char *errorProcString;
/*
* Access to the list of threads and to the thread send results is guarded by
* this mutex.
*/
TCL_DECLARE_MUTEX(threadMutex)
static Tcl_ObjCmdProc ThreadCmd;
static int ThreadCreate(Tcl_Interp *interp, const char *script,
int joinable);
static int ThreadList(Tcl_Interp *interp);
static int ThreadSend(Tcl_Interp *interp, Tcl_ThreadId id,
const char *script, int wait);
static int ThreadCancel(Tcl_Interp *interp, Tcl_ThreadId id,
const char *result, int flags);
|
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
Tcl_MutexLock(&threadMutex);
if (mainThreadId == 0) {
mainThreadId = Tcl_GetCurrentThread();
}
Tcl_MutexUnlock(&threadMutex);
| | | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
Tcl_MutexLock(&threadMutex);
if (mainThreadId == 0) {
mainThreadId = Tcl_GetCurrentThread();
}
Tcl_MutexUnlock(&threadMutex);
Tcl_CreateObjCommand(interp, "testthread", ThreadCmd, NULL, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ThreadCmd --
*
* This procedure is invoked to process the "testthread" Tcl command. See
* the user documentation for details on what it does.
*
* thread cancel ?-unwind? id ?result?
* thread create ?-joinable? ?script?
* thread send ?-async? id script
|
| ︙ | ︙ | |||
206 207 208 209 210 211 212 | * Side effects: * See the user documentation. * *---------------------------------------------------------------------- */ static int | | | | | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
ThreadCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
static const char *const threadOptions[] = {
"cancel", "create", "event", "exit", "id",
"join", "names", "send", "wait", "errorproc",
NULL
};
|
| ︙ | ︙ | |||
249 250 251 252 253 254 255 |
Tcl_MutexUnlock(&threadMutex);
}
switch (option) {
case THREAD_CANCEL: {
Tcl_WideInt id;
const char *result;
| | < | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
Tcl_MutexUnlock(&threadMutex);
}
switch (option) {
case THREAD_CANCEL: {
Tcl_WideInt id;
const char *result;
int flags, arg;
if ((objc < 3) || (objc > 5)) {
Tcl_WrongNumArgs(interp, 2, objv, "?-unwind? id ?result?");
return TCL_ERROR;
}
flags = 0;
arg = 2;
|
| ︙ | ︙ | |||
520 521 522 523 524 525 526 |
return TCL_ERROR;
}
/*
* Wait for the thread to start because it is using something on our stack!
*/
| | | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
return TCL_ERROR;
}
/*
* Wait for the thread to start because it is using something on our stack!
*/
Tcl_ConditionWait(&ctrl.condWait, &threadMutex, NULL);
Tcl_MutexUnlock(&threadMutex);
Tcl_ConditionFinalize(&ctrl.condWait);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt)(size_t)id));
return TCL_OK;
}
/*
|
| ︙ | ︙ | |||
674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
argv[1] = buf;
argv[2] = errorInfo;
script = Tcl_Merge(3, argv);
ThreadSend(interp, errorThreadId, script, 0);
Tcl_Free(script);
}
}
/*
*------------------------------------------------------------------------
*
* ListUpdateInner --
*
* Add the thread local storage to the list. This assumes the caller has
| > | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 |
argv[1] = buf;
argv[2] = errorInfo;
script = Tcl_Merge(3, argv);
ThreadSend(interp, errorThreadId, script, 0);
Tcl_Free(script);
}
}
/*
*------------------------------------------------------------------------
*
* ListUpdateInner --
*
* Add the thread local storage to the list. This assumes the caller has
|
| ︙ | ︙ | |||
751 752 753 754 755 756 757 | } /* *------------------------------------------------------------------------ * * ThreadList -- * | | | | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 |
}
/*
*------------------------------------------------------------------------
*
* ThreadList --
*
* Return a list of threads running Tcl interpreters.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static int
ThreadList(
Tcl_Interp *interp)
{
|
| ︙ | ︙ | |||
784 785 786 787 788 789 790 | } /* *------------------------------------------------------------------------ * * ThreadSend -- * | | | | | 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
}
/*
*------------------------------------------------------------------------
*
* ThreadSend --
*
* Send a script to another thread.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static int
ThreadSend(
Tcl_Interp *interp, /* The current interpreter. */
|
| ︙ | ︙ | |||
893 894 895 896 897 898 899 |
/*
* Block on the results and then get them.
*/
Tcl_ResetResult(interp);
while (resultPtr->result == NULL) {
| | | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 |
/*
* Block on the results and then get them.
*/
Tcl_ResetResult(interp);
while (resultPtr->result == NULL) {
Tcl_ConditionWait(&resultPtr->done, &threadMutex, NULL);
}
/*
* Unlink result from the result list.
*/
if (resultPtr->prevPtr) {
|
| ︙ | ︙ | |||
939 940 941 942 943 944 945 | } /* *------------------------------------------------------------------------ * * ThreadCancel -- * | | | | | 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 |
}
/*
*------------------------------------------------------------------------
*
* ThreadCancel --
*
* Cancels a script in another thread.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static int
ThreadCancel(
Tcl_Interp *interp, /* The current interpreter. */
|
| ︙ | ︙ | |||
995 996 997 998 999 1000 1001 | } /* *------------------------------------------------------------------------ * * ThreadEventProc -- * | | | | | 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 |
}
/*
*------------------------------------------------------------------------
*
* ThreadEventProc --
*
* Handle the event in the target thread.
*
* Results:
* Returns 1 to indicate that the event was processed.
*
* Side effects:
* Fills out the ThreadEventResult struct.
*
*------------------------------------------------------------------------
*/
static int
ThreadEventProc(
Tcl_Event *evPtr, /* Really ThreadEvent */
|
| ︙ | ︙ | |||
1065 1066 1067 1068 1069 1070 1071 | } /* *------------------------------------------------------------------------ * * ThreadFreeProc -- * | | | | | 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 | } /* *------------------------------------------------------------------------ * * ThreadFreeProc -- * * This is called from when we are exiting and memory needs * to be freed. * * Results: * None. * * Side effects: * Clears up mem specified in clientData * *------------------------------------------------------------------------ */ |
| ︙ | ︙ | |||
1091 1092 1093 1094 1095 1096 1097 | } /* *------------------------------------------------------------------------ * * ThreadDeleteEvent -- * | | | | | 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 | } /* *------------------------------------------------------------------------ * * ThreadDeleteEvent -- * * This is called from the ThreadExitProc to delete memory related * to events that we put on the queue. * * Results: * 1 it was our event and we want it removed, 0 otherwise. * * Side effects: * It cleans up our events in the event queue for this thread. * *------------------------------------------------------------------------ */ |
| ︙ | ︙ | |||
1118 1119 1120 1121 1122 1123 1124 |
}
/*
* If it was NULL, we were in the middle of servicing the event and it
* should be removed
*/
| | | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 |
}
/*
* If it was NULL, we were in the middle of servicing the event and it
* should be removed
*/
return (eventPtr->proc == NULL);
}
/*
*------------------------------------------------------------------------
*
* ThreadExitProc --
*
* This is called when the thread exits.
*
* Results:
* None.
*
* Side effects:
* It unblocks anyone that is waiting on a send to this thread. It cleans
* up any events in the event queue for this thread.
*
*------------------------------------------------------------------------
*/
|
| ︙ | ︙ |
Changes to generic/tclTimer.c.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 |
/*
* For each timer callback that's pending there is one record of the following
* type. The normal handlers (created by Tcl_CreateTimerHandler) are chained
* together in a list sorted by time (earliest event first).
*/
typedef struct TimerHandler {
| | | | < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/*
* For each timer callback that's pending there is one record of the following
* type. The normal handlers (created by Tcl_CreateTimerHandler) are chained
* together in a list sorted by time (earliest event first).
*/
typedef struct TimerHandler {
Tcl_Time time; /* When timer is to fire. */
Tcl_TimerProc *proc; /* Function to call. */
void *clientData; /* Argument to pass to proc. */
Tcl_TimerToken token; /* Identifies handler so it can be deleted. */
struct TimerHandler *nextPtr;
/* Next event in queue, or NULL for end of
* queue. */
} TimerHandler;
/*
* The data structure below is used by the "after" command to remember the
|
| ︙ | ︙ | |||
55 56 57 58 59 60 61 |
* which an "after" command has ever been invoked. A pointer to this structure
* is stored in the AssocData for the "tclAfter" key.
*/
typedef struct AfterAssocData {
Tcl_Interp *interp; /* The interpreter for which this data is
* registered. */
| | < < < < < < < < < < < < < < < | < < < < < | | > > | > > > > < < < < < < | < < < < < < < < < < > < | < > | | | > > | | | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
* which an "after" command has ever been invoked. A pointer to this structure
* is stored in the AssocData for the "tclAfter" key.
*/
typedef struct AfterAssocData {
Tcl_Interp *interp; /* The interpreter for which this data is
* registered. */
AfterInfo *firstAfterPtr; /* First in list of all "after"
* commands still pending for this interpreter, or
* NULL if none. */
} AfterAssocData;
/*
* There is one of the following structures for each of the handlers declared
* in a call to Tcl_DoWhenIdle. All of the currently-active handlers are
* linked together into a list.
*/
typedef struct IdleHandler {
Tcl_IdleProc *proc; /* Function to call. */
void *clientData; /* Value to pass to proc. */
int generation; /* Used to distinguish older handlers from
* recently-created ones. */
struct IdleHandler *nextPtr;/* Next in list of active handlers. */
} IdleHandler;
/*
* The timer and idle queues are per-thread because they are associated with
* the notifier, which is also per-thread.
*
* All static variables used in this file are collected into a single instance
* of the following structure. For multi-threaded implementations, there is
* one instance of this structure for each thread.
*
* Notice that different structures with the same name appear in other files.
* The structure defined below is used in this file only.
*/
typedef struct {
TimerHandler *firstTimerHandlerPtr; /* First event in queue. */
int lastTimerId; /* Timer identifier of most recently created
* timer. */
int timerPending; /* 1 if a timer event is in the queue. */
IdleHandler *idleList; /* First in list of all idle handlers. */
IdleHandler *lastIdlePtr; /* Last in list (or NULL for empty list). */
int idleGeneration; /* Used to fill in the "generation" fields of
* IdleHandler structures. Increments each
* time Tcl_DoOneEvent starts calling idle
* handlers, so that all old handlers can be
* called without calling any of the new ones
* created by old ones. */
int afterId; /* For unique identifiers of after events. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
* Helper macros for working with times. TCL_TIME_BEFORE encodes how to write
* the ordering relation on (normalized) times, and TCL_TIME_DIFF_MS computes
* the number of milliseconds difference between two times. Both macros use
* both of their arguments multiple times, so make sure they are cheap and
* side-effect free. The "prototypes" for these macros are:
*
* static int TCL_TIME_BEFORE(Tcl_Time t1, Tcl_Time t2);
* static Tcl_WideInt TCL_TIME_DIFF_MS(Tcl_Time t1, Tcl_Time t2);
*/
#define TCL_TIME_BEFORE(t1, t2) \
(((t1).sec<(t2).sec) || ((t1).sec==(t2).sec && (t1).usec<(t2).usec))
#define TCL_TIME_DIFF_MS(t1, t2) \
(1000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
((t1).usec - (t2).usec)/1000)
#define TCL_TIME_DIFF_MS_CEILING(t1, t2) \
(1000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
((t1).usec - (t2).usec + 999)/1000)
/*
* Sleeps under that number of milliseconds don't get double-checked
* and are done in exactly one Tcl_Sleep(). This to limit gettimeofday()s.
*/
#define SLEEP_OFFLOAD_GETTIMEOFDAY 20
/*
* The maximum number of milliseconds for each Tcl_Sleep call in AfterDelay.
* This is used to limit the maximum lag between interp limit and script
* cancellation checks.
*/
#define TCL_TIME_MAXIMUM_SLICE 500
/*
* Prototypes for functions referenced only in this file:
*/
static void AfterCleanupProc(void *clientData,
Tcl_Interp *interp);
static int AfterDelay(Tcl_Interp *interp, Tcl_WideInt ms);
static void AfterProc(void *clientData);
static void FreeAfterPtr(AfterInfo *afterPtr);
static AfterInfo * GetAfterEvent(AfterAssocData *assocPtr,
Tcl_Obj *commandPtr);
static ThreadSpecificData *InitTimer(void);
static void TimerExitProc(void *clientData);
static int TimerHandlerEventProc(Tcl_Event *evPtr, int flags);
static void TimerCheckProc(void *clientData, int flags);
static void TimerSetupProc(void *clientData, int flags);
/*
*----------------------------------------------------------------------
*
* InitTimer --
*
* This function initializes the timer module.
|
| ︙ | ︙ | |||
281 282 283 284 285 286 287 |
TimerExitProc(
TCL_UNUSED(void *))
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
Tcl_DeleteEventSource(TimerSetupProc, TimerCheckProc, NULL);
if (tsdPtr != NULL) {
| | < < < < < | | | | | | | | | < | | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < > | > > | | | | < | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
TimerExitProc(
TCL_UNUSED(void *))
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
Tcl_DeleteEventSource(TimerSetupProc, TimerCheckProc, NULL);
if (tsdPtr != NULL) {
TimerHandler *timerHandlerPtr;
timerHandlerPtr = tsdPtr->firstTimerHandlerPtr;
while (timerHandlerPtr != NULL) {
tsdPtr->firstTimerHandlerPtr = timerHandlerPtr->nextPtr;
Tcl_Free(timerHandlerPtr);
timerHandlerPtr = tsdPtr->firstTimerHandlerPtr;
}
}
}
/*
*--------------------------------------------------------------
*
* Tcl_CreateTimerHandler --
*
* Arrange for a given function to be invoked at a particular time in the
* future.
*
* Results:
* The return value is a token for the timer event, which may be used to
* delete the event before it fires.
*
* Side effects:
* When milliseconds have elapsed, proc will be invoked exactly once.
*
*--------------------------------------------------------------
*/
Tcl_TimerToken
Tcl_CreateTimerHandler(
int milliseconds, /* How many milliseconds to wait before
* invoking proc. */
Tcl_TimerProc *proc, /* Function to invoke. */
void *clientData) /* Arbitrary data to pass to proc. */
{
Tcl_Time time;
/*
* Compute when the event should fire.
*/
Tcl_GetTime(&time);
time.sec += milliseconds/1000;
time.usec += (milliseconds%1000)*1000;
if (time.usec >= 1000000) {
time.usec -= 1000000;
time.sec += 1;
}
return TclCreateAbsoluteTimerHandler(&time, proc, clientData);
}
/*
*--------------------------------------------------------------
*
* TclCreateAbsoluteTimerHandler --
*
|
| ︙ | ︙ | |||
410 411 412 413 414 415 416 | * exactly once. * *-------------------------------------------------------------- */ Tcl_TimerToken TclCreateAbsoluteTimerHandler( | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
* exactly once.
*
*--------------------------------------------------------------
*/
Tcl_TimerToken
TclCreateAbsoluteTimerHandler(
Tcl_Time *timePtr,
Tcl_TimerProc *proc,
void *clientData)
{
TimerHandler *timerHandlerPtr, *tPtr2, *prevPtr;
ThreadSpecificData *tsdPtr = InitTimer();
timerHandlerPtr = (TimerHandler *)Tcl_Alloc(sizeof(TimerHandler));
/*
* Fill in fields for the event.
*/
timerHandlerPtr->time = *timePtr;
timerHandlerPtr->proc = proc;
timerHandlerPtr->clientData = clientData;
tsdPtr->lastTimerId++;
timerHandlerPtr->token = (Tcl_TimerToken) INT2PTR(tsdPtr->lastTimerId);
/*
* Add the event to the corresponding queue in the correct position
* (ordered by event firing time).
*/
for (tPtr2 = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL; tPtr2 != NULL;
prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) {
if (TCL_TIME_BEFORE(timerHandlerPtr->time, tPtr2->time)) {
break;
}
}
timerHandlerPtr->nextPtr = tPtr2;
if (prevPtr == NULL) {
tsdPtr->firstTimerHandlerPtr = timerHandlerPtr;
} else {
prevPtr->nextPtr = timerHandlerPtr;
}
TimerSetupProc(NULL, TCL_ALL_EVENTS);
return timerHandlerPtr->token;
|
| ︙ | ︙ | |||
546 547 548 549 550 551 552 |
TimerHandler *timerHandlerPtr, *prevPtr;
ThreadSpecificData *tsdPtr = InitTimer();
if (token == NULL) {
return;
}
| < < | | | | | | | | | | | | | < | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
TimerHandler *timerHandlerPtr, *prevPtr;
ThreadSpecificData *tsdPtr = InitTimer();
if (token == NULL) {
return;
}
for (timerHandlerPtr = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL;
timerHandlerPtr != NULL; prevPtr = timerHandlerPtr,
timerHandlerPtr = timerHandlerPtr->nextPtr) {
if (timerHandlerPtr->token != token) {
continue;
}
if (prevPtr == NULL) {
tsdPtr->firstTimerHandlerPtr = timerHandlerPtr->nextPtr;
} else {
prevPtr->nextPtr = timerHandlerPtr->nextPtr;
}
Tcl_Free(timerHandlerPtr);
return;
}
}
/*
*----------------------------------------------------------------------
*
* TimerSetupProc --
|
| ︙ | ︙ | |||
588 589 590 591 592 593 594 |
*/
static void
TimerSetupProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
| | | < < | > | < < < < < < | < < < | | | < < < < < | < | | | | | | | < < < | < < < | | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 |
*/
static void
TimerSetupProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
Tcl_Time blockTime;
ThreadSpecificData *tsdPtr = InitTimer();
if (((flags & TCL_IDLE_EVENTS) && tsdPtr->idleList)
|| ((flags & TCL_TIMER_EVENTS) && tsdPtr->timerPending)) {
/*
* There is an idle handler or a pending timer event, so just poll.
*/
blockTime.sec = 0;
blockTime.usec = 0;
} else if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) {
/*
* Compute the timeout for the next timer on the list.
*/
Tcl_GetTime(&blockTime);
blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec;
blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec -
blockTime.usec;
if (blockTime.usec < 0) {
blockTime.sec -= 1;
blockTime.usec += 1000000;
}
if (blockTime.sec < 0) {
blockTime.sec = 0;
blockTime.usec = 0;
}
} else {
return;
}
Tcl_SetMaxBlockTime(&blockTime);
}
/*
*----------------------------------------------------------------------
*
* TimerCheckProc --
*
|
| ︙ | ︙ | |||
668 669 670 671 672 673 674 |
*/
static void
TimerCheckProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
| > | | < < < | < < < | | | < < < | | | > | < | | > | | | | | | | < < < < | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
*/
static void
TimerCheckProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
Tcl_Event *timerEvPtr;
Tcl_Time blockTime;
ThreadSpecificData *tsdPtr = InitTimer();
if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) {
/*
* Compute the timeout for the next timer on the list.
*/
Tcl_GetTime(&blockTime);
blockTime.sec = tsdPtr->firstTimerHandlerPtr->time.sec - blockTime.sec;
blockTime.usec = tsdPtr->firstTimerHandlerPtr->time.usec -
blockTime.usec;
if (blockTime.usec < 0) {
blockTime.sec -= 1;
blockTime.usec += 1000000;
}
if (blockTime.sec < 0) {
blockTime.sec = 0;
blockTime.usec = 0;
}
/*
* If the first timer has expired, stick an event on the queue.
*/
if (blockTime.sec == 0 && blockTime.usec == 0 &&
!tsdPtr->timerPending) {
tsdPtr->timerPending = 1;
timerEvPtr = (Tcl_Event *)Tcl_Alloc(sizeof(Tcl_Event));
timerEvPtr->proc = TimerHandlerEventProc;
Tcl_QueueEvent(timerEvPtr, TCL_QUEUE_TAIL);
}
}
}
/*
|
| ︙ | ︙ | |||
742 743 744 745 746 747 748 749 750 751 752 753 754 755 |
static int
TimerHandlerEventProc(
TCL_UNUSED(Tcl_Event *),
int flags) /* Flags that indicate what events to handle,
* such as TCL_FILE_EVENTS. */
{
ThreadSpecificData *tsdPtr = InitTimer();
/*
* Do nothing if timers aren't enabled. This leaves the event on the
* queue, so we will get to it as soon as ServiceEvents() is called with
* timers enabled.
*/
| > > > | 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
static int
TimerHandlerEventProc(
TCL_UNUSED(Tcl_Event *),
int flags) /* Flags that indicate what events to handle,
* such as TCL_FILE_EVENTS. */
{
TimerHandler *timerHandlerPtr, **nextPtrPtr;
Tcl_Time time;
int currentTimerId;
ThreadSpecificData *tsdPtr = InitTimer();
/*
* Do nothing if timers aren't enabled. This leaves the event on the
* queue, so we will get to it as soon as ServiceEvents() is called with
* timers enabled.
*/
|
| ︙ | ︙ | |||
779 780 781 782 783 784 785 |
* This is fairly likely on Windows, since it has a course granularity
* clock. Since timers are placed on the queue in time order with the
* most recently created handler appearing after earlier ones with the
* same expiration time, we don't have to worry about newer generation
* timers appearing before later ones.
*/
| < < < < < < < < < | < < < < < < < | | < < < < < | | | | | | | | | | | | | | | | | | | | | | < | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
* This is fairly likely on Windows, since it has a course granularity
* clock. Since timers are placed on the queue in time order with the
* most recently created handler appearing after earlier ones with the
* same expiration time, we don't have to worry about newer generation
* timers appearing before later ones.
*/
tsdPtr->timerPending = 0;
currentTimerId = tsdPtr->lastTimerId;
Tcl_GetTime(&time);
while (1) {
nextPtrPtr = &tsdPtr->firstTimerHandlerPtr;
timerHandlerPtr = tsdPtr->firstTimerHandlerPtr;
if (timerHandlerPtr == NULL) {
break;
}
if (TCL_TIME_BEFORE(time, timerHandlerPtr->time)) {
break;
}
/*
* Bail out if the next timer is of a newer generation.
*/
if ((currentTimerId - PTR2INT(timerHandlerPtr->token)) < 0) {
break;
}
/*
* Remove the handler from the queue before invoking it, to avoid
* potential reentrancy problems.
*/
*nextPtrPtr = timerHandlerPtr->nextPtr;
timerHandlerPtr->proc(timerHandlerPtr->clientData);
Tcl_Free(timerHandlerPtr);
}
TimerSetupProc(NULL, TCL_TIMER_EVENTS);
return 1;
}
/*
*--------------------------------------------------------------
|
| ︙ | ︙ | |||
861 862 863 864 865 866 867 |
void
Tcl_DoWhenIdle(
Tcl_IdleProc *proc, /* Function to invoke. */
void *clientData) /* Arbitrary value to pass to proc. */
{
IdleHandler *idlePtr;
| | | > | | 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 |
void
Tcl_DoWhenIdle(
Tcl_IdleProc *proc, /* Function to invoke. */
void *clientData) /* Arbitrary value to pass to proc. */
{
IdleHandler *idlePtr;
Tcl_Time blockTime;
ThreadSpecificData *tsdPtr = InitTimer();
idlePtr = (IdleHandler *)Tcl_Alloc(sizeof(IdleHandler));
idlePtr->proc = proc;
idlePtr->clientData = clientData;
idlePtr->generation = tsdPtr->idleGeneration;
idlePtr->nextPtr = NULL;
if (tsdPtr->lastIdlePtr == NULL) {
tsdPtr->idleList = idlePtr;
} else {
tsdPtr->lastIdlePtr->nextPtr = idlePtr;
}
tsdPtr->lastIdlePtr = idlePtr;
blockTime.sec = 0;
blockTime.usec = 0;
Tcl_SetMaxBlockTime(&blockTime);
}
/*
*----------------------------------------------------------------------
*
* Tcl_CancelIdleCall --
*
|
| ︙ | ︙ | |||
950 951 952 953 954 955 956 957 958 959 960 961 962 963 |
*/
int
TclServiceIdle(void)
{
IdleHandler *idlePtr;
int oldGeneration;
ThreadSpecificData *tsdPtr = InitTimer();
if (tsdPtr->idleList == NULL) {
return 0;
}
oldGeneration = tsdPtr->idleGeneration;
| > | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 |
*/
int
TclServiceIdle(void)
{
IdleHandler *idlePtr;
int oldGeneration;
Tcl_Time blockTime;
ThreadSpecificData *tsdPtr = InitTimer();
if (tsdPtr->idleList == NULL) {
return 0;
}
oldGeneration = tsdPtr->idleGeneration;
|
| ︙ | ︙ | |||
988 989 990 991 992 993 994 |
if (tsdPtr->idleList == NULL) {
tsdPtr->lastIdlePtr = NULL;
}
idlePtr->proc(idlePtr->clientData);
Tcl_Free(idlePtr);
}
if (tsdPtr->idleList) {
| > > | | 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 |
if (tsdPtr->idleList == NULL) {
tsdPtr->lastIdlePtr = NULL;
}
idlePtr->proc(idlePtr->clientData);
Tcl_Free(idlePtr);
}
if (tsdPtr->idleList) {
blockTime.sec = 0;
blockTime.usec = 0;
Tcl_SetMaxBlockTime(&blockTime);
}
return 1;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 |
*----------------------------------------------------------------------
*/
int
Tcl_AfterObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | > > > > | < > > > > > > > > > > > > > | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 |
*----------------------------------------------------------------------
*/
int
Tcl_AfterObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_WideInt ms = 0; /* Number of milliseconds to wait */
Tcl_Time wakeup;
AfterInfo *afterPtr;
AfterAssocData *assocPtr;
Tcl_Size length;
int index = -1;
static const char *const afterSubCmds[] = {
"cancel", "idle", "info", NULL
};
enum afterSubCmdsEnum {AFTER_CANCEL, AFTER_IDLE, AFTER_INFO};
ThreadSpecificData *tsdPtr = InitTimer();
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
return TCL_ERROR;
}
/*
* Create the "after" information associated for this interpreter, if it
* doesn't already exist.
*/
assocPtr = (AfterAssocData *)Tcl_GetAssocData(interp, "tclAfter", NULL);
if (assocPtr == NULL) {
assocPtr = (AfterAssocData *)Tcl_Alloc(sizeof(AfterAssocData));
assocPtr->interp = interp;
assocPtr->firstAfterPtr = NULL;
Tcl_SetAssocData(interp, "tclAfter", AfterCleanupProc, assocPtr);
}
/*
* First lets see if the command was passed a number as the first argument.
*/
if (TclGetWideIntFromObj(NULL, objv[1], &ms) != TCL_OK) {
if (Tcl_GetIndexFromObj(NULL, objv[1], afterSubCmds, "", 0, &index)
|
| ︙ | ︙ | |||
1056 1057 1058 1059 1060 1061 1062 |
/*
* At this point, either index = -1 and ms contains the number of ms
* to wait, or else index is the index of a subcommand.
*/
switch (index) {
case -1: {
| < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 |
/*
* At this point, either index = -1 and ms contains the number of ms
* to wait, or else index is the index of a subcommand.
*/
switch (index) {
case -1: {
if (ms < 0) {
ms = 0;
}
if (objc == 2) {
return AfterDelay(interp, ms);
}
afterPtr = (AfterInfo *)Tcl_Alloc(sizeof(AfterInfo));
afterPtr->assocPtr = assocPtr;
if (objc == 3) {
afterPtr->commandPtr = objv[2];
} else {
afterPtr->commandPtr = Tcl_ConcatObj(objc-2, objv+2);
}
|
| ︙ | ︙ | |||
1116 1117 1118 1119 1120 1121 1122 | * the future, and wrap-around is unlikely to occur in less than about * 1-10 years. Thus it's unlikely that any old ids will still be * around when wrap-around occurs. */ afterPtr->id = tsdPtr->afterId; tsdPtr->afterId += 1; | > > > > > > > | | | > > > > | | | < | < > > | | | < > > > | > > > > > | > > > > > > > > | > > > | | > > > > > > > | > | > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | < > > | | > > > | < < | | < | | | | | < | < < < | | | < < < > | | | < < < | < < < | < < < < < | < < > < | < < < | | < > | < < | < < < | | | < < | | | < < < < < < < | < < < | < < < | 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 |
* the future, and wrap-around is unlikely to occur in less than about
* 1-10 years. Thus it's unlikely that any old ids will still be
* around when wrap-around occurs.
*/
afterPtr->id = tsdPtr->afterId;
tsdPtr->afterId += 1;
Tcl_GetTime(&wakeup);
wakeup.sec += ms / 1000;
wakeup.usec += ms % 1000 * 1000;
if (wakeup.usec > 1000000) {
wakeup.sec++;
wakeup.usec -= 1000000;
}
afterPtr->token = TclCreateAbsoluteTimerHandler(&wakeup,
AfterProc, afterPtr);
afterPtr->nextPtr = assocPtr->firstAfterPtr;
assocPtr->firstAfterPtr = afterPtr;
Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
return TCL_OK;
}
case AFTER_CANCEL: {
Tcl_Obj *commandPtr;
const char *command, *tempCommand;
Tcl_Size tempLength;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "id|command");
return TCL_ERROR;
}
if (objc == 3) {
commandPtr = objv[2];
} else {
commandPtr = Tcl_ConcatObj(objc-2, objv+2);
}
command = TclGetStringFromObj(commandPtr, &length);
for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL;
afterPtr = afterPtr->nextPtr) {
tempCommand = TclGetStringFromObj(afterPtr->commandPtr,
&tempLength);
if ((length == tempLength)
&& !memcmp(command, tempCommand, length)) {
break;
}
}
if (afterPtr == NULL) {
afterPtr = GetAfterEvent(assocPtr, commandPtr);
}
if (objc != 3) {
Tcl_DecrRefCount(commandPtr);
}
if (afterPtr != NULL) {
if (afterPtr->token != NULL) {
Tcl_DeleteTimerHandler(afterPtr->token);
} else {
Tcl_CancelIdleCall(AfterProc, afterPtr);
}
FreeAfterPtr(afterPtr);
}
break;
}
case AFTER_IDLE:
if (objc < 3) {
Tcl_WrongNumArgs(interp, 2, objv, "script ?script ...?");
return TCL_ERROR;
}
afterPtr = (AfterInfo *)Tcl_Alloc(sizeof(AfterInfo));
afterPtr->assocPtr = assocPtr;
if (objc == 3) {
afterPtr->commandPtr = objv[2];
} else {
afterPtr->commandPtr = Tcl_ConcatObj(objc-2, objv+2);
}
Tcl_IncrRefCount(afterPtr->commandPtr);
afterPtr->id = tsdPtr->afterId;
tsdPtr->afterId += 1;
afterPtr->token = NULL;
afterPtr->nextPtr = assocPtr->firstAfterPtr;
assocPtr->firstAfterPtr = afterPtr;
Tcl_DoWhenIdle(AfterProc, afterPtr);
Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
break;
case AFTER_INFO:
if (objc == 2) {
Tcl_Obj *resultObj;
TclNewObj(resultObj);
for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL;
afterPtr = afterPtr->nextPtr) {
if (assocPtr->interp == interp) {
Tcl_ListObjAppendElement(NULL, resultObj, Tcl_ObjPrintf(
"after#%d", afterPtr->id));
}
}
Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?id?");
return TCL_ERROR;
}
afterPtr = GetAfterEvent(assocPtr, objv[2]);
if (afterPtr == NULL) {
const char *eventStr = TclGetString(objv[2]);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"event \"%s\" doesn't exist", eventStr));
Tcl_SetErrorCode(interp, "TCL","LOOKUP","EVENT", eventStr, (char *)NULL);
return TCL_ERROR;
} else {
Tcl_Obj *resultListPtr;
TclNewObj(resultListPtr);
Tcl_ListObjAppendElement(interp, resultListPtr,
afterPtr->commandPtr);
Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
(afterPtr->token == NULL) ? "idle" : "timer", -1));
Tcl_SetObjResult(interp, resultListPtr);
}
break;
default:
TCL_UNREACHABLE();
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* AfterDelay --
*
* Implements the blocking delay behaviour of [after $time]. Tricky
* because it has to take into account any time limit that has been set.
*
* Results:
* Standard Tcl result code (with error set if an error occurred due to a
* time limit being exceeded or being canceled).
*
* Side effects:
* May adjust the time limit granularity marker.
*
*----------------------------------------------------------------------
*/
static int
AfterDelay(
Tcl_Interp *interp,
Tcl_WideInt ms)
{
Interp *iPtr = (Interp *) interp;
Tcl_Time endTime, now;
Tcl_WideInt diff;
Tcl_GetTime(&now);
endTime = now;
endTime.sec += (ms / 1000);
endTime.usec += (ms % 1000) * 1000;
if (endTime.usec >= 1000000) {
endTime.sec++;
endTime.usec -= 1000000;
}
do {
if (Tcl_AsyncReady()) {
if (Tcl_AsyncInvoke(interp, TCL_OK) != TCL_OK) {
return TCL_ERROR;
}
}
if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
return TCL_ERROR;
}
if (iPtr->limit.timeEvent != NULL
&& TCL_TIME_BEFORE(iPtr->limit.time, now)) {
iPtr->limit.granularityTicker = 0;
if (Tcl_LimitCheck(interp) != TCL_OK) {
return TCL_ERROR;
}
}
if (iPtr->limit.timeEvent == NULL
|| TCL_TIME_BEFORE(endTime, iPtr->limit.time)) {
diff = TCL_TIME_DIFF_MS_CEILING(endTime, now);
if (diff > TCL_TIME_MAXIMUM_SLICE) {
diff = TCL_TIME_MAXIMUM_SLICE;
}
if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) {
diff = 1;
}
if (diff > 0) {
Tcl_Sleep((int) diff);
if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) {
break;
}
} else {
break;
}
} else {
diff = TCL_TIME_DIFF_MS(iPtr->limit.time, now);
if (diff > TCL_TIME_MAXIMUM_SLICE) {
diff = TCL_TIME_MAXIMUM_SLICE;
}
if (diff > 0) {
Tcl_Sleep((int) diff);
}
if (Tcl_AsyncReady()) {
if (Tcl_AsyncInvoke(interp, TCL_OK) != TCL_OK) {
return TCL_ERROR;
}
}
if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
return TCL_ERROR;
}
if (Tcl_LimitCheck(interp) != TCL_OK) {
return TCL_ERROR;
}
}
Tcl_GetTime(&now);
} while (TCL_TIME_BEFORE(now, endTime));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* GetAfterEvent --
|
| ︙ | ︙ | |||
1649 1650 1651 1652 1653 1654 1655 |
}
Tcl_DecrRefCount(afterPtr->commandPtr);
Tcl_Free(afterPtr);
}
Tcl_Free(assocPtr);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 |
}
Tcl_DecrRefCount(afterPtr->commandPtr);
Tcl_Free(afterPtr);
}
Tcl_Free(assocPtr);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/
|
Changes to generic/tclTomMath.h.
1 2 3 4 5 | #ifndef BN_TCL_H_ #define BN_TCL_H_ #include <stdint.h> #if defined(TCL_NO_TOMMATH_H) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#ifndef BN_TCL_H_
#define BN_TCL_H_
#include <stdint.h>
#if defined(TCL_NO_TOMMATH_H)
typedef size_t mp_digit;
typedef int mp_sign;
# define MP_ZPOS 0 /* positive integer */
# define MP_NEG 1 /* negative */
typedef int mp_ord;
# define MP_LT -1 /* less than */
# define MP_EQ 0 /* equal to */
# define MP_GT 1 /* greater than */
typedef int mp_err;
# define MP_OKAY 0 /* no error */
# define MP_ERR -1 /* unknown error */
# define MP_MEM -2 /* out of mem */
# define MP_VAL -3 /* invalid input */
# define MP_ITER -4 /* maximum iterations reached */
# define MP_BUF -5 /* buffer overflow, supplied buffer too small */
typedef int mp_order;
# define MP_LSB_FIRST -1
# define MP_MSB_FIRST 1
typedef int mp_endian;
# define MP_LITTLE_ENDIAN -1
# define MP_NATIVE_ENDIAN 0
# define MP_BIG_ENDIAN 1
# define MP_DEPRECATED_PRAGMA(s) /* nothing */
# define MP_WUR /* nothing */
# define mp_iszero(a) ((a)->used == 0)
# define mp_isneg(a) ((a)->sign != 0)
/* the infamous mp_int structure */
# ifndef MP_INT_DECLARED
# define MP_INT_DECLARED
typedef struct mp_int mp_int;
# endif
struct mp_int {
int used, alloc;
mp_sign sign;
mp_digit *dp;
};
#elif !defined(BN_H_) /* If BN_H_ already defined, don't try to include tommath.h again. */
# include "tommath.h"
#endif
#include "tclTomMathDecls.h" /* IWYU pragma: export */
|
| ︙ | ︙ |
Changes to generic/tclTomMathDecls.h.
1 2 3 4 5 6 7 8 | /* *---------------------------------------------------------------------- * * tclTomMathDecls.h -- * * This file contains the declarations for the 'libtommath' * functions that are exported by the Tcl library. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* *---------------------------------------------------------------------- * * tclTomMathDecls.h -- * * This file contains the declarations for the 'libtommath' * functions that are exported by the Tcl library. * * Copyright (c) 2005 by Kevin B. Kenny. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLTOMMATHDECLS #define _TCLTOMMATHDECLS |
| ︙ | ︙ | |||
25 26 27 28 29 30 31 | * Define the version of the Stubs table that's exported for tommath */ #define TCLTOMMATH_EPOCH 0 #define TCLTOMMATH_REVISION 0 #define Tcl_TomMath_InitStubs(interp,version) \ | | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
* Define the version of the Stubs table that's exported for tommath
*/
#define TCLTOMMATH_EPOCH 0
#define TCLTOMMATH_REVISION 0
#define Tcl_TomMath_InitStubs(interp,version) \
(TclTomMathInitializeStubs((interp),(version),\
TCLTOMMATH_EPOCH,TCLTOMMATH_REVISION))
/* Define custom memory allocation for libtommath */
/* MODULE_SCOPE void* TclBNAlloc( size_t ); */
#define TclBNAlloc(s) Tcl_AttemptAlloc((size_t)(s))
/* MODULE_SCOPE void* TclBNCalloc( size_t, size_t ); */
#define TclBNCalloc(m,s) memset(Tcl_AttemptAlloc((size_t)(m)*(size_t)(s)),0,(size_t)(m)*(size_t)(s))
|
| ︙ | ︙ |
Changes to generic/tclTomMathInterface.c.
| ︙ | ︙ | |||
63 64 65 66 67 68 69 |
*/
int
TclBN_epoch(void)
{
return TCLTOMMATH_EPOCH;
}
| | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
*/
int
TclBN_epoch(void)
{
return TCLTOMMATH_EPOCH;
}
/*
*----------------------------------------------------------------------
*
* TclBN_revision --
*
* Returns the revision level of the TclTomMath stubs table
*
|
| ︙ | ︙ |
Changes to generic/tclTomMathStubLib.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | #include "tclInt.h" #include "tclTomMath.h" MODULE_SCOPE const TclTomMathStubs *tclTomMathStubsPtr; const TclTomMathStubs *tclTomMathStubsPtr = NULL; | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include "tclInt.h" #include "tclTomMath.h" MODULE_SCOPE const TclTomMathStubs *tclTomMathStubsPtr; const TclTomMathStubs *tclTomMathStubsPtr = NULL; /* *---------------------------------------------------------------------- * * TclTomMathInitStubs -- * * Initializes the Stubs table for Tcl's subset of libtommath * |
| ︙ | ︙ |
Changes to generic/tclTrace.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
* Structures used to hold information about variable traces:
*/
typedef struct {
int flags; /* Operations for which Tcl command is to be
* invoked. */
Tcl_Size length; /* Number of non-NUL chars. in command. */
| | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
* Structures used to hold information about variable traces:
*/
typedef struct {
int flags; /* Operations for which Tcl command is to be
* invoked. */
Tcl_Size length; /* Number of non-NUL chars. in command. */
char command[TCLFLEXARRAY]; /* Space for Tcl command to invoke. Actual
* size will be as large as necessary to hold
* command. This field must be the last in the
* structure, so that it can be larger than 1
* byte. */
} TraceVarInfo;
typedef struct {
|
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
typedef struct {
int flags; /* Operations for which Tcl command is to be
* invoked. */
Tcl_Size length; /* Number of non-NUL chars. in command. */
Tcl_Trace stepTrace; /* Used for execution traces, when tracing
* inside the given command */
| | | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
typedef struct {
int flags; /* Operations for which Tcl command is to be
* invoked. */
Tcl_Size length; /* Number of non-NUL chars. in command. */
Tcl_Trace stepTrace; /* Used for execution traces, when tracing
* inside the given command */
Tcl_Size startLevel; /* Used for bookkeeping with step execution
* traces, store the level at which the step
* trace was invoked */
char *startCmd; /* Used for bookkeeping with step execution
* traces, store the command name which
* invoked step trace */
int curFlags; /* Trace flags for the current command */
int curCode; /* Return code for the current command */
size_t refCount; /* Used to ensure this structure is not
* deleted too early. Keeps track of how many
* pieces of code have a pointer to this
* structure. */
char command[TCLFLEXARRAY]; /* Space for Tcl command to invoke. Actual
* size will be as large as necessary to hold
* command. This field must be the last in the
* structure, so that it can be larger than 1
* byte. */
} TraceCommandInfo;
/*
|
| ︙ | ︙ | |||
77 78 79 80 81 82 83 | * currently executing. Therefore we don't let * further traces execute. * TCL_TRACE_EXEC_DIRECT - This execution trace is triggered directly * by the command being traced, not because of * an internal trace. * The flag 'TCL_TRACE_DESTROYED' may also be used in command execution traces. */ | | | | | | | < | | | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
* currently executing. Therefore we don't let
* further traces execute.
* TCL_TRACE_EXEC_DIRECT - This execution trace is triggered directly
* by the command being traced, not because of
* an internal trace.
* The flag 'TCL_TRACE_DESTROYED' may also be used in command execution traces.
*/
#define TCL_TRACE_ENTER_DURING_EXEC 4
#define TCL_TRACE_LEAVE_DURING_EXEC 8
#define TCL_TRACE_ANY_EXEC 15
#define TCL_TRACE_EXEC_IN_PROGRESS 0x10
#define TCL_TRACE_EXEC_DIRECT 0x20
/*
* Forward declarations for functions defined in this file:
*/
enum traceOptionsEnum {
TRACE_ADD, TRACE_INFO, TRACE_REMOVE
};
typedef int (Tcl_TraceTypeObjCmd)(Tcl_Interp *interp, enum traceOptionsEnum optionIndex,
Tcl_Size objc, Tcl_Obj *const objv[]);
static Tcl_TraceTypeObjCmd TraceVariableObjCmd;
static Tcl_TraceTypeObjCmd TraceCommandObjCmd;
static Tcl_TraceTypeObjCmd TraceExecutionObjCmd;
/*
* Each subcommand has a number of 'types' to which it can apply. Currently
|
| ︙ | ︙ | |||
121 122 123 124 125 126 127 | /* * Declarations for local functions to this file: */ static int CallTraceFunction(Tcl_Interp *interp, Trace *tracePtr, Command *cmdPtr, const char *command, Tcl_Size numChars, | | < | < < | < | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
/*
* Declarations for local functions to this file:
*/
static int CallTraceFunction(Tcl_Interp *interp, Trace *tracePtr,
Command *cmdPtr, const char *command, Tcl_Size numChars,
Tcl_Size objc, Tcl_Obj *const objv[]);
static char * TraceVarProc(void *clientData, Tcl_Interp *interp,
const char *name1, const char *name2, int flags);
static void TraceCommandProc(void *clientData,
Tcl_Interp *interp, const char *oldName,
const char *newName, int flags);
static Tcl_CmdObjTraceProc2 TraceExecutionProc;
static int StringTraceProc(void *clientData,
Tcl_Interp *interp, Tcl_Size level,
const char *command, Tcl_Command commandInfo,
Tcl_Size objc, Tcl_Obj *const objv[]);
static void StringTraceDeleteProc(void *clientData);
static void DisposeTraceResult(int flags, char *result);
static int TraceVarEx(Tcl_Interp *interp, const char *part1,
const char *part2, VarTrace *tracePtr);
/*
* The following structure holds the client data for string-based
* trace procs
*/
typedef struct {
void *clientData; /* Client data from Tcl_CreateTrace */
Tcl_CmdTraceProc *proc; /* Trace function from Tcl_CreateTrace */
} StringTraceData;
/*
* Convenience macros for iterating over the list of traces. Note that each of
* these *must* be treated as a command, and *must* have a block following it.
*/
#define FOREACH_VAR_TRACE(interp, name, clientData) \
|
| ︙ | ︙ | |||
189 190 191 192 193 194 195 |
*----------------------------------------------------------------------
*/
int
Tcl_TraceObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
*----------------------------------------------------------------------
*/
int
Tcl_TraceObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
/* Main sub commands to 'trace' */
static const char *const traceOptions[] = {
"add", "info", "remove",
NULL
};
enum traceOptionsEnum optionIndex;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
return TCL_ERROR;
}
if (Tcl_GetIndexFromObj(interp, objv[1], traceOptions, "option", 0,
|
| ︙ | ︙ | |||
280 281 282 283 284 285 286 |
*
*----------------------------------------------------------------------
*/
static int
TraceExecutionObjCmd(
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
*
*----------------------------------------------------------------------
*/
static int
TraceExecutionObjCmd(
Tcl_Interp *interp, /* Current interpreter. */
enum traceOptionsEnum optionIndex, /* Add, info or remove */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *name, *command;
Tcl_Size length;
static const char *const opStrings[] = {
"enter", "leave", "enterstep", "leavestep", NULL
};
enum operations {
|
| ︙ | ︙ | |||
531 532 533 534 535 536 537 |
*
*----------------------------------------------------------------------
*/
static int
TraceCommandObjCmd(
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
*
*----------------------------------------------------------------------
*/
static int
TraceCommandObjCmd(
Tcl_Interp *interp, /* Current interpreter. */
enum traceOptionsEnum optionIndex, /* Add, info or remove */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *name, *command;
Tcl_Size length;
static const char *const opStrings[] = { "delete", "rename", NULL };
enum operations { TRACE_CMD_DELETE, TRACE_CMD_RENAME } index;
switch (optionIndex) {
|
| ︙ | ︙ | |||
729 730 731 732 733 734 735 |
*
*----------------------------------------------------------------------
*/
static int
TraceVariableObjCmd(
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
*
*----------------------------------------------------------------------
*/
static int
TraceVariableObjCmd(
Tcl_Interp *interp, /* Current interpreter. */
enum traceOptionsEnum optionIndex, /* Add, info or remove */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *name, *command;
Tcl_Size length;
void *clientData;
static const char *const opStrings[] = {
"array", "read", "unset", "write", NULL
};
|
| ︙ | ︙ | |||
994 995 996 997 998 999 1000 |
* traced. */
const char *cmdName, /* Name of command. */
int flags, /* OR-ed collection of bits, including any of
* TCL_TRACE_RENAME, TCL_TRACE_DELETE, and any
* of the TRACE_*_EXEC flags */
Tcl_CommandTraceProc *proc, /* Function to call when specified ops are
* invoked upon cmdName. */
| | | 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 |
* traced. */
const char *cmdName, /* Name of command. */
int flags, /* OR-ed collection of bits, including any of
* TCL_TRACE_RENAME, TCL_TRACE_DELETE, and any
* of the TRACE_*_EXEC flags */
Tcl_CommandTraceProc *proc, /* Function to call when specified ops are
* invoked upon cmdName. */
void *clientData) /* Arbitrary argument to pass to proc. */
{
Command *cmdPtr;
CommandTrace *tracePtr;
cmdPtr = (Command *) Tcl_FindCommand(interp, cmdName, NULL,
TCL_LEAVE_ERR_MSG);
if (cmdPtr == NULL) {
|
| ︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 |
Tcl_UntraceCommand(
Tcl_Interp *interp, /* Interpreter containing command. */
const char *cmdName, /* Name of command. */
int flags, /* OR-ed collection of bits, including any of
* TCL_TRACE_RENAME, TCL_TRACE_DELETE, and any
* of the TRACE_*_EXEC flags */
Tcl_CommandTraceProc *proc, /* Function assocated with trace. */
| | | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 |
Tcl_UntraceCommand(
Tcl_Interp *interp, /* Interpreter containing command. */
const char *cmdName, /* Name of command. */
int flags, /* OR-ed collection of bits, including any of
* TCL_TRACE_RENAME, TCL_TRACE_DELETE, and any
* of the TRACE_*_EXEC flags */
Tcl_CommandTraceProc *proc, /* Function assocated with trace. */
void *clientData) /* Arbitrary argument to pass to proc. */
{
CommandTrace *tracePtr;
CommandTrace *prevPtr;
Command *cmdPtr;
Interp *iPtr = (Interp *)interp;
ActiveCommandTrace *activePtr;
int hasExecTraces = 0;
|
| ︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 | * Depends on the command associated with the trace. * *---------------------------------------------------------------------- */ static void TraceCommandProc( | | | 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 |
* Depends on the command associated with the trace.
*
*----------------------------------------------------------------------
*/
static void
TraceCommandProc(
void *clientData, /* Information about the command trace. */
Tcl_Interp *interp, /* Interpreter containing command. */
const char *oldName, /* Name of command being changed. */
const char *newName, /* New name of command. Empty string or NULL
* means command is being deleted (renamed to
* ""). */
int flags) /* OR-ed bits giving operation and other
* information. */
|
| ︙ | ︙ | |||
1307 1308 1309 1310 1311 1312 1313 |
Tcl_Interp *interp, /* The current interpreter. */
const char *command, /* Pointer to beginning of the current command
* string. */
TCL_UNUSED(Tcl_Size) /*numChars*/,
Command *cmdPtr, /* Points to command's Command struct. */
int code, /* The current result code. */
int traceFlags, /* Current tracing situation. */
| | | | 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 |
Tcl_Interp *interp, /* The current interpreter. */
const char *command, /* Pointer to beginning of the current command
* string. */
TCL_UNUSED(Tcl_Size) /*numChars*/,
Command *cmdPtr, /* Points to command's Command struct. */
int code, /* The current result code. */
int traceFlags, /* Current tracing situation. */
Tcl_Size objc, /* Number of arguments for the command. */
Tcl_Obj *const objv[]) /* Pointers to Tcl_Obj of each argument. */
{
Interp *iPtr = (Interp *) interp;
CommandTrace *tracePtr, *lastTracePtr;
ActiveCommandTrace active;
Tcl_Size curLevel;
int traceCode = TCL_OK;
Tcl_InterpState state = NULL;
|
| ︙ | ︙ | |||
1336 1337 1338 1339 1340 1341 1342 |
(traceCode == TCL_OK) && (tracePtr != NULL);
tracePtr = active.nextTracePtr) {
if (traceFlags & TCL_TRACE_LEAVE_EXEC) {
/*
* Execute the trace command in order of creation for "leave".
*/
| | | | 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 |
(traceCode == TCL_OK) && (tracePtr != NULL);
tracePtr = active.nextTracePtr) {
if (traceFlags & TCL_TRACE_LEAVE_EXEC) {
/*
* Execute the trace command in order of creation for "leave".
*/
active.reverseScan = 1;
active.nextTracePtr = NULL;
tracePtr = cmdPtr->tracePtr;
while (tracePtr->nextPtr != lastTracePtr) {
active.nextTracePtr = tracePtr;
tracePtr = tracePtr->nextPtr;
}
} else {
active.reverseScan = 0;
active.nextTracePtr = tracePtr->nextPtr;
}
if (tracePtr->traceProc == TraceCommandProc) {
TraceCommandInfo *tcmdPtr = (TraceCommandInfo *)tracePtr->clientData;
if (tcmdPtr->flags != 0) {
tcmdPtr->curFlags = traceFlags | TCL_TRACE_EXEC_DIRECT;
|
| ︙ | ︙ | |||
1413 1414 1415 1416 1417 1418 1419 |
const char *command, /* Pointer to beginning of the current command
* string. */
Tcl_Size numChars, /* The number of characters in 'command' which
* are part of the command string. */
Command *cmdPtr, /* Points to command's Command struct. */
int code, /* The current result code. */
int traceFlags, /* Current tracing situation. */
| | | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 |
const char *command, /* Pointer to beginning of the current command
* string. */
Tcl_Size numChars, /* The number of characters in 'command' which
* are part of the command string. */
Command *cmdPtr, /* Points to command's Command struct. */
int code, /* The current result code. */
int traceFlags, /* Current tracing situation. */
Tcl_Size objc, /* Number of arguments for the command. */
Tcl_Obj *const objv[]) /* Pointers to Tcl_Obj of each argument. */
{
Interp *iPtr = (Interp *) interp;
Trace *tracePtr, *lastTracePtr;
ActiveInterpTrace active;
Tcl_Size curLevel;
int traceCode = TCL_OK;
Tcl_InterpState state = NULL;
|
| ︙ | ︙ | |||
1447 1448 1449 1450 1451 1452 1453 | * "enterstep" operation. The order is changed for "enterstep" * instead of for "leavestep" as was done in * TclCheckExecutionTraces because for step traces, * Tcl_CreateObjTrace creates one more linked list of traces which * results in one more reversal of trace invocation. */ | | | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 |
* "enterstep" operation. The order is changed for "enterstep"
* instead of for "leavestep" as was done in
* TclCheckExecutionTraces because for step traces,
* Tcl_CreateObjTrace creates one more linked list of traces which
* results in one more reversal of trace invocation.
*/
active.reverseScan = 1;
active.nextTracePtr = NULL;
tracePtr = iPtr->tracePtr;
while (tracePtr->nextPtr != lastTracePtr) {
active.nextTracePtr = tracePtr;
tracePtr = tracePtr->nextPtr;
}
if (active.nextTracePtr) {
lastTracePtr = active.nextTracePtr->nextPtr;
}
} else {
active.reverseScan = 0;
active.nextTracePtr = tracePtr->nextPtr;
}
if (tracePtr->level > 0 && curLevel > tracePtr->level) {
continue;
}
|
| ︙ | ︙ | |||
1551 1552 1553 1554 1555 1556 1557 |
*
*----------------------------------------------------------------------
*/
static int
CallTraceFunction(
Tcl_Interp *interp, /* The current interpreter. */
| | | | 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 |
*
*----------------------------------------------------------------------
*/
static int
CallTraceFunction(
Tcl_Interp *interp, /* The current interpreter. */
Trace *tracePtr, /* Describes the trace function to call. */
Command *cmdPtr, /* Points to command's Command struct. */
const char *command, /* Points to the first character of the
* command's source before substitutions. */
Tcl_Size numChars, /* The number of characters in the command's
* source. */
Tcl_Size objc, /* Number of arguments for the command. */
Tcl_Obj *const objv[]) /* Pointers to Tcl_Obj of each argument. */
{
Interp *iPtr = (Interp *) interp;
char *commandCopy;
int traceCode;
/*
* Copy the command characters into a new string.
|
| ︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 |
TraceExecutionProc(
void *clientData,
Tcl_Interp *interp,
Tcl_Size level,
const char *command,
TCL_UNUSED(Tcl_Command),
Tcl_Size objc,
| | | 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 |
TraceExecutionProc(
void *clientData,
Tcl_Interp *interp,
Tcl_Size level,
const char *command,
TCL_UNUSED(Tcl_Command),
Tcl_Size objc,
Tcl_Obj *const objv[])
{
int call = 0;
Interp *iPtr = (Interp *) interp;
TraceCommandInfo *tcmdPtr = (TraceCommandInfo *)clientData;
int flags = tcmdPtr->curFlags;
int code = tcmdPtr->curCode;
int traceCode = TCL_OK;
|
| ︙ | ︙ | |||
1800 1801 1802 1803 1804 1805 1806 |
* string in startLevel and startCmd so that we can delete this
* interpreter trace when it reaches the end of this proc.
*/
if ((flags & TCL_TRACE_ENTER_EXEC) && (tcmdPtr->stepTrace == NULL)
&& (tcmdPtr->flags & (TCL_TRACE_ENTER_DURING_EXEC |
TCL_TRACE_LEAVE_DURING_EXEC))) {
| | | | | 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 |
* string in startLevel and startCmd so that we can delete this
* interpreter trace when it reaches the end of this proc.
*/
if ((flags & TCL_TRACE_ENTER_EXEC) && (tcmdPtr->stepTrace == NULL)
&& (tcmdPtr->flags & (TCL_TRACE_ENTER_DURING_EXEC |
TCL_TRACE_LEAVE_DURING_EXEC))) {
unsigned len = strlen(command) + 1;
tcmdPtr->startLevel = level;
tcmdPtr->startCmd = (char *)Tcl_Alloc(len);
memcpy(tcmdPtr->startCmd, command, len);
tcmdPtr->refCount++;
tcmdPtr->stepTrace = Tcl_CreateObjTrace2(interp, 0,
(tcmdPtr->flags & TCL_TRACE_ANY_EXEC) >> 2,
TraceExecutionProc, tcmdPtr, CommandObjTraceDeleted);
}
}
if (flags & TCL_TRACE_DESTROYED) {
if (tcmdPtr->stepTrace != NULL) {
Tcl_DeleteTrace(interp, tcmdPtr->stepTrace);
tcmdPtr->stepTrace = NULL;
Tcl_Free(tcmdPtr->startCmd);
|
| ︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | * Depends on the command associated with the trace. * *---------------------------------------------------------------------- */ static char * TraceVarProc( | | | 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 |
* Depends on the command associated with the trace.
*
*----------------------------------------------------------------------
*/
static char *
TraceVarProc(
void *clientData, /* Information about the variable trace. */
Tcl_Interp *interp, /* Interpreter containing variable. */
const char *name1, /* Name of variable or array. */
const char *name2, /* Name of element within array; NULL means
* scalar variable is being referenced. */
int flags) /* OR-ed bits giving operation and other
* information. */
{
|
| ︙ | ︙ | |||
1958 1959 1960 1961 1962 1963 1964 | * * void proc(void * clientData, * Tcl_Interp * interp, * int level, * const char * command, * Tcl_Command commandInfo, * int objc, | | | 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 | * * void proc(void * clientData, * Tcl_Interp * interp, * int level, * const char * command, * Tcl_Command commandInfo, * int objc, * Tcl_Obj *const objv[]); * * The 'clientData' and 'interp' arguments to 'proc' will be the same as * the arguments to Tcl_CreateObjTrace. The 'level' argument gives the * nesting depth of command interpretation within the interpreter. The * 'command' argument is the ASCII text of the command being evaluated - * before any substitutions are performed. The 'commandInfo' argument * gives a handle to the command procedure that will be evaluated. The |
| ︙ | ︙ | |||
1991 1992 1993 1994 1995 1996 1997 | * * When the trace is deleted, the 'delProc' function will be invoked, * passing it the original client data. * *---------------------------------------------------------------------- */ | < | | | | < | < | | | | < | | | 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 |
*
* When the trace is deleted, the 'delProc' function will be invoked,
* passing it the original client data.
*
*----------------------------------------------------------------------
*/
typedef struct {
Tcl_CmdObjTraceProc *proc;
Tcl_CmdObjTraceDeleteProc *delProc;
void *clientData;
} TraceWrapperInfo;
static int
traceWrapperProc(
void *clientData,
Tcl_Interp *interp,
Tcl_Size level,
const char *command,
Tcl_Command commandInfo,
Tcl_Size objc,
Tcl_Obj *const objv[])
{
TraceWrapperInfo *info = (TraceWrapperInfo *)clientData;
if (objc > INT_MAX) {
objc = -1; /* Signal Tcl_CmdObjTraceProc that objc is out of range */
}
return info->proc(info->clientData, interp, (int)level, command, commandInfo, objc, objv);
}
static void
traceWrapperDelProc(
void *clientData)
{
TraceWrapperInfo *info = (TraceWrapperInfo *)clientData;
clientData = info->clientData;
if (info->delProc) {
info->delProc(clientData);
}
Tcl_Free(info);
}
Tcl_Trace
Tcl_CreateObjTrace(
Tcl_Interp *interp, /* Tcl interpreter */
Tcl_Size level, /* Maximum nesting level */
int flags, /* Flags, see above */
Tcl_CmdObjTraceProc *proc, /* Trace callback */
void *clientData, /* Client data for the callback */
Tcl_CmdObjTraceDeleteProc *delProc)
/* Function to call when trace is deleted */
{
TraceWrapperInfo *info = (TraceWrapperInfo *)Tcl_Alloc(sizeof(TraceWrapperInfo));
info->proc = proc;
info->delProc = delProc;
info->clientData = clientData;
return Tcl_CreateObjTrace2(interp, level, flags,
(proc ? traceWrapperProc : NULL),
info, traceWrapperDelProc);
}
Tcl_Trace
Tcl_CreateObjTrace2(
Tcl_Interp *interp, /* Tcl interpreter */
Tcl_Size level, /* Maximum nesting level */
int flags, /* Flags, see above */
Tcl_CmdObjTraceProc2 *proc, /* Trace callback */
void *clientData, /* Client data for the callback */
Tcl_CmdObjTraceDeleteProc *delProc)
/* Function to call when trace is deleted */
{
Trace *tracePtr;
Interp *iPtr = (Interp *) interp;
/*
|
| ︙ | ︙ | |||
2138 2139 2140 2141 2142 2143 2144 | * command and the ClientData value it will receive, and argc and argv * give the arguments to the command, after any argument parsing and * substitution. Proc does not return a value. * *---------------------------------------------------------------------- */ | < | | | 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 |
* command and the ClientData value it will receive, and argc and argv
* give the arguments to the command, after any argument parsing and
* substitution. Proc does not return a value.
*
*----------------------------------------------------------------------
*/
Tcl_Trace
Tcl_CreateTrace(
Tcl_Interp *interp, /* Interpreter in which to create trace. */
Tcl_Size level, /* Only call proc for commands at nesting
* level<=argument level (1=>top level). */
Tcl_CmdTraceProc *proc, /* Function to call before executing each
* command. */
void *clientData) /* Arbitrary value word to pass to proc. */
{
StringTraceData *data = (StringTraceData *)Tcl_Alloc(sizeof(StringTraceData));
data->clientData = clientData;
data->proc = proc;
return Tcl_CreateObjTrace2(interp, level, 0, StringTraceProc,
data, StringTraceDeleteProc);
|
| ︙ | ︙ | |||
2205 2206 2207 2208 2209 2210 2211 |
/*
* Invoke the command function. Note that we cast away const-ness on two
* parameters for compatibility with legacy code; the code MUST NOT modify
* either command or argv.
*/
| | | | 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 |
/*
* Invoke the command function. Note that we cast away const-ness on two
* parameters for compatibility with legacy code; the code MUST NOT modify
* either command or argv.
*/
data->proc(data->clientData, interp, level, (char *) command,
cmdPtr->proc, cmdPtr->clientData, objc, argv);
TclStackFree(interp, (void *) argv);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
2234 2235 2236 2237 2238 2239 2240 |
static void
StringTraceDeleteProc(
void *clientData)
{
Tcl_Free(clientData);
}
| < | 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 |
static void
StringTraceDeleteProc(
void *clientData)
{
Tcl_Free(clientData);
}
/*
*----------------------------------------------------------------------
*
* Tcl_DeleteTrace --
*
* Remove a trace.
|
| ︙ | ︙ | |||
2412 2413 2414 2415 2416 2417 2418 |
int
TclCheckArrayTraces(
Tcl_Interp *interp,
Var *varPtr,
Var *arrayPtr,
Tcl_Obj *name,
| | | 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 |
int
TclCheckArrayTraces(
Tcl_Interp *interp,
Var *varPtr,
Var *arrayPtr,
Tcl_Obj *name,
int index)
{
int code = TCL_OK;
if (varPtr && (varPtr->flags & VAR_TRACED_ARRAY)
&& (TclIsVarArray(varPtr) || TclIsVarUndefined(varPtr))) {
Interp *iPtr = (Interp *)interp;
|
| ︙ | ︙ | |||
2453 2454 2455 2456 2457 2458 2459 |
*
*----------------------------------------------------------------------
*/
int
TclObjCallVarTraces(
Interp *iPtr, /* Interpreter containing variable. */
| | | | 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 |
*
*----------------------------------------------------------------------
*/
int
TclObjCallVarTraces(
Interp *iPtr, /* Interpreter containing variable. */
Var *arrayPtr, /* Pointer to array variable that contains the
* variable, or NULL if the variable isn't an
* element of an array. */
Var *varPtr, /* Variable whose traces are to be invoked. */
Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr, /* Variable's two-part name. */
int flags, /* Flags passed to trace functions: indicates
* what's happening to variable, plus maybe
* TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY */
int leaveErrMsg, /* If true, and one of the traces indicates an
* error, then leave an error message and
* stack trace information in *iPTr. */
int index) /* Index into the local variable table of the
* variable, or -1. Only used when part1Ptr is
* NULL. */
{
const char *part1, *part2;
if (!part1Ptr) {
part1Ptr = localName(iPtr->varFramePtr, index);
|
| ︙ | ︙ | |||
2487 2488 2489 2490 2491 2492 2493 |
return TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, flags,
leaveErrMsg);
}
int
TclCallVarTraces(
Interp *iPtr, /* Interpreter containing variable. */
| | | 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 |
return TclCallVarTraces(iPtr, arrayPtr, varPtr, part1, part2, flags,
leaveErrMsg);
}
int
TclCallVarTraces(
Interp *iPtr, /* Interpreter containing variable. */
Var *arrayPtr, /* Pointer to array variable that contains the
* variable, or NULL if the variable isn't an
* element of an array. */
Var *varPtr, /* Variable whose traces are to be invoked. */
const char *part1,
const char *part2, /* Variable's two-part name. */
int flags, /* Flags passed to trace functions: indicates
* what's happening to variable, plus maybe
|
| ︙ | ︙ | |||
2547 2548 2549 2550 2551 2552 2553 |
if (*p == '(') {
openParen = p;
do {
p++;
} while (*p != '\0');
p--;
if (*p == ')') {
| | | 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 |
if (*p == '(') {
openParen = p;
do {
p++;
} while (*p != '\0');
p--;
if (*p == ')') {
int offset = (openParen - part1);
char *newPart1;
Tcl_DStringInit(&nameCopy);
Tcl_DStringAppend(&nameCopy, part1, p-part1);
newPart1 = Tcl_DStringValue(&nameCopy);
newPart1[offset] = 0;
part1 = newPart1;
|
| ︙ | ︙ | |||
2795 2796 2797 2798 2799 2800 2801 |
* trace applies to scalar variable or array
* as-a-whole. */
int flags, /* OR-ed collection of bits describing current
* trace, including any of TCL_TRACE_READS,
* TCL_TRACE_WRITES, TCL_TRACE_UNSETS,
* TCL_GLOBAL_ONLY, and TCL_NAMESPACE_ONLY. */
Tcl_VarTraceProc *proc, /* Function associated with trace. */
| | | 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 |
* trace applies to scalar variable or array
* as-a-whole. */
int flags, /* OR-ed collection of bits describing current
* trace, including any of TCL_TRACE_READS,
* TCL_TRACE_WRITES, TCL_TRACE_UNSETS,
* TCL_GLOBAL_ONLY, and TCL_NAMESPACE_ONLY. */
Tcl_VarTraceProc *proc, /* Function associated with trace. */
void *clientData) /* Arbitrary argument to pass to proc. */
{
VarTrace *tracePtr;
VarTrace *prevPtr, *nextPtr;
Var *varPtr, *arrayPtr;
Interp *iPtr = (Interp *) interp;
ActiveVarTrace *activePtr;
int flagMask, allFlags = 0;
|
| ︙ | ︙ | |||
2823 2824 2825 2826 2827 2828 2829 |
/*
* Set up a mask to mask out the parts of the flags that we are not
* interested in now.
*/
flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
| | | 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 |
/*
* Set up a mask to mask out the parts of the flags that we are not
* interested in now.
*/
flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
TCL_TRACE_ARRAY | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT;
flags &= flagMask;
hPtr = Tcl_FindHashEntry(&iPtr->varTraces, varPtr);
for (tracePtr = (VarTrace *)Tcl_GetHashValue(hPtr), prevPtr = NULL; ;
prevPtr = tracePtr, tracePtr = tracePtr->nextPtr) {
if (tracePtr == NULL) {
goto updateFlags;
|
| ︙ | ︙ | |||
2998 2999 3000 3001 3002 3003 3004 |
* as-a-whole. */
int flags, /* OR-ed collection of bits, including any of
* TCL_TRACE_READS, TCL_TRACE_WRITES,
* TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, and
* TCL_NAMESPACE_ONLY. */
Tcl_VarTraceProc *proc, /* Function to call when specified ops are
* invoked upon varName. */
| | | 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 |
* as-a-whole. */
int flags, /* OR-ed collection of bits, including any of
* TCL_TRACE_READS, TCL_TRACE_WRITES,
* TCL_TRACE_UNSETS, TCL_GLOBAL_ONLY, and
* TCL_NAMESPACE_ONLY. */
Tcl_VarTraceProc *proc, /* Function to call when specified ops are
* invoked upon varName. */
void *clientData) /* Arbitrary argument to pass to proc. */
{
VarTrace *tracePtr;
int result;
tracePtr = (VarTrace *)Tcl_Alloc(sizeof(VarTrace));
tracePtr->traceProc = proc;
tracePtr->clientData = clientData;
|
| ︙ | ︙ | |||
3087 3088 3089 3090 3091 3092 3093 |
}
/*
* Set up trace information.
*/
flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
| | | 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 |
}
/*
* Set up trace information.
*/
flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS |
TCL_TRACE_ARRAY | TCL_TRACE_RESULT_DYNAMIC | TCL_TRACE_RESULT_OBJECT;
tracePtr->flags = tracePtr->flags & flagMask;
hPtr = Tcl_CreateHashEntry(&iPtr->varTraces, varPtr, &isNew);
if (isNew) {
tracePtr->nextPtr = NULL;
} else {
tracePtr->nextPtr = (VarTrace *)Tcl_GetHashValue(hPtr);
|
| ︙ | ︙ |
Added generic/tclUniData.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 |
/*
* tclUniData.c --
*
* Declarations of Unicode character information tables. This file is
* automatically generated by the tools/uniParse.tcl script. Do not
* modify this file by hand.
*
* Copyright © 1998 Scriptics Corporation.
* All rights reserved.
*/
/*
* A 16-bit Unicode character is split into two parts in order to index
* into the following tables. The lower OFFSET_BITS comprise an offset
* into a page of characters. The upper bits comprise the page number.
*/
#define OFFSET_BITS 5
/*
* The pageMap is indexed by page number and returns an alternate page number
* that identifies a unique page of characters. Many Unicode characters map
* to the same alternate page number.
*/
static const unsigned short pageMap[] = {
0, 32, 64, 96, 0, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416,
448, 224, 480, 512, 544, 576, 608, 640, 672, 704, 704, 736, 768, 800,
832, 864, 896, 928, 960, 992, 224, 1024, 224, 1056, 224, 224, 1088,
1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1344, 1344,
1440, 1472, 1504, 1536, 1568, 1344, 1344, 1600, 1632, 1664, 1696, 1728,
1760, 1792, 1824, 1344, 1856, 1888, 1920, 1952, 1984, 2016, 2048, 2080,
2112, 2144, 2176, 2208, 2240, 2272, 2304, 2336, 2368, 2400, 2432, 2464,
2496, 2528, 2560, 2592, 2624, 2656, 2688, 2720, 2752, 2784, 2816, 2848,
2880, 2912, 2944, 2976, 3008, 3040, 3072, 3104, 3136, 3168, 3200, 3232,
3264, 3296, 3328, 3360, 3392, 3296, 3424, 3456, 3488, 3520, 3552, 3584,
3616, 3296, 1344, 3648, 3680, 3712, 3744, 3776, 3808, 3840, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 3872, 1344, 3904, 3936,
3968, 1344, 4000, 1344, 4032, 4064, 4096, 4128, 4128, 4160, 4192, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 4224, 4256, 1344, 1344, 4288, 4320, 4352,
4384, 4416, 1344, 4448, 4480, 4512, 4544, 1344, 4576, 4608, 4640, 4672,
1344, 4704, 4736, 4768, 4800, 4832, 1344, 4864, 4896, 4928, 4960, 1344,
4992, 5024, 5056, 5088, 5120, 5152, 5184, 5216, 5248, 5280, 5312, 5344,
1344, 5376, 1344, 5408, 5440, 5472, 5504, 5536, 5568, 5600, 5632, 5664,
5696, 5728, 5760, 5696, 704, 704, 224, 224, 224, 224, 5792, 224, 224,
224, 5824, 5856, 5888, 5920, 5952, 5984, 6016, 6048, 6080, 6112, 6144,
6176, 6208, 6240, 6272, 6304, 6336, 6368, 6400, 6432, 6464, 6496, 6528,
6560, 6592, 6592, 6592, 6592, 6592, 6592, 6592, 6592, 6624, 6656, 4928,
6688, 6720, 6752, 6784, 6816, 4928, 6848, 6880, 6912, 6944, 6976, 7008,
7040, 4928, 4928, 4928, 4928, 4928, 7072, 7104, 7136, 4928, 4928, 4928,
7168, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 7200, 7232, 4928, 7264,
7296, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 6592, 6592, 6592,
6592, 7328, 6592, 7360, 7392, 6592, 6592, 6592, 6592, 6592, 6592, 6592,
6592, 4928, 7424, 7456, 7488, 4928, 4928, 4928, 4928, 7520, 7552, 7584,
7616, 224, 224, 224, 7648, 7680, 7712, 1344, 7744, 7776, 7808, 7808,
704, 7840, 7872, 7904, 3296, 7936, 4928, 4928, 7968, 4928, 4928, 4928,
4928, 4928, 4928, 8000, 8032, 8064, 8096, 3200, 1344, 8128, 4192, 1344,
8160, 8192, 8224, 1344, 1344, 8256, 1344, 4928, 8288, 8320, 8352, 8384,
4928, 8352, 8416, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928,
4928, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 4928, 4928, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 8448, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 8480, 4928, 8512, 5472, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 8544, 8576, 224, 8608, 8640, 1344, 1344, 8672, 8704, 8736, 224,
8768, 8800, 8832, 8864, 8896, 8928, 8960, 1344, 8992, 9024, 9056, 9088,
9120, 1632, 9152, 9184, 9216, 1920, 9248, 9280, 9312, 1344, 9344, 9376,
9408, 1344, 9440, 9472, 9504, 9536, 9568, 9600, 9632, 9664, 9664, 1344,
9696, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 9728, 9760, 9792, 9824, 9824, 9824, 9824, 9824, 9824, 9824,
9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824,
9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824,
9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824,
9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824,
9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9824, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856, 9856,
9856, 9856, 9856, 9856, 9856, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 9888, 1344, 1344, 9920, 3296, 9952, 9984, 10016,
1344, 1344, 10048, 10080, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 10112, 10144, 1344, 10176, 1344, 10208, 10240, 10272,
10304, 10336, 10368, 1344, 1344, 1344, 10400, 10432, 64, 10464, 10496,
10528, 4736, 10560, 10592
#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8
,10624, 10656, 10688, 3296, 1344, 1344, 1344, 10720, 10752, 10784,
10816, 10848, 10880, 10912, 8032, 10944, 3296, 3296, 3296, 3296, 9216,
1344, 10976, 11008, 1344, 11040, 11072, 11104, 11136, 1344, 11168,
3296, 11200, 11232, 11264, 1344, 11296, 11328, 11360, 11392, 1344,
11424, 1344, 11456, 11488, 11520, 1344, 11552, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 7776, 4704, 11584, 11616, 11648, 3296,
3296, 11680, 11712, 11744, 11776, 4736, 11808, 3296, 11840, 11872,
11904, 9920, 3296, 1344, 11936, 11968, 6912, 12000, 12032, 12064, 12096,
12128, 3296, 12160, 12192, 1344, 12224, 12256, 12288, 12320, 12352,
3296, 3296, 1344, 1344, 12384, 3296, 12416, 12448, 12480, 12512, 1344,
12544, 12576, 12608, 12640, 3296, 3296, 3296, 3296, 3296, 3296, 12672,
1344, 12704, 12736, 12768, 12128, 12800, 12832, 12864, 12896, 12864,
12928, 7776, 12960, 12992, 13024, 13056, 5312, 13088, 13120, 13152,
13184, 13216, 13248, 13280, 5312, 13312, 13344, 13376, 13408, 13440,
13472, 3296, 13504, 13536, 13568, 13600, 13632, 13664, 13696, 13728,
13760, 13792, 13824, 13856, 1344, 13888, 13920, 13952, 1344, 13984,
14016, 3296, 3296, 3296, 3296, 3296, 1344, 14048, 14080, 3296, 1344,
14112, 14144, 14176, 1344, 14208, 14240, 14272, 14304, 14336, 14368,
3296, 3296, 3296, 3296, 3296, 1344, 14400, 3296, 3296, 3296, 14432,
14464, 14496, 14528, 14560, 14592, 3296, 3296, 14624, 14656, 14688,
14720, 14752, 14784, 1344, 14816, 14848, 1344, 4608, 14880, 3296, 3296,
14912, 3296, 3296, 1344, 14944, 14976, 15008, 15040, 15072, 15104,
15136, 3296, 3296, 15168, 15200, 15232, 15264, 15296, 15328, 15360,
15392, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 15424, 15456, 15488,
15520, 3296, 3296, 15552, 15584, 15616, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9920,
3296, 3296, 3296, 10816, 10816, 10816, 15648, 1344, 1344, 1344, 1344,
1344, 1344, 15680, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 12864, 1344, 1344, 15712, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 15744, 15776, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 10720,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 14368, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 15808, 15840, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 4608, 4736, 15872, 1344,
4736, 15328, 15904, 1344, 15936, 15968, 16000, 16032, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 16064,
16096, 3296, 3296, 3296, 3296, 3296, 3296, 14432, 14464, 16128, 16160,
16192, 3296, 1344, 1344, 16224, 16256, 16288, 3296, 3296, 16320, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 4704, 16352, 4736, 3296, 3296, 3296, 1344, 1344, 1344, 16384,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 16416, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 16448, 16480, 16512, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9792, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344,
1344, 16544, 16576, 16608, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 4928, 4928, 4928, 4928, 4928,
4928, 4928, 16640, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928,
4928, 4928, 4928, 4928, 4928, 16672, 16704, 16736, 704, 16768, 16800,
4928, 4928, 4928, 16832, 3296, 4928, 4928, 4928, 4928, 4928, 4928,
4928, 8000, 4928, 16864, 4928, 16896, 16928, 16960, 4928, 6880, 4928,
4928, 16992, 3296, 3296, 3296, 17024, 17024, 4928, 4928, 17056, 17088,
3296, 3296, 3296, 3296, 17120, 17152, 17184, 17216, 17248, 17280, 17312,
17344, 17376, 17408, 17440, 17472, 17504, 17120, 17152, 17536, 17216,
17568, 17600, 17632, 17344, 17664, 17696, 17728, 17760, 17792, 17824,
17856, 17888, 17920, 17952, 17984, 4928, 4928, 4928, 4928, 4928, 4928,
4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 704, 18016,
704, 18048, 18080, 18112, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 18144, 18176, 3296, 3296, 3296, 3296, 3296, 3296,
18208, 18240, 5696, 18272, 18304, 3296, 3296, 3296, 1344, 18336, 18368,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 12864, 18400,
1344, 18432, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 12864, 18464, 3296, 3296, 3296, 3296,
3296, 3296, 12864, 18496, 3296, 3296, 3296, 3296, 3296, 3296, 4736,
18528, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 18560, 1344, 1344,
1344, 1344, 1344, 1344, 18592, 3296, 18624, 18656, 18688, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 18720,
6912, 18752, 3296, 3296, 18784, 18816, 3296, 3296, 3296, 3296, 3296,
3296, 18848, 18880, 18912, 18944, 18976, 19008, 3296, 19040, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 4928, 19072, 4928, 4928,
7968, 19104, 19136, 8000, 19168, 4928, 4928, 4928, 4928, 19200, 3296,
19232, 19264, 19296, 19328, 19360, 3296, 3296, 3296, 3296, 4928, 4928,
4928, 4928, 4928, 4928, 4928, 19392, 4928, 4928, 4928, 4928, 4928,
4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928,
4928, 4928, 4928, 4928, 4928, 19424, 19456, 4928, 4928, 4928, 4928,
4928, 4928, 19488, 19520, 19072, 4928, 19552, 4928, 19584, 19616, 19648,
3296, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 4928, 19680,
19712, 19744, 4928, 19776, 19808, 4928, 4928, 4928, 4928, 19840, 4928,
4928, 19872, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 11296, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9888, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 19904, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 11296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 11296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296,
3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 3296, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1792, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344,
1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 1344, 9920
#endif /* TCL_UTF_MAX > 3 */
};
/*
* The groupMap is indexed by combining the alternate page number with
* the page offset and returns a group number that identifies a unique
* set of character attributes.
*/
static const unsigned char groupMap[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 4, 3, 3, 3, 5, 6, 3, 7, 3, 8,
3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 7, 7, 7, 3, 3, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 5, 3, 6, 11, 12, 11, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 5, 7, 6, 7, 1, 2, 3, 4, 4, 4, 4, 14, 3, 11, 14, 15, 16,
7, 17, 14, 11, 14, 7, 18, 18, 11, 19, 3, 3, 11, 18, 15, 20, 18, 18,
18, 3, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 7, 10, 10, 10, 10, 10, 10, 10, 21,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 7, 13, 13, 13, 13, 13, 13, 13, 22, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 25, 26, 23, 24, 23,
24, 23, 24, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 27,
23, 24, 23, 24, 23, 24, 28, 29, 30, 23, 24, 23, 24, 31, 23, 24, 32,
32, 23, 24, 21, 33, 34, 35, 23, 24, 32, 36, 37, 38, 39, 23, 24, 40,
41, 38, 42, 43, 44, 23, 24, 23, 24, 23, 24, 45, 23, 24, 45, 21, 21,
23, 24, 45, 23, 24, 46, 46, 23, 24, 23, 24, 47, 23, 24, 21, 15, 23,
24, 21, 48, 15, 15, 15, 15, 49, 50, 51, 49, 50, 51, 49, 50, 51, 23,
24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 52, 23,
24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
21, 49, 50, 51, 23, 24, 53, 54, 23, 24, 23, 24, 23, 24, 23, 24, 55,
21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 21, 21, 21, 21, 21, 21, 56, 23, 24, 57, 58, 59, 59, 23, 24,
60, 61, 62, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 63, 64, 65, 66,
67, 21, 68, 68, 21, 69, 21, 70, 71, 21, 21, 21, 68, 72, 21, 73, 74,
75, 76, 21, 77, 78, 76, 79, 80, 21, 21, 78, 21, 81, 82, 21, 21, 83,
21, 21, 21, 21, 21, 21, 21, 84, 21, 21, 85, 21, 86, 85, 21, 21, 21,
87, 85, 88, 89, 89, 90, 21, 21, 21, 21, 21, 91, 21, 15, 15, 21, 21,
21, 21, 21, 21, 21, 92, 93, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94, 11, 11, 11, 11, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 94, 94, 94, 94, 94, 11, 11, 11, 11, 11, 11, 11, 94,
11, 94, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 96, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 23, 24, 23,
24, 94, 11, 23, 24, 0, 0, 94, 43, 43, 43, 3, 97, 0, 0, 0, 0, 11, 11,
98, 3, 99, 99, 99, 0, 100, 0, 101, 101, 21, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10,
10, 10, 10, 10, 102, 103, 103, 103, 21, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 104, 13, 13, 13, 13, 13, 13,
13, 13, 13, 105, 106, 106, 107, 108, 109, 110, 110, 110, 111, 112,
113, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 114, 115, 116, 117, 118, 119, 7, 23,
24, 120, 23, 24, 21, 55, 55, 55, 121, 121, 121, 121, 121, 121, 121,
121, 121, 121, 121, 121, 121, 121, 121, 121, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 115, 115, 115, 115, 115, 115, 115, 115,
115, 115, 115, 115, 115, 115, 115, 115, 23, 24, 14, 95, 95, 95, 95,
95, 122, 122, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 123, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 124, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 0, 125, 125, 125, 125, 125, 125, 125, 125, 125,
125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
125, 0, 0, 94, 3, 3, 3, 3, 3, 3, 21, 126, 126, 126, 126, 126, 126,
126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
126, 126, 126, 126, 21, 21, 3, 8, 0, 0, 14, 14, 4, 0, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 8, 95, 3, 95, 95, 3, 95, 95, 3, 95, 0,
0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0,
0, 15, 15, 15, 15, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17,
17, 17, 17, 7, 7, 7, 3, 3, 4, 3, 3, 14, 14, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 3, 17, 3, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 94, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 15, 15,
95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 3, 15, 95, 95, 95, 95, 95, 95, 95, 17, 14, 95, 95, 95, 95,
95, 95, 94, 94, 95, 95, 14, 95, 95, 95, 95, 15, 15, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 15, 15, 15, 14, 14, 15, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 0, 17, 15, 95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 0, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 15,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
95, 95, 95, 95, 95, 95, 95, 95, 95, 94, 94, 14, 3, 3, 3, 94, 0, 0,
95, 4, 4, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 94, 95, 95, 95, 95, 95,
95, 95, 95, 95, 94, 95, 95, 95, 94, 95, 95, 95, 95, 95, 0, 0, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 95, 95, 95, 0, 0, 3, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 11, 15, 15, 15, 15,
15, 15, 15, 17, 17, 0, 0, 0, 0, 0, 95, 95, 95, 95, 95, 95, 95, 95,
95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 94, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 17, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
127, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 95, 127, 95, 15, 127, 127, 127, 95, 95, 95, 95, 95,
95, 95, 95, 127, 127, 127, 127, 95, 127, 127, 15, 95, 95, 95, 95, 95,
95, 95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 3, 3, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 3, 94, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 95, 127, 127, 0, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15,
15, 15, 0, 15, 0, 0, 0, 15, 15, 15, 15, 0, 0, 95, 15, 127, 127, 127,
95, 95, 95, 95, 0, 0, 127, 127, 0, 0, 127, 127, 95, 15, 0, 0, 0, 0,
0, 0, 0, 0, 127, 0, 0, 0, 0, 15, 15, 0, 15, 15, 15, 95, 95, 0, 0, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 4, 4, 18, 18, 18, 18, 18, 18, 14,
4, 15, 3, 95, 0, 0, 95, 95, 127, 0, 15, 15, 15, 15, 15, 15, 0, 0, 0,
0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15,
0, 15, 15, 0, 15, 15, 0, 15, 15, 0, 0, 95, 0, 127, 127, 127, 95, 95,
0, 0, 0, 0, 95, 95, 0, 0, 95, 95, 95, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0,
0, 15, 15, 15, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 95, 95, 15, 15, 15, 95, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95,
95, 127, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15,
15, 15, 15, 0, 0, 95, 15, 127, 127, 127, 95, 95, 95, 95, 95, 0, 95,
95, 127, 0, 127, 127, 95, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 15, 15, 95, 95, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3,
4, 0, 0, 0, 0, 0, 0, 0, 15, 95, 95, 95, 95, 95, 95, 0, 95, 127, 127,
0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 0, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15,
15, 0, 0, 95, 15, 127, 95, 127, 95, 95, 95, 95, 0, 0, 127, 127, 0,
0, 127, 127, 95, 0, 0, 0, 0, 0, 0, 0, 95, 95, 127, 0, 0, 0, 0, 15,
15, 0, 15, 15, 15, 95, 95, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 14,
15, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 15, 0,
15, 15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 0, 15, 15, 15, 15, 0,
0, 0, 15, 15, 0, 15, 0, 15, 15, 0, 0, 0, 15, 15, 0, 0, 0, 15, 15, 15,
0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0,
127, 127, 95, 127, 127, 0, 0, 0, 127, 127, 127, 0, 127, 127, 127, 95,
0, 0, 15, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 14, 14, 14, 14, 14,
14, 4, 14, 0, 0, 0, 0, 0, 95, 127, 127, 127, 95, 15, 15, 15, 15, 15,
15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 95, 15, 95,
95, 95, 127, 127, 127, 127, 0, 95, 95, 95, 0, 95, 95, 95, 95, 0, 0,
0, 0, 0, 0, 0, 95, 95, 0, 15, 15, 15, 0, 15, 15, 0, 0, 15, 15, 95,
95, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 3, 18,
18, 18, 18, 18, 18, 18, 14, 15, 95, 127, 127, 3, 15, 15, 15, 15, 15,
15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 0, 0, 95, 15, 127,
95, 127, 127, 127, 127, 127, 0, 95, 127, 127, 0, 127, 127, 95, 95,
0, 0, 0, 0, 0, 0, 0, 127, 127, 0, 0, 0, 0, 0, 15, 15, 15, 0, 15, 15,
95, 95, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 15, 15, 127, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 95, 127, 127, 15, 15, 15, 15, 15, 15,
15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 15,
127, 127, 127, 95, 95, 95, 95, 0, 127, 127, 127, 0, 127, 127, 127,
95, 15, 14, 0, 0, 0, 0, 15, 15, 15, 127, 18, 18, 18, 18, 18, 18, 18,
15, 15, 15, 95, 95, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18,
18, 18, 18, 18, 18, 18, 14, 15, 15, 15, 15, 15, 15, 0, 95, 127, 127,
0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 0, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 95,
0, 0, 0, 0, 127, 127, 127, 95, 95, 95, 0, 95, 0, 127, 127, 127, 127,
127, 127, 127, 127, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
0, 0, 127, 127, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 15, 15, 95, 95, 95,
95, 95, 95, 95, 0, 0, 0, 0, 4, 15, 15, 15, 15, 15, 15, 94, 95, 95,
95, 95, 95, 95, 95, 95, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 0, 15, 0, 15, 15, 15, 15,
15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 95, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 95, 15,
0, 0, 15, 15, 15, 15, 15, 0, 94, 0, 95, 95, 95, 95, 95, 95, 95, 0,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 15, 15, 15, 15, 15, 14, 14, 14,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 14, 14, 14, 95,
95, 14, 14, 14, 14, 14, 14, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 14, 95, 14, 95, 14, 95, 5, 6, 5, 6, 127,
127, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 127, 95, 95, 95, 95,
95, 3, 95, 95, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 0, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 0, 14, 14, 14, 14, 14, 14, 14, 14, 95, 14,
14, 14, 14, 14, 14, 0, 14, 14, 3, 3, 3, 3, 3, 14, 14, 14, 14, 3, 3,
0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127,
95, 95, 95, 95, 127, 95, 95, 95, 95, 95, 95, 127, 95, 95, 127, 127,
95, 95, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 3, 3, 15, 15,
15, 15, 15, 15, 127, 127, 95, 95, 15, 15, 15, 15, 95, 95, 95, 15, 127,
127, 127, 15, 15, 127, 127, 127, 127, 127, 127, 127, 15, 15, 15, 95,
95, 95, 95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95,
127, 127, 95, 95, 127, 127, 127, 127, 127, 127, 95, 15, 127, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 127, 127, 127, 95, 14, 14, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 0, 128, 0, 0, 0, 0, 0, 128, 0, 0, 129,
129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129,
129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129,
129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129,
3, 94, 129, 129, 129, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15,
15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15,
0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0,
15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15,
15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
0, 0, 95, 95, 95, 3, 3, 3, 3, 3, 3, 3, 3, 3, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 130, 130, 130, 130,
130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,
130, 130, 107, 107, 107, 107, 107, 107, 0, 0, 113, 113, 113, 113, 113,
113, 0, 0, 8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 3, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 5, 6, 0, 0, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 3, 3, 3, 131, 131, 131, 15, 15, 15, 15, 15,
15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 127, 0, 0, 0, 0, 0,
0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 95, 95, 127, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
95, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 0, 95, 95, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 127, 95, 95, 95, 95, 95, 95,
95, 127, 127, 127, 127, 127, 127, 127, 127, 95, 127, 127, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 3, 3, 3, 94, 3, 3, 3, 4, 15, 95, 0,
0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 8, 3, 3,
3, 3, 95, 95, 95, 17, 95, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
0, 0, 15, 15, 15, 94, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15,
95, 95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 95, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0,
95, 95, 95, 127, 127, 127, 127, 95, 95, 127, 127, 127, 0, 0, 0, 0,
127, 127, 95, 127, 127, 127, 127, 127, 127, 95, 95, 95, 0, 0, 0, 0,
14, 0, 0, 0, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0,
0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 0, 0, 0, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
95, 95, 127, 127, 95, 0, 0, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 95, 127, 95, 95,
95, 95, 95, 95, 95, 0, 95, 127, 95, 127, 127, 95, 95, 95, 95, 95, 95,
95, 95, 127, 127, 127, 127, 127, 127, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 0, 0, 95, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 94,
3, 3, 3, 3, 3, 3, 0, 0, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 122, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 0, 0, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 95, 95, 95,
127, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 127, 95,
95, 95, 95, 95, 127, 95, 127, 127, 127, 127, 127, 95, 127, 127, 15,
15, 15, 15, 15, 15, 15, 15, 0, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
3, 3, 3, 3, 3, 3, 3, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 95, 95,
95, 95, 95, 95, 95, 95, 95, 14, 14, 14, 14, 14, 14, 14, 14, 14, 3,
3, 3, 95, 95, 127, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 127, 95, 95, 95, 95, 127, 127, 95, 95, 127, 95, 95, 95, 15, 15,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 95, 127, 95, 95, 127, 127, 127, 95, 127, 95, 95, 95, 127, 127,
0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 15, 15, 15, 15, 127, 127, 127,
127, 127, 127, 127, 127, 95, 95, 95, 95, 95, 95, 95, 95, 127, 127,
95, 95, 0, 0, 0, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
0, 15, 15, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 94, 94, 94, 94, 94, 94, 3, 3, 132, 133,
134, 135, 135, 136, 137, 138, 139, 23, 24, 0, 0, 0, 0, 0, 140, 140,
140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 0,
0, 140, 140, 140, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 95,
95, 95, 3, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 127,
95, 95, 95, 95, 95, 95, 95, 15, 15, 15, 15, 95, 15, 15, 15, 15, 15,
15, 95, 15, 15, 127, 95, 95, 15, 0, 0, 0, 0, 0, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 94, 141, 21, 21,
21, 142, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 143, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 94, 94, 94,
94, 94, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 23, 24, 21, 21, 21, 21, 21, 144, 21, 21, 145, 21,
146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147, 147, 147,
147, 147, 146, 146, 146, 146, 146, 146, 0, 0, 147, 147, 147, 147, 147,
147, 0, 0, 146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 147, 147,
147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 146, 146, 147, 147,
147, 147, 147, 147, 147, 147, 146, 146, 146, 146, 146, 146, 0, 0, 147,
147, 147, 147, 147, 147, 0, 0, 21, 146, 21, 146, 21, 146, 21, 146,
0, 147, 0, 147, 0, 147, 0, 147, 146, 146, 146, 146, 146, 146, 146,
146, 147, 147, 147, 147, 147, 147, 147, 147, 148, 148, 149, 149, 149,
149, 150, 150, 151, 151, 152, 152, 153, 153, 0, 0, 146, 146, 146, 146,
146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154, 146, 146,
146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154, 154, 154,
146, 146, 146, 146, 146, 146, 146, 146, 154, 154, 154, 154, 154, 154,
154, 154, 146, 146, 21, 155, 21, 0, 21, 21, 147, 147, 156, 156, 157,
11, 158, 11, 11, 11, 21, 155, 21, 0, 21, 21, 159, 159, 159, 159, 157,
11, 11, 11, 146, 146, 21, 21, 0, 0, 21, 21, 147, 147, 160, 160, 0,
11, 11, 11, 146, 146, 21, 21, 21, 116, 21, 21, 147, 147, 161, 161,
120, 11, 11, 11, 0, 0, 21, 155, 21, 0, 21, 21, 162, 162, 163, 163,
157, 11, 11, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 17,
8, 8, 8, 8, 8, 8, 3, 3, 16, 20, 5, 16, 16, 20, 5, 16, 3, 3, 3, 3, 3,
3, 3, 3, 164, 165, 17, 17, 17, 17, 17, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
16, 20, 3, 3, 3, 3, 12, 12, 3, 3, 3, 7, 5, 6, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 7, 3, 12, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 17, 17, 17,
17, 17, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 94, 0, 0, 18,
18, 18, 18, 18, 18, 7, 7, 7, 5, 6, 94, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 7, 7, 7, 5, 6, 0, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 122, 122, 122, 122, 95, 122, 122, 122, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 14, 14, 110, 14, 14, 14, 14, 110, 14, 14, 21, 110, 110, 110,
21, 21, 110, 110, 110, 21, 14, 110, 14, 14, 7, 110, 110, 110, 110,
110, 14, 14, 14, 14, 14, 14, 110, 14, 166, 14, 110, 14, 167, 168, 110,
110, 14, 21, 110, 110, 169, 110, 21, 15, 15, 15, 15, 21, 14, 14, 21,
21, 110, 110, 7, 7, 7, 7, 7, 110, 21, 21, 21, 21, 14, 7, 14, 14, 170,
14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
171, 171, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 131, 131, 131, 23, 24, 131, 131, 131, 131, 18,
14, 14, 0, 0, 0, 0, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 7, 7, 14, 14,
14, 14, 7, 14, 14, 7, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 7, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 14, 14, 7,
14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 14, 14,
14, 14, 14, 14, 14, 14, 5, 6, 5, 6, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 14, 14, 14, 14,
14, 14, 14, 5, 6, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 173, 173, 173, 173, 173, 173,
173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
173, 173, 173, 173, 173, 173, 174, 174, 174, 174, 174, 174, 174, 174,
174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174,
174, 174, 174, 174, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7,
14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7,
7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6,
5, 6, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 5, 6, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5,
6, 5, 6, 5, 6, 5, 6, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 6, 5, 6, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 5, 6, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 14, 14, 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 125, 125, 125, 125, 125,
125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
125, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
126, 126, 126, 126, 126, 126, 126, 23, 24, 175, 176, 177, 178, 179,
23, 24, 23, 24, 23, 24, 180, 181, 182, 183, 21, 23, 24, 21, 23, 24,
21, 21, 21, 21, 21, 94, 94, 184, 184, 23, 24, 23, 24, 21, 14, 14, 14,
14, 14, 14, 23, 24, 23, 24, 95, 95, 95, 23, 24, 0, 0, 0, 0, 0, 3, 3,
3, 3, 18, 3, 3, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 0,
185, 0, 0, 0, 0, 0, 185, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0,
0, 0, 0, 0, 94, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15,
15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15,
0, 15, 15, 15, 15, 15, 15, 15, 0, 3, 3, 16, 20, 16, 20, 3, 3, 3, 16,
20, 3, 16, 20, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 3, 3, 8, 3, 16, 20, 3,
3, 16, 20, 5, 6, 5, 6, 5, 6, 5, 6, 3, 3, 3, 3, 3, 94, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 8, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 14, 14, 3, 3, 3, 5, 6, 5, 6, 5, 6, 5, 6, 8, 0, 0, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 3, 3,
3, 14, 94, 15, 131, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 14, 14, 5, 6, 5,
6, 5, 6, 5, 6, 8, 5, 6, 6, 14, 131, 131, 131, 131, 131, 131, 131, 131,
131, 95, 95, 95, 95, 127, 127, 8, 94, 94, 94, 94, 94, 14, 14, 131,
131, 131, 94, 15, 3, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 95, 95, 11,
11, 94, 94, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 94, 94,
94, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 14, 14, 18, 18,
18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, 18, 18, 18, 18,
18, 18, 18, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 94, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 94, 3, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 15, 95, 122, 122, 122, 3, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 3, 94, 23, 24, 23, 24, 23, 24,
23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 94, 94, 95, 95, 15, 15, 15, 15, 15, 15, 131, 131,
131, 131, 131, 131, 131, 131, 131, 131, 95, 95, 3, 3, 3, 3, 3, 3, 0,
0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 94, 94, 94, 94, 94, 94,
94, 94, 94, 11, 11, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
23, 24, 21, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24,
94, 21, 21, 21, 21, 21, 21, 21, 21, 23, 24, 23, 24, 186, 23, 24, 23,
24, 23, 24, 23, 24, 23, 24, 94, 11, 11, 23, 24, 187, 21, 15, 23, 24,
23, 24, 188, 21, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 23, 24, 189, 190, 191, 192, 189, 21, 193, 194,
195, 196, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23, 24, 23,
24, 197, 198, 199, 23, 24, 23, 24, 200, 23, 24, 23, 24, 23, 24, 23,
24, 23, 24, 23, 24, 23, 24, 23, 24, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 94, 94, 94, 23, 24, 15, 94, 94,
21, 15, 15, 15, 15, 15, 15, 15, 95, 15, 15, 15, 95, 15, 15, 15, 15,
95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 127, 127, 95, 95, 127, 14, 14, 14, 14,
95, 0, 0, 0, 18, 18, 18, 18, 18, 18, 14, 14, 4, 14, 0, 0, 0, 0, 0,
0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 95,
95, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0,
0, 0, 0, 0, 0, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 15, 15, 15, 15, 15, 15, 3, 3, 3, 15, 3, 15, 15,
95, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 3, 3, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 127,
127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 127, 127, 95, 95, 95, 95, 127,
127, 95, 95, 127, 127, 127, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
0, 94, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 3, 3, 15, 15, 15,
15, 15, 95, 94, 15, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 95, 95, 95, 95, 95, 95, 127, 127, 95, 95, 127, 127, 95, 95, 0,
0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 95, 15, 15, 15, 15, 15, 15, 15,
15, 95, 127, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 3, 3, 3, 3,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 94,
15, 15, 15, 15, 15, 15, 14, 14, 14, 15, 127, 95, 127, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 15, 95,
95, 95, 15, 15, 95, 95, 15, 15, 15, 15, 15, 95, 95, 15, 95, 15, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
15, 15, 94, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127,
95, 95, 127, 127, 3, 3, 15, 94, 94, 127, 95, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15,
15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15,
15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 202, 21, 21, 21, 21, 21,
21, 21, 11, 94, 94, 94, 94, 21, 21, 21, 21, 21, 21, 21, 21, 21, 94,
11, 11, 0, 0, 0, 0, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 15, 15, 15, 127,
127, 95, 127, 127, 95, 127, 127, 3, 127, 95, 0, 0, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 204, 204, 204,
204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
204, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
205, 205, 205, 205, 205, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 21,
21, 21, 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21,
21, 21, 21, 0, 0, 0, 0, 0, 15, 95, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15,
15, 15, 15, 15, 0, 15, 0, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 6, 5, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 4, 14, 14, 14, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 3, 3, 3, 3,
3, 3, 3, 5, 6, 3, 0, 0, 0, 0, 0, 0, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 3, 8, 8, 12, 12, 5, 6, 5, 6, 5, 6,
5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 3, 3, 5, 6, 3, 3, 3, 3, 12, 12, 12, 3,
3, 3, 0, 3, 3, 3, 3, 8, 5, 6, 5, 6, 5, 6, 3, 3, 3, 7, 8, 7, 7, 7, 0,
3, 4, 3, 3, 0, 0, 0, 0, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
0, 0, 17, 0, 3, 3, 3, 4, 3, 3, 3, 5, 6, 3, 7, 3, 8, 3, 3, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 3, 3, 7, 7, 7, 3, 11, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 5, 7, 6, 7, 5, 6, 3, 5, 6, 3, 3, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 94, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 94,
94, 0, 0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 0,
0, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 0, 0, 0, 4, 4, 7, 11,
14, 4, 4, 0, 14, 7, 7, 7, 7, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
17, 17, 17, 14, 14, 0, 0
#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8
,15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 131, 131,
131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
131, 131, 131, 131, 131, 131, 131, 131, 131, 18, 18, 18, 18, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, 18,
14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 95, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 95, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 18, 18,
18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 131, 15, 15, 15, 15,
15, 15, 15, 15, 131, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95,
95, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 3, 15, 15, 15, 15, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
3, 131, 131, 131, 131, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0,
0, 0, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206, 206, 0, 0, 0, 0, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 3, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 0,
208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
208, 0, 208, 208, 208, 208, 208, 208, 208, 0, 208, 208, 0, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209, 209, 0, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 0, 209, 209,
209, 209, 209, 209, 209, 0, 209, 209, 0, 0, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94,
94, 94, 94, 94, 94, 0, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 0, 94, 94,
94, 94, 94, 94, 94, 94, 94, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15,
0, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 0,
0, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 3, 18, 18, 18, 18, 18, 18, 18,
18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 14, 14, 18, 18, 18, 18, 18, 18, 18, 0,
0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 0, 0, 0, 0, 18,
18, 18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 18, 18, 18, 18, 18, 18, 0, 0, 0,
3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 3, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 0, 0, 0, 0, 18, 18, 15, 15, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 15, 95, 95, 95, 0, 95, 95, 0, 0, 0,
0, 0, 95, 95, 95, 95, 15, 15, 15, 15, 0, 15, 15, 15, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 95, 95, 95, 0, 0, 0, 0, 95,
18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3,
3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 18, 18, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 0, 0, 0, 0, 18, 18, 18, 18,
18, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 18, 18, 18,
18, 18, 18, 18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18,
18, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100,
100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105,
105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105,
105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105,
105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 0, 0, 0, 0, 0, 0,
0, 18, 18, 18, 18, 18, 18, 15, 15, 15, 15, 95, 95, 95, 95, 0, 0, 0,
0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 15, 15, 15, 15, 94, 15, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
0, 0, 0, 95, 95, 95, 95, 95, 8, 94, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0,
0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 95, 95, 8, 0, 0, 15, 15, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 94, 15, 15, 0, 0, 0,
0, 0, 0, 0, 0, 3, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 95, 95, 95, 95, 95, 95, 18, 18, 18, 18, 18, 18, 18, 15,
0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 18, 18, 18, 18, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95,
3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 15, 15, 15, 15, 15, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 95, 127, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 3, 3, 3,
3, 3, 3, 3, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 95,
15, 15, 95, 95, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127, 127, 95,
95, 95, 95, 127, 127, 95, 95, 3, 3, 17, 3, 3, 3, 3, 95, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 17, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0,
0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 95, 95,
95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 95, 95, 95, 95, 95, 127, 95, 95, 95, 95, 95, 95, 95, 95,
0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 3, 3, 15, 127, 127, 15, 0, 0,
0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 95, 3, 3, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
127, 127, 127, 95, 95, 95, 95, 95, 95, 95, 95, 95, 127, 127, 15, 15,
15, 15, 3, 3, 3, 3, 95, 95, 95, 95, 3, 127, 95, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 15, 3, 15, 3, 3, 3, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127, 127, 95,
95, 95, 127, 127, 95, 127, 95, 95, 3, 3, 3, 3, 3, 3, 95, 15, 15, 95,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 0, 15, 15,
15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3, 0, 0, 0, 0, 0, 0,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 127, 127, 127,
95, 95, 95, 95, 95, 95, 95, 95, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 0, 0, 0, 0, 0, 0, 95, 95, 127, 127, 0, 15, 15, 15, 15, 15,
15, 15, 15, 0, 0, 15, 15, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15,
15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 0, 95, 95, 15, 127,
127, 95, 127, 127, 127, 127, 0, 0, 127, 127, 0, 0, 127, 127, 127, 0,
0, 15, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 127,
127, 0, 0, 95, 95, 95, 95, 95, 95, 95, 0, 0, 0, 95, 95, 95, 95, 95,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 15, 0, 0, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 127, 127, 127, 95, 95,
95, 95, 95, 95, 0, 127, 0, 0, 127, 0, 127, 127, 127, 127, 0, 127, 127,
95, 127, 95, 15, 95, 15, 3, 3, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 95,
95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127, 127, 95, 95, 95,
95, 95, 95, 95, 95, 127, 127, 95, 95, 95, 127, 95, 15, 15, 15, 15,
3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 3, 3, 0, 3, 95, 15, 15,
15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 127, 127, 127, 95, 95, 95, 95, 95, 95, 127,
95, 127, 127, 127, 127, 95, 95, 127, 95, 95, 15, 15, 3, 15, 0, 0, 0,
0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127, 127,
95, 95, 95, 95, 0, 0, 127, 127, 127, 127, 95, 95, 127, 95, 95, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 15,
15, 15, 15, 95, 95, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 127, 127, 127, 95, 95, 95, 95, 95, 95, 95, 95,
127, 127, 95, 127, 95, 95, 3, 3, 3, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 127, 95,
127, 127, 95, 95, 95, 95, 95, 95, 127, 95, 15, 3, 0, 0, 0, 0, 0, 0,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 0, 0, 95, 127, 95, 127, 127, 95, 95, 95, 95,
127, 95, 95, 95, 95, 95, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
18, 18, 3, 3, 3, 14, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127, 127, 95, 95, 95, 95,
95, 95, 95, 95, 95, 127, 95, 95, 3, 0, 0, 0, 0, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18,
18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 0, 0, 15, 15, 15, 15, 15, 15,
15, 15, 0, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 127, 127, 127,
127, 127, 0, 127, 127, 0, 0, 95, 95, 127, 95, 15, 127, 15, 127, 95,
3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0,
0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 127, 127, 127, 95, 95, 95, 95, 0, 0, 95, 95, 127, 127, 127, 127,
95, 15, 3, 15, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 127, 15, 95,
95, 95, 95, 3, 3, 3, 3, 3, 3, 3, 3, 95, 0, 0, 0, 0, 0, 0, 0, 0, 15,
95, 95, 95, 95, 95, 95, 127, 127, 95, 95, 95, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 127, 95, 95, 3, 3, 3, 15, 3, 3, 3, 3, 3, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 127, 95, 95,
95, 127, 95, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 15, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 127, 95, 95, 95, 95, 95, 95, 95,
0, 95, 95, 95, 95, 95, 95, 127, 95, 15, 3, 3, 3, 3, 3, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 3,
3, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 0, 127, 95, 95, 95, 95, 95, 95, 95, 127, 95, 95, 127, 95,
95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15,
0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 0, 0, 0, 95, 0, 95, 95,
0, 95, 95, 95, 95, 95, 95, 95, 15, 95, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 0,
15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 127, 127, 127, 127, 127, 0, 95, 95, 0, 127, 127, 95, 127, 95, 15,
0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 94, 15, 15, 0, 0, 0, 0, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 95, 95, 127, 127, 3, 3, 0, 0, 0, 0, 0, 0, 0, 95,
95, 15, 127, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
127, 127, 95, 95, 95, 95, 95, 0, 0, 0, 127, 127, 95, 127, 95, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 95,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 14,
14, 14, 14, 14, 14, 14, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 3, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
131, 131, 131, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 95,
15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 127, 127, 127, 95, 95, 95, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0,
0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 3, 3, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 95, 95, 95, 95,
95, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 95, 95, 95, 95, 95, 95, 95, 3, 3, 3,
3, 3, 14, 14, 14, 14, 94, 94, 94, 94, 3, 14, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 18, 18, 18, 18, 18, 18, 18,
0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 94, 94, 94, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 94, 94,
3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 3, 3, 3, 3, 0, 0, 0, 0, 0, 210, 210, 210, 210, 210, 210,
210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
210, 210, 210, 210, 210, 0, 0, 211, 211, 211, 211, 211, 211, 211, 211,
211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211,
211, 211, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 95, 15, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 95,
95, 95, 95, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 3, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 94, 94, 131,
131, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 94, 94, 94, 0, 94, 94, 94, 94, 94, 94,
94, 0, 94, 94, 0, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 0, 0, 15, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 0, 15, 15, 15, 15, 15,
15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 0, 0, 14, 95, 95, 3, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0,
0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 0, 0, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 0,
0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14,
14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 127, 127,
95, 95, 95, 14, 14, 14, 127, 127, 127, 127, 127, 127, 17, 17, 17, 17,
17, 17, 17, 17, 95, 95, 95, 95, 95, 95, 95, 95, 14, 14, 95, 95, 95,
95, 95, 95, 95, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
95, 95, 95, 95, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 95, 95, 95, 14, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0,
0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 21, 21, 21, 21, 21, 21, 21, 0, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 110, 0, 110, 110, 0, 0, 110, 0, 0, 110, 110, 0, 0, 110,
110, 110, 110, 0, 110, 110, 110, 110, 110, 110, 110, 110, 21, 21, 21,
21, 0, 21, 0, 21, 21, 21, 21, 21, 21, 21, 0, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 110, 110, 0, 110, 110,
110, 110, 0, 0, 110, 110, 110, 110, 110, 110, 110, 110, 0, 110, 110,
110, 110, 110, 110, 110, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 110,
110, 0, 110, 110, 110, 110, 0, 110, 110, 110, 110, 110, 0, 110, 0,
0, 0, 110, 110, 110, 110, 110, 110, 110, 0, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 110, 110, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 21, 21, 21,
21, 21, 21, 0, 0, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 7, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 7, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
7, 21, 21, 21, 21, 21, 21, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21,
21, 21, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 7,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 7, 21, 21, 21, 21, 21, 21, 110, 21,
0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 14, 14, 14, 14, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 14, 14,
14, 14, 14, 14, 14, 14, 95, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 95, 14, 14, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 95, 95, 95, 95, 95, 0, 95, 95, 95, 95, 95, 95,
95, 95, 95, 95, 95, 95, 95, 95, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 0, 0, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 95, 95, 95, 95, 95, 95,
0, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
95, 0, 0, 95, 95, 95, 95, 95, 95, 95, 0, 95, 95, 0, 95, 95, 95, 95,
95, 0, 0, 0, 0, 0, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 0, 95, 95, 95, 95, 95, 95, 95, 94, 94, 94, 94, 94, 94, 94,
0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 15, 14, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 95, 95,
95, 95, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 4, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 94, 95, 95, 95, 95, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 95, 95, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
0, 0, 3, 15, 15, 15, 95, 15, 15, 95, 15, 15, 15, 15, 15, 15, 15, 95,
95, 15, 15, 15, 15, 15, 95, 0, 0, 0, 0, 0, 0, 0, 0, 15, 94, 15, 15,
15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15, 15, 0, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15,
0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 95, 95, 95, 95, 95, 95, 95,
0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 213, 213,
213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213,
213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213,
213, 213, 213, 213, 95, 95, 95, 95, 95, 95, 95, 94, 0, 0, 0, 0, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
14, 18, 18, 18, 4, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 15, 15, 15, 15, 0,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 0, 15, 0, 0, 15,
0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15,
0, 15, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 15,
15, 0, 15, 15, 0, 15, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15,
15, 0, 15, 0, 0, 15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 0,
15, 15, 15, 15, 0, 15, 15, 15, 15, 0, 15, 0, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 15, 15, 15, 0, 15, 15, 15, 15, 15,
0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0,
14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 11, 11, 11, 11, 11, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14,
14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14,
0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0,
0, 0, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7,
7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0,
0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0,
0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 0, 14, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 14, 0, 0, 0, 0, 0, 15,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15
#endif /* TCL_UTF_MAX > 3 */
};
/*
* Each group represents a unique set of character attributes. The attributes
* are encoded into a 32-bit value as follows:
*
* Bits 0-4 Character category: see the constants listed below.
*
* Bits 5-7 Case delta type: 000 = identity
* 010 = add delta for lower
* 011 = add delta for lower, add 1 for title
* 100 = subtract delta for title/upper
* 101 = sub delta for upper, sub 1 for title
* 110 = sub delta for upper, add delta for lower
* 111 = subtract delta for upper
*
* Bits 8-31 Case delta: delta for case conversions. This should be the
* highest field so we can easily sign extend.
*/
static const int groups[] = {
0, 15, 12, 25, 27, 21, 22, 26, 20, 9, 8257, 28, 19, 8322, 29,
5, 23, 16, 11, -190078, 24, 2, -30846, 321, 386, -50879, 59522,
-30911, 76930, -49790, 53825, 52801, 52545, 20289, 51777, 52033,
53057, -24702, 54081, 53569, -41598, -10895486, 54593, -33150,
54849, 55873, 55617, 56129, -14206, 609, 451, 674, 20354, -24767,
-14271, -33215, 2763585, -41663, 2762817, -2768510, -49855, 17729,
18241, -2760318, -2759550, -2760062, 53890, 52866, 52610, 51842,
52098, -10833534, -10832510, 53122, -10839678, -10823550, -10830718,
53634, 54146, -2750078, -10829950, -2751614, 54658, 54914, -2745982,
55938, -10830462, -10824062, 17794, 55682, 18306, 56194, -10818686,
-10817918, 4, 6, -21370, 29761, 9793, 9537, 16449, 16193, 9858,
9602, 8066, 16514, 16258, 2113, 16002, 14722, 1, 12162, 13954,
2178, 22146, 20610, -1662, 29826, -15295, 24706, -1727, 20545,
7, 3905, 3970, 12353, 12418, 8, 1859649, -769822, 9949249, 10,
1601154, 1600898, 1598594, 1598082, 1598338, 1596546, 1582466,
-9027966, -769983, -9044862, -976254, -9058174, 15234, -1949375,
-1918, -1983, -18814, -21886, -25470, -32638, -28542, -32126,
-1981, -2174, -18879, -2237, 1844610, -21951, -25535, -28607,
-32703, -32191, 13, 14, -1924287, -2145983, -2115007, 7233, 7298,
4170, 4234, 6749, 6813, -2750143, -976319, -2746047, 2763650,
2762882, -2759615, -2751679, -2760383, -2760127, -2768575, 1859714,
-9044927, -10823615, -12158, -10830783, -10833599, -10832575,
-10830015, -10817983, -10824127, -10818751, 237633, -12223, -10830527,
-9058239, -10839743, -10895551, 237698, 9949314, 18, 17, 10305,
10370, 10049, 10114, 6977, 7042, 8769, 8834
};
#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8
# define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1FFFFF) >= 0x33480)
#else
# define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1F0000) != 0)
#endif
/*
* The following constants are used to determine the category of a
* Unicode character.
*/
enum {
UNASSIGNED,
UPPERCASE_LETTER,
LOWERCASE_LETTER,
TITLECASE_LETTER,
MODIFIER_LETTER,
OTHER_LETTER,
NON_SPACING_MARK,
ENCLOSING_MARK,
COMBINING_SPACING_MARK,
DECIMAL_DIGIT_NUMBER,
LETTER_NUMBER,
OTHER_NUMBER,
SPACE_SEPARATOR,
LINE_SEPARATOR,
PARAGRAPH_SEPARATOR,
CONTROL,
FORMAT,
PRIVATE_USE,
SURROGATE,
CONNECTOR_PUNCTUATION,
DASH_PUNCTUATION,
OPEN_PUNCTUATION,
CLOSE_PUNCTUATION,
INITIAL_QUOTE_PUNCTUATION,
FINAL_QUOTE_PUNCTUATION,
OTHER_PUNCTUATION,
MATH_SYMBOL,
CURRENCY_SYMBOL,
MODIFIER_SYMBOL,
OTHER_SYMBOL
};
/*
* The following macros extract the fields of the character info. The
* GetDelta() macro is complicated because we can't rely on the C compiler
* to do sign extension on right shifts.
*/
#define GetCaseType(info) (((info) & 0xE0) >> 5)
#define GetCategory(ch) (GetUniCharInfo(ch) & 0x1F)
#define GetDelta(info) ((info) >> 8)
/*
* This macro extracts the information about a character from the
* Unicode character tables.
*/
#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8
# define GetUniCharInfo(ch) (groups[groupMap[pageMap[((ch) & 0x1FFFFF) >> OFFSET_BITS] | ((ch) & ((1 << OFFSET_BITS)-1))]])
#else
# define GetUniCharInfo(ch) (groups[groupMap[pageMap[((ch) & 0xFFFF) >> OFFSET_BITS] | ((ch) & ((1 << OFFSET_BITS)-1))]])
#endif
|
Changes to generic/tclUtf.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* * tclUtf.c -- * * Routines for manipulating UTF-8 strings. * * Copyright © 1997-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < | | | | < | | < | | < | | < | | | | < | | | | | < < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
/*
* tclUtf.c --
*
* Routines for manipulating UTF-8 strings.
*
* Copyright © 1997-1998 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
/*
* Include the static character classification tables and macros.
*/
#include "tclUniData.c"
/*
* The following masks are used for fast character category tests. The x_BITS
* values are shifted right by the category value to determine whether the
* given category is included in the set.
*/
enum UnicodeCharacterCategoryMasks {
ALPHA_BITS = (1 << UPPERCASE_LETTER) | (1 << LOWERCASE_LETTER) |
(1 << TITLECASE_LETTER) | (1 << MODIFIER_LETTER) |
(1 << OTHER_LETTER),
CONTROL_BITS = (1 << CONTROL) | (1 << FORMAT),
DIGIT_BITS = (1 << DECIMAL_DIGIT_NUMBER),
SPACE_BITS = (1 << SPACE_SEPARATOR) | (1 << LINE_SEPARATOR) |
(1 << PARAGRAPH_SEPARATOR),
WORD_BITS = ALPHA_BITS | DIGIT_BITS | (1 << CONNECTOR_PUNCTUATION),
PUNCT_BITS = (1 << CONNECTOR_PUNCTUATION) |
(1 << DASH_PUNCTUATION) | (1 << OPEN_PUNCTUATION) |
(1 << CLOSE_PUNCTUATION) | (1 << INITIAL_QUOTE_PUNCTUATION) |
(1 << FINAL_QUOTE_PUNCTUATION) | (1 << OTHER_PUNCTUATION),
GRAPH_BITS = WORD_BITS | PUNCT_BITS |
(1 << NON_SPACING_MARK) | (1 << ENCLOSING_MARK) |
(1 << COMBINING_SPACING_MARK) | (1 << LETTER_NUMBER) |
(1 << OTHER_NUMBER) |
(1 << MATH_SYMBOL) | (1 << CURRENCY_SYMBOL) |
(1 << MODIFIER_SYMBOL) | (1 << OTHER_SYMBOL)
};
/*
* Unicode characters less than this value are represented by themselves in
* UTF-8 strings.
*/
|
| ︙ | ︙ | |||
145 146 147 148 149 150 151 | * encoding, or because it encodes something out of the proper range. * * Given a pointer to the bytes \xF8 or \xFC , this routine will * try to read beyond the end of the "bounds" table. Callers must * prevent this. * * Given a pointer to something else (an ASCII byte, a trail byte, | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | * encoding, or because it encodes something out of the proper range. * * Given a pointer to the bytes \xF8 or \xFC , this routine will * try to read beyond the end of the "bounds" table. Callers must * prevent this. * * Given a pointer to something else (an ASCII byte, a trail byte, * or another byte that can never begin a valid byte sequence such * as \xF5) this routine returns false. That makes the routine poorly * named, as it does not detect and report all invalid sequences. * * Callers have to take care that this routine does something useful * for their needs. * * Results: |
| ︙ | ︙ | |||
169 170 171 172 173 174 175 |
0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, /* (\xE4 - \xEC) -- all valid */
0x90, 0xBF, /* \xF0\x80 through \xF0\x8F are invalid prefixes */
0x80, 0x8F /* \xF4\x90 and higher are invalid prefixes */
};
static int
Invalid(
| | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF, /* (\xE4 - \xEC) -- all valid */
0x90, 0xBF, /* \xF0\x80 through \xF0\x8F are invalid prefixes */
0x80, 0x8F /* \xF4\x90 and higher are invalid prefixes */
};
static int
Invalid(
const char *src) /* Points to lead byte of a UTF-8 byte sequence */
{
unsigned char byte = UCHAR(*src);
int index;
if ((byte & 0xC3) == 0xC0) {
/* Only lead bytes 0xC0, 0xE0, 0xF0, 0xF4 need examination */
index = (byte - 0xC0) >> 1;
|
| ︙ | ︙ | |||
366 367 368 369 370 371 372 |
Tcl_Size uniLength, /* Length of Utf-16 string. */
Tcl_DString *dsPtr) /* UTF-8 representation of string is appended
* to this previously initialized DString. */
{
const unsigned short *w, *wEnd;
char *p, *string;
Tcl_Size oldLength;
| | | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
Tcl_Size uniLength, /* Length of Utf-16 string. */
Tcl_DString *dsPtr) /* UTF-8 representation of string is appended
* to this previously initialized DString. */
{
const unsigned short *w, *wEnd;
char *p, *string;
Tcl_Size oldLength;
int len = 1;
/*
* UTF-8 string length in bytes will be <= Utf16 string length * 3.
*/
if (uniStr == NULL) {
return NULL;
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 |
*chPtr = byte;
return 1;
}
Tcl_Size
Tcl_UtfToChar16(
| | | | < | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
*chPtr = byte;
return 1;
}
Tcl_Size
Tcl_UtfToChar16(
const char *src, /* The UTF-8 string. */
unsigned short *chPtr)/* Filled with the Tcl_UniChar represented by
* the UTF-8 string. This could be a surrogate too. */
{
unsigned short byte;
/*
* Unroll 1 to 4 byte UTF-8 sequences.
*/
|
| ︙ | ︙ | |||
559 560 561 562 563 564 565 |
* bytes, then we must produce a follow-up low surrogate. We only
* do that if the high surrogate matches the bits we encounter.
*/
if (((byte & 0xC0) == 0x80)
&& ((src[1] & 0xC0) == 0x80) && ((src[2] & 0xC0) == 0x80)
&& (((((byte - 0x10) << 2) & 0xFC) | 0xD800) == (*chPtr & 0xFCFC))
&& ((src[1] & 0xF0) == (((*chPtr << 4) & 0x30) | 0x80))) {
| | | | | | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
* bytes, then we must produce a follow-up low surrogate. We only
* do that if the high surrogate matches the bits we encounter.
*/
if (((byte & 0xC0) == 0x80)
&& ((src[1] & 0xC0) == 0x80) && ((src[2] & 0xC0) == 0x80)
&& (((((byte - 0x10) << 2) & 0xFC) | 0xD800) == (*chPtr & 0xFCFC))
&& ((src[1] & 0xF0) == (((*chPtr << 4) & 0x30) | 0x80))) {
*chPtr = ((src[1] & 0x0F) << 6) + (src[2] & 0x3F) + 0xDC00;
return 3;
}
if ((unsigned)(byte-0x80) < (unsigned)0x20) {
*chPtr = cp1252[byte-0x80];
} else {
*chPtr = byte;
}
return 1;
} else if (byte < 0xE0) {
if ((byte != 0xC1) && ((src[1] & 0xC0) == 0x80)) {
/*
* Two-byte-character lead-byte followed by a trail-byte.
*/
*chPtr = (((byte & 0x1F) << 6) | (src[1] & 0x3F));
if ((unsigned)(*chPtr - 1) >= (UNICODE_SELF - 1)) {
return 2;
}
}
/*
* A two-byte-character lead-byte not followed by trail-byte
* represents itself.
*/
} else if (byte < 0xF0) {
if (((src[1] & 0xC0) == 0x80) && ((src[2] & 0xC0) == 0x80)) {
/*
* Three-byte-character lead byte followed by two trail bytes.
*/
*chPtr = (((byte & 0x0F) << 12)
| ((src[1] & 0x3F) << 6) | (src[2] & 0x3F));
if (*chPtr > 0x7FF) {
return 3;
}
}
/*
* A three-byte-character lead-byte not followed by two trail-bytes
* represents itself.
*/
} else if (byte < 0xF5) {
if (((src[1] & 0xC0) == 0x80) && ((src[2] & 0xC0) == 0x80)) {
/*
* Four-byte-character lead byte followed by at least two trail bytes.
* We don't test the validity of 3th trail byte, see [ed29806ba]
*/
Tcl_UniChar high = (((byte & 0x07) << 8) | ((src[1] & 0x3F) << 2)
| ((src[2] & 0x3F) >> 4)) - 0x40;
if (high < 0x400) {
/* produce high surrogate, advance source pointer */
*chPtr = 0xD800 + high;
return 1;
}
/* out of range, < 0x10000 or > 0x10FFFF */
}
/*
* A four-byte-character lead-byte not followed by three trail-bytes
|
| ︙ | ︙ | |||
808 809 810 811 812 813 814 | * None. * *--------------------------------------------------------------------------- */ Tcl_Size Tcl_NumUtfChars( | | | | | 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
* None.
*
*---------------------------------------------------------------------------
*/
Tcl_Size
Tcl_NumUtfChars(
const char *src, /* The UTF-8 string to measure. */
Tcl_Size length) /* The length of the string in bytes, or
* negative value for strlen(src). */
{
Tcl_UniChar ch = 0;
Tcl_Size i = 0;
if (length < 0) {
/* string is NUL-terminated, so TclUtfToUniChar calls are safe. */
while (*src != '\0') {
|
| ︙ | ︙ | |||
860 861 862 863 864 865 866 |
}
}
return i;
}
Tcl_Size
TclNumUtfChars(
| | | | | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 |
}
}
return i;
}
Tcl_Size
TclNumUtfChars(
const char *src, /* The UTF-8 string to measure. */
Tcl_Size length) /* The length of the string in bytes, or
* negative for strlen(src). */
{
unsigned short ch = 0;
Tcl_Size i = 0;
if (length < 0) {
/* string is NUL-terminated, so TclUtfToUniChar calls are safe. */
while (*src != '\0') {
|
| ︙ | ︙ | |||
909 910 911 912 913 914 915 |
src++;
}
i++;
}
}
return i;
}
| | | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 |
src++;
}
i++;
}
}
return i;
}
/*
*---------------------------------------------------------------------------
*
* Tcl_UtfFindFirst --
*
* Returns a pointer to the first occurrence of the given Unicode character
* in the NULL-terminated UTF-8 string. The NULL terminator is considered
|
| ︙ | ︙ | |||
935 936 937 938 939 940 941 |
const char *
Tcl_UtfFindFirst(
const char *src, /* The UTF-8 string to be searched. */
int ch) /* The Unicode character to search for. */
{
while (1) {
| < | | 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 |
const char *
Tcl_UtfFindFirst(
const char *src, /* The UTF-8 string to be searched. */
int ch) /* The Unicode character to search for. */
{
while (1) {
int find, len = TclUtfToUniChar(src, &find);
if (find == ch) {
return src;
}
if (*src == '\0') {
return NULL;
}
|
| ︙ | ︙ | |||
975 976 977 978 979 980 981 |
Tcl_UtfFindLast(
const char *src, /* The UTF-8 string to be searched. */
int ch) /* The Unicode character to search for. */
{
const char *last = NULL;
while (1) {
| < | | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 |
Tcl_UtfFindLast(
const char *src, /* The UTF-8 string to be searched. */
int ch) /* The Unicode character to search for. */
{
const char *last = NULL;
while (1) {
int find, len = TclUtfToUniChar(src, &find);
if (find == ch) {
last = src;
}
if (*src == '\0') {
break;
}
|
| ︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 | * None. * *--------------------------------------------------------------------------- */ int Tcl_UniCharAtIndex( | | | > | > | | | 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 |
* None.
*
*---------------------------------------------------------------------------
*/
int
Tcl_UniCharAtIndex(
const char *src, /* The UTF-8 string to dereference. */
Tcl_Size index) /* The position of the desired character. */
{
Tcl_UniChar ch = 0;
int i = 0;
if (index < 0) {
return -1;
}
while (index--) {
i = TclUtfToUniChar(src, &ch);
src += i;
}
TclUtfToUniChar(src, &i);
return i;
}
/*
*---------------------------------------------------------------------------
*
* Tcl_UtfAtIndex --
*
|
| ︙ | ︙ | |||
1220 1221 1222 1223 1224 1225 1226 | * None. * *--------------------------------------------------------------------------- */ const char * Tcl_UtfAtIndex( | | | | | | | 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
* None.
*
*---------------------------------------------------------------------------
*/
const char *
Tcl_UtfAtIndex(
const char *src, /* The UTF-8 string. */
Tcl_Size index) /* The position of the desired character. */
{
Tcl_UniChar ch = 0;
while (index-- > 0) {
src += TclUtfToUniChar(src, &ch);
}
return src;
}
const char *
TclUtfAtIndex(
const char *src, /* The UTF-8 string. */
Tcl_Size index) /* The position of the desired character. */
{
unsigned short ch = 0;
Tcl_Size len = 0;
if (index > 0) {
while (index--) {
src += (len = Tcl_UtfToChar16(src, &ch));
}
if ((ch >= 0xD800) && (len < 3)) {
/* Index points at character following high Surrogate */
src += Tcl_UtfToChar16(src, &ch);
}
}
return src;
}
/*
*---------------------------------------------------------------------------
*
* Tcl_UtfBackslash --
*
* Figure out how to handle a backslash sequence.
*
|
| ︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 |
int *readPtr, /* Fill in with number of characters read from
* src, unless NULL. */
char *dst) /* Filled with the bytes represented by the
* backslash sequence. */
{
#define LINE_LENGTH 128
Tcl_Size numRead;
| | | | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 |
int *readPtr, /* Fill in with number of characters read from
* src, unless NULL. */
char *dst) /* Filled with the bytes represented by the
* backslash sequence. */
{
#define LINE_LENGTH 128
Tcl_Size numRead;
int result;
result = TclParseBackslash(src, LINE_LENGTH, &numRead, dst);
if (numRead == LINE_LENGTH) {
/*
* We ate a whole line. Pay the price of a strlen()
*/
result = TclParseBackslash(src, strlen(src), &numRead, dst);
}
if (readPtr != NULL) {
*readPtr = numRead;
}
return result;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 |
*----------------------------------------------------------------------
*/
int
TclpUtfNcmp2(
const void *csPtr, /* UTF string to compare to ct. */
const void *ctPtr, /* UTF string cs is compared to. */
| | | 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 |
*----------------------------------------------------------------------
*/
int
TclpUtfNcmp2(
const void *csPtr, /* UTF string to compare to ct. */
const void *ctPtr, /* UTF string cs is compared to. */
size_t numBytes) /* Number of *bytes* to compare. */
{
const char *cs = (const char *)csPtr;
const char *ct = (const char *)ctPtr;
/*
* We can't simply call 'memcmp(cs, ct, numBytes);' because we need to
* check for Tcl's \xC0\x80 non-utf-8 null encoding. Otherwise utf-8 lexes
* fine in the strcmp manner.
|
| ︙ | ︙ | |||
1546 1547 1548 1549 1550 1551 1552 |
*----------------------------------------------------------------------
*/
int
TclUtfNcmp(
const char *cs, /* UTF string to compare to ct. */
const char *ct, /* UTF string cs is compared to. */
| | | 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 |
*----------------------------------------------------------------------
*/
int
TclUtfNcmp(
const char *cs, /* UTF string to compare to ct. */
const char *ct, /* UTF string cs is compared to. */
size_t numChars) /* Number of UTF-16 chars to compare. */
{
unsigned short ch1 = 0, ch2 = 0;
/*
* Cannot use 'memcmp(cs, ct, n);' as byte representation of \u0000 (the
* pair of bytes 0xC0,0x80) is larger than byte representation of \u0001
* (the byte 0x01.)
|
| ︙ | ︙ | |||
1568 1569 1570 1571 1572 1573 1574 |
*/
cs += Tcl_UtfToChar16(cs, &ch1);
ct += Tcl_UtfToChar16(ct, &ch2);
if (ch1 != ch2) {
/* Surrogates always report higher than non-surrogates */
if (((ch1 & 0xFC00) == 0xD800)) {
| | | | | | 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 |
*/
cs += Tcl_UtfToChar16(cs, &ch1);
ct += Tcl_UtfToChar16(ct, &ch2);
if (ch1 != ch2) {
/* Surrogates always report higher than non-surrogates */
if (((ch1 & 0xFC00) == 0xD800)) {
if ((ch2 & 0xFC00) != 0xD800) {
return ch1;
}
} else if ((ch2 & 0xFC00) == 0xD800) {
return -ch2;
}
return (ch1 - ch2);
}
}
return 0;
}
int
Tcl_UtfNcmp(
const char *cs, /* UTF string to compare to ct. */
const char *ct, /* UTF string cs is compared to. */
size_t numChars) /* Number of chars to compare. */
{
Tcl_UniChar ch1 = 0, ch2 = 0;
/*
* Cannot use 'memcmp(cs, ct, n);' as byte representation of \u0000 (the
* pair of bytes 0xC0,0x80) is larger than byte representation of \u0001
* (the byte 0x01.)
|
| ︙ | ︙ | |||
1632 1633 1634 1635 1636 1637 1638 |
*----------------------------------------------------------------------
*/
int
TclUtfNcasecmp(
const char *cs, /* UTF string to compare to ct. */
const char *ct, /* UTF string cs is compared to. */
| | | | | | | | | 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 |
*----------------------------------------------------------------------
*/
int
TclUtfNcasecmp(
const char *cs, /* UTF string to compare to ct. */
const char *ct, /* UTF string cs is compared to. */
size_t numChars) /* Number of UTF-16 chars to compare. */
{
unsigned short ch1 = 0, ch2 = 0;
while (numChars-- > 0) {
/*
* n must be interpreted as UTF-16 chars, not bytes.
* This should be called only when both strings are of
* at least n UTF-16 chars long (no need for \0 check)
*/
cs += Tcl_UtfToChar16(cs, &ch1);
ct += Tcl_UtfToChar16(ct, &ch2);
if (ch1 != ch2) {
/* Surrogates always report higher than non-surrogates */
if (((ch1 & 0xFC00) == 0xD800)) {
if ((ch2 & 0xFC00) != 0xD800) {
return ch1;
}
} else if ((ch2 & 0xFC00) == 0xD800) {
return -ch2;
}
ch1 = Tcl_UniCharToLower(ch1);
ch2 = Tcl_UniCharToLower(ch2);
if (ch1 != ch2) {
return (ch1 - ch2);
}
}
}
return 0;
}
int
Tcl_UtfNcasecmp(
const char *cs, /* UTF string to compare to ct. */
const char *ct, /* UTF string cs is compared to. */
size_t numChars) /* Number of chars to compare. */
{
Tcl_UniChar ch1 = 0, ch2 = 0;
while (numChars-- > 0) {
/*
* n must be interpreted as chars, not bytes.
* This should be called only when both strings are of
|
| ︙ | ︙ | |||
1689 1690 1691 1692 1693 1694 1695 |
if (ch1 != ch2) {
return (ch1 - ch2);
}
}
}
return 0;
}
| | | 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 |
if (ch1 != ch2) {
return (ch1 - ch2);
}
}
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* Tcl_UtfCmp --
*
* Compare UTF chars of string cs to string ct case sensitively.
* Replacement for strcmp in Tcl core, in places where UTF-8 should
|
| ︙ | ︙ | |||
1785 1786 1787 1788 1789 1790 1791 |
*/
int
Tcl_UniCharToUpper(
int ch) /* Unicode character to convert. */
{
if (!UNICODE_OUT_OF_RANGE(ch)) {
| > | > > > | 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 |
*/
int
Tcl_UniCharToUpper(
int ch) /* Unicode character to convert. */
{
if (!UNICODE_OUT_OF_RANGE(ch)) {
int info = GetUniCharInfo(ch);
if (GetCaseType(info) & 0x04) {
ch -= GetDelta(info);
}
}
/* Clear away extension bits, if any */
return ch & 0x1FFFFF;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1812 1813 1814 1815 1816 1817 1818 |
*/
int
Tcl_UniCharToLower(
int ch) /* Unicode character to convert. */
{
if (!UNICODE_OUT_OF_RANGE(ch)) {
| > > | > > > | | 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 |
*/
int
Tcl_UniCharToLower(
int ch) /* Unicode character to convert. */
{
if (!UNICODE_OUT_OF_RANGE(ch)) {
int info = GetUniCharInfo(ch);
int mode = GetCaseType(info);
if ((mode & 0x02) && (mode != 0x7)) {
ch += GetDelta(info);
}
}
/* Clear away extension bits, if any */
return ch & 0x1FFFFF;
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharToTitle --
*
* Compute the titlecase equivalent of the given Unicode character.
*
|
| ︙ | ︙ | |||
1839 1840 1841 1842 1843 1844 1845 |
*/
int
Tcl_UniCharToTitle(
int ch) /* Unicode character to convert. */
{
if (!UNICODE_OUT_OF_RANGE(ch)) {
| > > | > > > > > > > > > > > | 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 |
*/
int
Tcl_UniCharToTitle(
int ch) /* Unicode character to convert. */
{
if (!UNICODE_OUT_OF_RANGE(ch)) {
int info = GetUniCharInfo(ch);
int mode = GetCaseType(info);
if (mode & 0x1) {
/*
* Subtract or add one depending on the original case.
*/
if (mode != 0x7) {
ch += ((mode & 0x4) ? -1 : 1);
}
} else if (mode == 0x4) {
ch -= GetDelta(info);
}
}
/* Clear away extension bits, if any */
return ch & 0x1FFFFF;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1874 1875 1876 1877 1878 1879 1880 |
while (*uniStr != '\0') {
len++;
uniStr++;
}
return len;
}
| | | | 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 |
while (*uniStr != '\0') {
len++;
uniStr++;
}
return len;
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharLen --
*
* Find the length of a UniChar string. The str input must be null
* terminated.
*
* Results:
* Returns the length of str in UniChars (not bytes).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Tcl_Size
Tcl_UniCharLen(
const int *uniStr) /* Unicode string to find length of. */
{
Tcl_Size len = 0;
while (*uniStr != '\0') {
len++;
uniStr++;
}
|
| ︙ | ︙ | |||
1926 1927 1928 1929 1930 1931 1932 |
*----------------------------------------------------------------------
*/
int
TclUniCharNcmp(
const Tcl_UniChar *ucs, /* Unicode string to compare to uct. */
const Tcl_UniChar *uct, /* Unicode string ucs is compared to. */
| | | 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 |
*----------------------------------------------------------------------
*/
int
TclUniCharNcmp(
const Tcl_UniChar *ucs, /* Unicode string to compare to uct. */
const Tcl_UniChar *uct, /* Unicode string ucs is compared to. */
size_t numChars) /* Number of chars to compare. */
{
#if defined(WORDS_BIGENDIAN)
/*
* We are definitely on a big-endian machine; memcmp() is safe
*/
return memcmp(ucs, uct, numChars*sizeof(Tcl_UniChar));
|
| ︙ | ︙ | |||
1971 1972 1973 1974 1975 1976 1977 |
*----------------------------------------------------------------------
*/
int
TclUniCharNcasecmp(
const Tcl_UniChar *ucs, /* Unicode string to compare to uct. */
const Tcl_UniChar *uct, /* Unicode string ucs is compared to. */
| | | 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 |
*----------------------------------------------------------------------
*/
int
TclUniCharNcasecmp(
const Tcl_UniChar *ucs, /* Unicode string to compare to uct. */
const Tcl_UniChar *uct, /* Unicode string ucs is compared to. */
size_t numChars) /* Number of chars to compare. */
{
for ( ; numChars != 0; numChars--, ucs++, uct++) {
if (*ucs != *uct) {
Tcl_UniChar lcs = Tcl_UniCharToLower(*ucs);
Tcl_UniChar lct = Tcl_UniCharToLower(*uct);
if (lcs != lct) {
|
| ︙ | ︙ | |||
2006 2007 2008 2009 2010 2011 2012 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsAlnum(
int ch) /* Unicode character to test. */
{
| > | > > | 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsAlnum(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
}
return (((ALPHA_BITS | DIGIT_BITS) >> GetCategory(ch)) & 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsAlpha --
*
|
| ︙ | ︙ | |||
2029 2030 2031 2032 2033 2034 2035 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsAlpha(
int ch) /* Unicode character to test. */
{
| > | > > | 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsAlpha(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
}
return ((ALPHA_BITS >> GetCategory(ch)) & 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsControl --
*
|
| ︙ | ︙ | |||
2052 2053 2054 2055 2056 2057 2058 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsControl(
int ch) /* Unicode character to test. */
{
| > > > > > | | 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsControl(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
/* Clear away extension bits, if any */
ch &= 0x1FFFFF;
return ((ch == 0xE0001) || ((unsigned)(ch - 0xE0020) <= 0x5F));
}
return ((CONTROL_BITS >> GetCategory(ch)) & 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsDigit --
*
|
| ︙ | ︙ | |||
2075 2076 2077 2078 2079 2080 2081 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsDigit(
int ch) /* Unicode character to test. */
{
| > | > > | 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsDigit(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
}
return (GetCategory(ch) == DECIMAL_DIGIT_NUMBER);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsGraph --
*
|
| ︙ | ︙ | |||
2098 2099 2100 2101 2102 2103 2104 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsGraph(
int ch) /* Unicode character to test. */
{
| > > > | | 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsGraph(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return ((unsigned)((ch & 0x1FFFFF) - 0xE0100) <= 0xEF);
}
return ((GRAPH_BITS >> GetCategory(ch)) & 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsLower --
*
|
| ︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsLower(
int ch) /* Unicode character to test. */
{
| > | > > | 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsLower(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
}
return (GetCategory(ch) == LOWERCASE_LETTER);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsPrint --
*
|
| ︙ | ︙ | |||
2144 2145 2146 2147 2148 2149 2150 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsPrint(
int ch) /* Unicode character to test. */
{
| > | > > | 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsPrint(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return ((unsigned)((ch & 0x1FFFFF) - 0xE0100) <= 0xEF);
}
return (((GRAPH_BITS|SPACE_BITS) >> GetCategory(ch)) & 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsPunct --
*
|
| ︙ | ︙ | |||
2167 2168 2169 2170 2171 2172 2173 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsPunct(
int ch) /* Unicode character to test. */
{
| > | > > | 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsPunct(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
}
return ((PUNCT_BITS >> GetCategory(ch)) & 1);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsSpace --
*
|
| ︙ | ︙ | |||
2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 |
/*
* If the character is within the first 127 characters, just use the
* standard C function, otherwise consult the Unicode table.
*/
if (ch < 0x80) {
return TclIsSpaceProcM((char) ch);
} else if (ch == 0x0085 || ch == 0x180E || ch == 0x200B
|| ch == 0x202F || ch == 0x2060 || ch == 0xFEFF) {
return 1;
} else {
| > > | | 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 |
/*
* If the character is within the first 127 characters, just use the
* standard C function, otherwise consult the Unicode table.
*/
if (ch < 0x80) {
return TclIsSpaceProcM((char) ch);
} else if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
} else if (ch == 0x0085 || ch == 0x180E || ch == 0x200B
|| ch == 0x202F || ch == 0x2060 || ch == 0xFEFF) {
return 1;
} else {
return ((SPACE_BITS >> GetCategory(ch)) & 1);
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsUpper --
|
| ︙ | ︙ | |||
2228 2229 2230 2231 2232 2233 2234 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsUpper(
int ch) /* Unicode character to test. */
{
| > | > > | 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsUpper(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
}
return (GetCategory(ch) == UPPERCASE_LETTER);
}
/*
*----------------------------------------------------------------------
*
* Tcl_UniCharIsWordChar --
*
|
| ︙ | ︙ | |||
2251 2252 2253 2254 2255 2256 2257 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsWordChar(
int ch) /* Unicode character to test. */
{
| > | > > | < > | 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 |
*----------------------------------------------------------------------
*/
int
Tcl_UniCharIsWordChar(
int ch) /* Unicode character to test. */
{
if (UNICODE_OUT_OF_RANGE(ch)) {
return 0;
}
return ((WORD_BITS >> GetCategory(ch)) & 1);
}
/*
*----------------------------------------------------------------------
*
* TclUniCharCaseMatch --
*
* See if a particular Unicode string matches a particular pattern.
* Allows case insensitivity. This is the Unicode equivalent of the char*
* Tcl_StringCaseMatch. The UniChar strings must be NULL-terminated.
* This has no provision for counted UniChar strings, thus should not be
* used where NULLs are expected in the UniChar string. Use
* TclUniCharMatch where possible.
*
* Results:
* The return value is 1 if string matches pattern, and 0 otherwise. The
* matching operation permits the following special characters in the
* pattern: *?\[] (see the manual entry for details on what these mean).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclUniCharCaseMatch(
const Tcl_UniChar *uniStr, /* Unicode String. */
const Tcl_UniChar *uniPattern,
/* Pattern, which may contain special
* characters. */
int nocase) /* 0 for case sensitive, 1 for insensitive */
{
|
| ︙ | ︙ | |||
2300 2301 2302 2303 2304 2305 2306 |
* of the string, we failed.
*/
if (p == 0) {
return (*uniStr == 0);
}
if ((*uniStr == 0) && (p != '*')) {
| | | | 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 |
* of the string, we failed.
*/
if (p == 0) {
return (*uniStr == 0);
}
if ((*uniStr == 0) && (p != '*')) {
return 0;
}
/*
* Check for a "*" as the next pattern character. It matches any
* substring. We handle this by skipping all the characters up to the
* next matching one in the pattern, and then calling ourselves
* recursively for each postfix of string, until either we match or we
* reach the end of the string.
*/
if (p == '*') {
/*
* Skip all successive *'s in the pattern
*/
while (*(++uniPattern) == '*') {
/* empty body */
}
p = *uniPattern;
if (p == 0) {
return 1;
}
if (nocase) {
p = Tcl_UniCharToLower(p);
}
while (1) {
/*
* Optimization for matching - cruise through the string
|
| ︙ | ︙ | |||
2346 2347 2348 2349 2350 2351 2352 |
} else {
while (*uniStr && (p != *uniStr)) {
uniStr++;
}
}
}
if (TclUniCharCaseMatch(uniStr, uniPattern, nocase)) {
| | | | 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 |
} else {
while (*uniStr && (p != *uniStr)) {
uniStr++;
}
}
}
if (TclUniCharCaseMatch(uniStr, uniPattern, nocase)) {
return 1;
}
if (*uniStr == 0) {
return 0;
}
uniStr++;
}
}
/*
* Check for a "?" as the next pattern character. It matches any
|
| ︙ | ︙ | |||
2380 2381 2382 2383 2384 2385 2386 |
Tcl_UniChar startChar, endChar;
uniPattern++;
ch1 = (nocase ? Tcl_UniCharToLower(*uniStr) : *uniStr);
uniStr++;
while (1) {
if ((*uniPattern == ']') || (*uniPattern == 0)) {
| | | | 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 |
Tcl_UniChar startChar, endChar;
uniPattern++;
ch1 = (nocase ? Tcl_UniCharToLower(*uniStr) : *uniStr);
uniStr++;
while (1) {
if ((*uniPattern == ']') || (*uniPattern == 0)) {
return 0;
}
startChar = (nocase ? Tcl_UniCharToLower(*uniPattern)
: *uniPattern);
uniPattern++;
if (*uniPattern == '-') {
uniPattern++;
if (*uniPattern == 0) {
return 0;
}
endChar = (nocase ? Tcl_UniCharToLower(*uniPattern)
: *uniPattern);
uniPattern++;
if (((startChar <= ch1) && (ch1 <= endChar))
|| ((endChar <= ch1) && (ch1 <= startChar))) {
/*
|
| ︙ | ︙ | |||
2422 2423 2424 2425 2426 2427 2428 |
/*
* If the next pattern character is '\', just strip off the '\' so we
* do exact matching on the character that follows.
*/
if (p == '\\') {
if (*(++uniPattern) == '\0') {
| | | | | < > | 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 |
/*
* If the next pattern character is '\', just strip off the '\' so we
* do exact matching on the character that follows.
*/
if (p == '\\') {
if (*(++uniPattern) == '\0') {
return 0;
}
}
/*
* There's no special character. Just make sure that the next bytes of
* each string match.
*/
if (nocase) {
if (Tcl_UniCharToLower(*uniStr) !=
Tcl_UniCharToLower(*uniPattern)) {
return 0;
}
} else if (*uniStr != *uniPattern) {
return 0;
}
uniStr++;
uniPattern++;
}
}
/*
*----------------------------------------------------------------------
*
* TclUniCharMatch --
*
* See if a particular Unicode string matches a particular pattern.
* Allows case insensitivity. This is the Unicode equivalent of the char*
* Tcl_StringCaseMatch. This variant of TclUniCharCaseMatch uses counted
* Strings, so embedded NULLs are allowed.
*
* Results:
* The return value is 1 if string matches pattern, and 0 otherwise. The
* matching operation permits the following special characters in the
* pattern: *?\[] (see the manual entry for details on what these mean).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclUniCharMatch(
const Tcl_UniChar *string, /* Unicode String. */
Tcl_Size strLen, /* Length of String */
const Tcl_UniChar *pattern, /* Pattern, which may contain special
* characters. */
Tcl_Size ptnLen, /* Length of Pattern */
int nocase) /* 0 for case sensitive, 1 for insensitive */
|
| ︙ | ︙ | |||
2492 2493 2494 2495 2496 2497 2498 |
*/
if (pattern == patternEnd) {
return (string == stringEnd);
}
p = *pattern;
if ((string == stringEnd) && (p != '*')) {
| | | | 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 |
*/
if (pattern == patternEnd) {
return (string == stringEnd);
}
p = *pattern;
if ((string == stringEnd) && (p != '*')) {
return 0;
}
/*
* Check for a "*" as the next pattern character. It matches any
* substring. We handle this by skipping all the characters up to the
* next matching one in the pattern, and then calling ourselves
* recursively for each postfix of string, until either we match or we
* reach the end of the string.
*/
if (p == '*') {
/*
* Skip all successive *'s in the pattern.
*/
while (*(++pattern) == '*') {
/* empty body */
}
if (pattern == patternEnd) {
return 1;
}
p = *pattern;
if (nocase) {
p = Tcl_UniCharToLower(p);
}
while (1) {
/*
|
| ︙ | ︙ | |||
2539 2540 2541 2542 2543 2544 2545 |
while ((string < stringEnd) && (p != *string)) {
string++;
}
}
}
if (TclUniCharMatch(string, stringEnd - string,
pattern, patternEnd - pattern, nocase)) {
| | | | 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 |
while ((string < stringEnd) && (p != *string)) {
string++;
}
}
}
if (TclUniCharMatch(string, stringEnd - string,
pattern, patternEnd - pattern, nocase)) {
return 1;
}
if (string == stringEnd) {
return 0;
}
string++;
}
}
/*
* Check for a "?" as the next pattern character. It matches any
|
| ︙ | ︙ | |||
2573 2574 2575 2576 2577 2578 2579 |
Tcl_UniChar ch1, startChar, endChar;
pattern++;
ch1 = (nocase ? Tcl_UniCharToLower(*string) : *string);
string++;
while (1) {
if ((*pattern == ']') || (pattern == patternEnd)) {
| | | | 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 |
Tcl_UniChar ch1, startChar, endChar;
pattern++;
ch1 = (nocase ? Tcl_UniCharToLower(*string) : *string);
string++;
while (1) {
if ((*pattern == ']') || (pattern == patternEnd)) {
return 0;
}
startChar = (nocase ? Tcl_UniCharToLower(*pattern) : *pattern);
pattern++;
if (*pattern == '-') {
pattern++;
if (pattern == patternEnd) {
return 0;
}
endChar = (nocase ? Tcl_UniCharToLower(*pattern)
: *pattern);
pattern++;
if (((startChar <= ch1) && (ch1 <= endChar))
|| ((endChar <= ch1) && (ch1 <= startChar))) {
/*
|
| ︙ | ︙ | |||
2614 2615 2616 2617 2618 2619 2620 |
/*
* If the next pattern character is '\', just strip off the '\' so we
* do exact matching on the character that follows.
*/
if (p == '\\') {
if (++pattern == patternEnd) {
| | | | | 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 |
/*
* If the next pattern character is '\', just strip off the '\' so we
* do exact matching on the character that follows.
*/
if (p == '\\') {
if (++pattern == patternEnd) {
return 0;
}
}
/*
* There's no special character. Just make sure that the next bytes of
* each string match.
*/
if (nocase) {
if (Tcl_UniCharToLower(*string) != Tcl_UniCharToLower(*pattern)) {
return 0;
}
} else if (*string != *pattern) {
return 0;
}
string++;
pattern++;
}
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to generic/tclUtil.c.
| ︙ | ︙ | |||
144 145 146 147 148 149 150 |
* for it. This is a caching internalrep, keeping the result of a parse
* around. This type is only created from a pre-existing string, so an
* updateStringProc will never be called and need not exist. The type
* is unregistered, so has no need of a setFromAnyProc either.
*/
static const Tcl_ObjType endOffsetType = {
| | | | | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
* for it. This is a caching internalrep, keeping the result of a parse
* around. This type is only created from a pre-existing string, so an
* updateStringProc will never be called and need not exist. The type
* is unregistered, so has no need of a setFromAnyProc either.
*/
static const Tcl_ObjType endOffsetType = {
"end-offset", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
NULL, /* updateStringProc */
NULL, /* setFromAnyProc */
TCL_OBJTYPE_V1(TclLengthOne)
};
Tcl_Size
TclLengthOne(
TCL_UNUSED(Tcl_Obj *))
{
|
| ︙ | ︙ | |||
748 749 750 751 752 753 754 755 756 757 758 759 760 761 |
*/
if ((openBraces == 0) && !inQuotes) {
size = (p - elemStart);
goto done;
}
}
break;
}
p++;
}
/*
* End of list/dict: terminate element.
*/
| > | 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
*/
if ((openBraces == 0) && !inQuotes) {
size = (p - elemStart);
goto done;
}
}
break;
}
p++;
}
/*
* End of list/dict: terminate element.
*/
|
| ︙ | ︙ | |||
899 900 901 902 903 904 905 |
* Space used to hold element separating white space in the original
* string gets re-purposed to hold '\0' characters in the argv array.
*/
size = TclMaxListLength(list, TCL_INDEX_NONE, &end) + 1;
length = end - list;
if (size >= (Tcl_Size) (TCL_SIZE_MAX/sizeof(char *)) ||
| | < < < < < | | > | 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 |
* Space used to hold element separating white space in the original
* string gets re-purposed to hold '\0' characters in the argv array.
*/
size = TclMaxListLength(list, TCL_INDEX_NONE, &end) + 1;
length = end - list;
if (size >= (Tcl_Size) (TCL_SIZE_MAX/sizeof(char *)) ||
length > (Tcl_Size) (TCL_SIZE_MAX - 1 - (size * sizeof(char *)))) {
if (interp) {
Tcl_SetResult(
interp, "memory allocation limit exceeded", TCL_STATIC);
}
return TCL_ERROR;
}
argv = (const char **)Tcl_Alloc((size * sizeof(char *)) + length + 1);
for (i = 0, p = ((char *) argv) + size*sizeof(char *);
*list != 0; i++) {
const char *prevList = list;
int literal;
result = TclFindElement(interp, list, length, &element, &list,
|
| ︙ | ︙ | |||
977 978 979 980 981 982 983 | * None. * *---------------------------------------------------------------------- */ Tcl_Size Tcl_ScanElement( | | | | | 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 |
* None.
*
*----------------------------------------------------------------------
*/
Tcl_Size
Tcl_ScanElement(
const char *src, /* String to convert to list element. */
int *flagPtr) /* Where to store information to guide
* Tcl_ConvertCountedElement. */
{
return Tcl_ScanCountedElement(src, TCL_INDEX_NONE, flagPtr);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 |
}
} else {
memcpy(p, src, length);
p += length;
}
*p = '}';
p++;
| | | 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 |
}
} else {
memcpy(p, src, length);
p += length;
}
*p = '}';
p++;
return (p - dst);
}
/* conversion == CONVERT_ESCAPE or CONVERT_MASK */
/*
* Formatted string is original string converted to escape sequences.
*/
|
| ︙ | ︙ | |||
1560 1561 1562 1563 1564 1565 1566 |
*p = '\\';
p++;
*p = 'v';
p++;
continue;
case '\0':
if (length < 0) {
| | | | 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 |
*p = '\\';
p++;
*p = 'v';
p++;
continue;
case '\0':
if (length < 0) {
return (p - dst);
}
/*
* If we reach this point, there's an embedded NULL in the string
* range being processed, which should not happen when the
* encoding rules for Tcl strings are properly followed. If the
* day ever comes when we stop tolerating such things, this is
* where to put the Tcl_Panic().
*/
break;
}
*p = *src;
p++;
}
return (p - dst);
}
/*
*----------------------------------------------------------------------
*
* Tcl_Merge --
*
|
| ︙ | ︙ | |||
1634 1635 1636 1637 1638 1639 1640 |
if (argc <= LOCAL_SIZE) {
flagPtr = localFlags;
} else {
flagPtr = (char *)Tcl_Alloc(argc);
}
for (i = 0; i < argc; i++) {
| | | 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 |
if (argc <= LOCAL_SIZE) {
flagPtr = localFlags;
} else {
flagPtr = (char *)Tcl_Alloc(argc);
}
for (i = 0; i < argc; i++) {
flagPtr[i] = ( i ? DONT_QUOTE_HASH : 0 );
bytesNeeded += TclScanElement(argv[i], TCL_INDEX_NONE, &flagPtr[i]);
}
bytesNeeded += argc;
/*
* Pass two: copy into the result area.
*/
|
| ︙ | ︙ | |||
1665 1666 1667 1668 1669 1670 1671 |
return result;
}
/*
*----------------------------------------------------------------------
*
* TclTrimRight --
| < | 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 |
return result;
}
/*
*----------------------------------------------------------------------
*
* TclTrimRight --
* Takes two counted strings in the Tcl encoding. Conceptually
* finds the sub string (offset) to trim from the right side of the
* first string all characters found in the second string.
*
* Results:
* The number of bytes to be removed from the end of the string.
*
|
| ︙ | ︙ | |||
1820 1821 1822 1823 1824 1825 1826 |
return p - bytes;
}
/*
*----------------------------------------------------------------------
*
* TclTrim --
| < | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 |
return p - bytes;
}
/*
*----------------------------------------------------------------------
*
* TclTrim --
* Finds the sub string (offset) to trim from both sides of the
* first string all characters found in the second string.
*
* Results:
* The number of bytes to be removed from the start of the string
*
* Side effects:
|
| ︙ | ︙ | |||
1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 |
* rely on (trim[numTrim] == '\0'). */
Tcl_Size *trimRightPtr) /* Offset from the end of the string. */
{
Tcl_Size trimLeft = 0, trimRight = 0;
/* Empty strings -> nothing to do */
if ((numBytes > 0) && (numTrim > 0)) {
/* When bytes is NUL-terminated, returns 0 <= trimLeft <= numBytes */
trimLeft = TclTrimLeft(bytes, numBytes, trim, numTrim);
numBytes -= trimLeft;
/* If we did not trim the whole string, it starts with a character
* that we will not trim. Skip over it. */
if (numBytes > 0) {
| > | 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 |
* rely on (trim[numTrim] == '\0'). */
Tcl_Size *trimRightPtr) /* Offset from the end of the string. */
{
Tcl_Size trimLeft = 0, trimRight = 0;
/* Empty strings -> nothing to do */
if ((numBytes > 0) && (numTrim > 0)) {
/* When bytes is NUL-terminated, returns 0 <= trimLeft <= numBytes */
trimLeft = TclTrimLeft(bytes, numBytes, trim, numTrim);
numBytes -= trimLeft;
/* If we did not trim the whole string, it starts with a character
* that we will not trim. Skip over it. */
if (numBytes > 0) {
|
| ︙ | ︙ | |||
1997 1998 1999 2000 2001 2002 2003 |
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
Tcl_ConcatObj(
Tcl_Size objc, /* Number of objects to concatenate. */
| | | 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 |
*
*----------------------------------------------------------------------
*/
Tcl_Obj *
Tcl_ConcatObj(
Tcl_Size objc, /* Number of objects to concatenate. */
Tcl_Obj *const objv[]) /* Array of objects to concatenate. */
{
int needSpace = 0;
Tcl_Size i, bytesNeeded = 0, elemLength;
const char *element;
Tcl_Obj *objPtr, *resPtr;
/*
|
| ︙ | ︙ | |||
2156 2157 2158 2159 2160 2161 2162 |
/*
* See if we're at the end of both the pattern and the string. If so,
* we succeeded. If we're at the end of the pattern but not at the end
* of the string, we failed.
*/
if (p == '\0') {
| | | < < | 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 |
/*
* See if we're at the end of both the pattern and the string. If so,
* we succeeded. If we're at the end of the pattern but not at the end
* of the string, we failed.
*/
if (p == '\0') {
return (*str == '\0');
}
if ((*str == '\0') && (p != '*')) {
return 0;
}
/*
* Check for a "*" as the next pattern character. It matches any
* substring. We handle this by calling ourselves recursively for each
* postfix of string, until either we match or we reach the end of the
* string.
*/
if (p == '*') {
/*
* Skip all successive *'s in the pattern
*/
while (*(++pattern) == '*');
p = *pattern;
if (p == '\0') {
return 1;
}
/*
* This is a special case optimization for single-byte utf.
|
| ︙ | ︙ | |||
2316 2317 2318 2319 2320 2321 2322 |
}
/* If we reach here, we matched. Need to move past closing ] */
while (*pattern != ']') {
if (*pattern == '\0') {
/* We ran out of pattern after matching something in
* (unclosed!) brackets. So long as we ran out of string
* at the same time, we have a match. Otherwise, not. */
| | | 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 |
}
/* If we reach here, we matched. Need to move past closing ] */
while (*pattern != ']') {
if (*pattern == '\0') {
/* We ran out of pattern after matching something in
* (unclosed!) brackets. So long as we ran out of string
* at the same time, we have a match. Otherwise, not. */
return (*str == '\0');
}
pattern++;
}
pattern++;
continue;
}
|
| ︙ | ︙ | |||
2363 2364 2365 2366 2367 2368 2369 | * TclByteArrayMatch -- * * See if a particular string matches a particular pattern. Does not * allow for case insensitivity. * Parallels tclUtf.c:TclUniCharMatch, adjusted for char* and sans nocase. * * Results: | | < > | 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 |
* TclByteArrayMatch --
*
* See if a particular string matches a particular pattern. Does not
* allow for case insensitivity.
* Parallels tclUtf.c:TclUniCharMatch, adjusted for char* and sans nocase.
*
* Results:
* The return value is 1 if string matches pattern, and 0 otherwise. The
* matching operation permits the following special characters in the
* pattern: *?\[] (see the manual entry for details on what these mean).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclByteArrayMatch(
const unsigned char *string,/* String. */
Tcl_Size strLen, /* Length of String */
const unsigned char *pattern,
/* Pattern, which may contain special
* characters. */
Tcl_Size ptnLen, /* Length of Pattern */
|
| ︙ | ︙ | |||
2397 2398 2399 2400 2401 2402 2403 |
/*
* See if we're at the end of both the pattern and the string. If so,
* we succeeded. If we're at the end of the pattern but not at the end
* of the string, we failed.
*/
if (pattern == patternEnd) {
| | | | | | | 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 |
/*
* See if we're at the end of both the pattern and the string. If so,
* we succeeded. If we're at the end of the pattern but not at the end
* of the string, we failed.
*/
if (pattern == patternEnd) {
return (string == stringEnd);
}
p = *pattern;
if ((string == stringEnd) && (p != '*')) {
return 0;
}
/*
* Check for a "*" as the next pattern character. It matches any
* substring. We handle this by skipping all the characters up to the
* next matching one in the pattern, and then calling ourselves
* recursively for each postfix of string, until either we match or we
* reach the end of the string.
*/
if (p == '*') {
/*
* Skip all successive *'s in the pattern.
*/
while ((++pattern < patternEnd) && (*pattern == '*')) {
/* empty body */
}
if (pattern == patternEnd) {
return 1;
}
p = *pattern;
while (1) {
/*
* Optimization for matching - cruise through the string
* quickly if the next char in the pattern isn't a special
* character.
*/
if ((p != '[') && (p != '?') && (p != '\\')) {
while ((string < stringEnd) && (p != *string)) {
string++;
}
}
if (TclByteArrayMatch(string, stringEnd - string,
pattern, patternEnd - pattern, 0)) {
return 1;
}
if (string == stringEnd) {
return 0;
}
string++;
}
}
/*
* Check for a "?" as the next pattern character. It matches any
|
| ︙ | ︙ | |||
2472 2473 2474 2475 2476 2477 2478 |
unsigned char ch1, startChar, endChar;
pattern++;
ch1 = *string;
string++;
while (1) {
if ((*pattern == ']') || (pattern == patternEnd)) {
| | | | 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 |
unsigned char ch1, startChar, endChar;
pattern++;
ch1 = *string;
string++;
while (1) {
if ((*pattern == ']') || (pattern == patternEnd)) {
return 0;
}
startChar = *pattern;
pattern++;
if (*pattern == '-') {
pattern++;
if (pattern == patternEnd) {
return 0;
}
endChar = *pattern;
pattern++;
if (((startChar <= ch1) && (ch1 <= endChar))
|| ((endChar <= ch1) && (ch1 <= startChar))) {
/*
* Matches ranges of form [a-z] or [z-a].
|
| ︙ | ︙ | |||
2513 2514 2515 2516 2517 2518 2519 |
/*
* If the next pattern character is '\', just strip off the '\' so we
* do exact matching on the character that follows.
*/
if (p == '\\') {
if (++pattern == patternEnd) {
| | | | < > | | | 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 |
/*
* If the next pattern character is '\', just strip off the '\' so we
* do exact matching on the character that follows.
*/
if (p == '\\') {
if (++pattern == patternEnd) {
return 0;
}
}
/*
* There's no special character. Just make sure that the next bytes of
* each string match.
*/
if (*string != *pattern) {
return 0;
}
string++;
pattern++;
}
}
/*
*----------------------------------------------------------------------
*
* TclStringMatchObj --
*
* See if a particular string matches a particular pattern. Allows case
* insensitivity. This is the generic multi-type handler for the various
* matching algorithms.
*
* Results:
* The return value is 1 if string matches pattern, and 0 otherwise. The
* matching operation permits the following special characters in the
* pattern: *?\[] (see the manual entry for details on what these mean).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclStringMatchObj(
Tcl_Obj *strObj, /* string object. */
Tcl_Obj *ptnObj, /* pattern object. */
int flags) /* Only TCL_MATCH_NOCASE should be passed, or
* 0. */
{
int match;
Tcl_Size length = 0, plen = 0;
/*
* Promote based on the type of incoming object.
* XXX: Currently doesn't take advantage of exact-ness that
* XXX: TclReToGlob tells us about
trivial = nocase ? 0 : TclMatchIsTrivial(TclGetString(ptnObj));
*/
if (TclHasInternalRep(strObj, &tclStringType) || (strObj->typePtr == NULL)) {
Tcl_UniChar *udata, *uptn;
udata = Tcl_GetUnicodeFromObj(strObj, &length);
uptn = Tcl_GetUnicodeFromObj(ptnObj, &plen);
match = TclUniCharMatch(udata, length, uptn, plen, flags);
} else if (TclIsPureByteArray(strObj) && TclIsPureByteArray(ptnObj)
&& !flags) {
unsigned char *data, *ptn;
data = Tcl_GetBytesFromObj(NULL, strObj, &length);
ptn = Tcl_GetBytesFromObj(NULL, ptnObj, &plen);
match = TclByteArrayMatch(data, length, ptn, plen, 0);
} else {
match = Tcl_StringCaseMatch(TclGetString(strObj),
|
| ︙ | ︙ | |||
3506 3507 3508 3509 3510 3511 3512 | * integer([+-]integer)? or end([+-]integer)?. * * If the computed index lies within the valid range of Tcl indices * (0..TCL_SIZE_MAX) it is returned. Higher values are returned as * TCL_SIZE_MAX. Negative values are returned as TCL_INDEX_NONE (-1). * * Callers should pass reasonable values for endValue - one in the | | | 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 | * integer([+-]integer)? or end([+-]integer)?. * * If the computed index lies within the valid range of Tcl indices * (0..TCL_SIZE_MAX) it is returned. Higher values are returned as * TCL_SIZE_MAX. Negative values are returned as TCL_INDEX_NONE (-1). * * Callers should pass reasonable values for endValue - one in the * valid index range or TCL_INDEX_NONE (-1), for example for an empty * list. * * Results: * TCL_OK * * The index is stored at the address given by 'indexPtr'. * |
| ︙ | ︙ | |||
3546 3547 3548 3549 3550 3551 3552 |
if (GetWideForIndex(interp, objPtr, endValue, &wide) == TCL_ERROR) {
return TCL_ERROR;
}
if (indexPtr != NULL) {
/* Note: check against TCL_SIZE_MAX needed for 32-bit builds */
if (wide >= 0 && wide <= TCL_SIZE_MAX) {
| | | | | 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 |
if (GetWideForIndex(interp, objPtr, endValue, &wide) == TCL_ERROR) {
return TCL_ERROR;
}
if (indexPtr != NULL) {
/* Note: check against TCL_SIZE_MAX needed for 32-bit builds */
if (wide >= 0 && wide <= TCL_SIZE_MAX) {
*indexPtr = (Tcl_Size)wide; /* A valid index */
} else if (wide > TCL_SIZE_MAX) {
*indexPtr = TCL_SIZE_MAX; /* Beyond max possible index */
} else if (wide < -1-TCL_SIZE_MAX) {
*indexPtr = -1-TCL_SIZE_MAX; /* Below most negative index */
} else if ((wide < 0) && (endValue >= 0)) {
*indexPtr = TCL_INDEX_NONE; /* No clue why this special case */
} else {
*indexPtr = (Tcl_Size) wide;
}
}
return TCL_OK;
}
|
| ︙ | ︙ | |||
3577 3578 3579 3580 3581 3582 3583 |
* WIDE_MIN: Index value TCL_INDEX_NONE (or -1)
* WIDE_MIN+1: Index value n, for any n < -1 (usually same effect as -1)
* -$n: Index "end-[expr {$n-1}]"
* -2: Index "end-1"
* -1: Index "end"
* 0: Index "0"
* WIDE_MAX-1: Index "end+n", for any n > 1. Distinguish from end+1 for
| | | 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 |
* WIDE_MIN: Index value TCL_INDEX_NONE (or -1)
* WIDE_MIN+1: Index value n, for any n < -1 (usually same effect as -1)
* -$n: Index "end-[expr {$n-1}]"
* -2: Index "end-1"
* -1: Index "end"
* 0: Index "0"
* WIDE_MAX-1: Index "end+n", for any n > 1. Distinguish from end+1 for
* commands like lset.
* WIDE_MAX: Index "end+1"
*
* Results:
* Tcl return code.
*
* Side effects:
* May store a Tcl_ObjType.
|
| ︙ | ︙ | |||
3834 3835 3836 3837 3838 3839 3840 |
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* TclIndexEncode --
| < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 |
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
* TclIndexEncode --
* IMPORTANT: function only encodes indices in the range that fits within
* an "int" type. Do NOT change this as the byte code compiler and engine
* which call this function cannot handle wider index types. Indices
* outside the range will result in the function returning an error.
*
* Parse objPtr to determine if it is an index value. Two cases
* are possible. The value objPtr might be parsed as an absolute
* index value in the Tcl_Size range. Note that this includes
* index values that are integers as presented and it includes index
* arithmetic expressions.
*
* The largest string supported in Tcl 8 has byte length TCL_SIZE_MAX.
* This means the largest supported character length is also TCL_SIZE_MAX,
* and the index of the last character in a string of length TCL_SIZE_MAX
* is TCL_SIZE_MAX-1. Thus the absolute index values that can be
* directly meaningful as an index into either a list or a string are
* integer values in the range 0 to TCL_SIZE_MAX - 1.
*
* This function however can only handle integer indices in the range
* 0 : INT_MAX-1.
*
* Any absolute index value parsed outside that range is encoded
* using the before and after values passed in by the
* caller as the encoding to use for indices that are either
* less than or greater than the usable index range. TCL_INDEX_NONE
* is available as a good choice for most callers to use for
* after. Likewise, the value TCL_INDEX_NONE is good for
* most callers to use for before. Other values are possible
* when the caller knows it is helpful in producing its own behavior
* for indices before and after the indexed item.
*
* A token can also be parsed as an end-relative index expression.
* All end-relative expressions that indicate an index larger
* than end (end+2, end--5) point beyond the end of the indexed
* collection, and can be encoded as after. The end-relative
* expressions that indicate an index less than or equal to end
* are encoded relative to the value TCL_INDEX_END (-2). The
* index "end" is encoded as -2, down to the index "end-0x7FFFFFFE"
* which is encoded as INT_MIN. Since the largest index into a
* string possible in Tcl 8 is 0x7FFFFFFE, the interpretation of
* "end-0x7FFFFFFE" for that largest string would be 0. Thus,
* if the tokens "end-0x7FFFFFFF" or "end+-0x80000000" are parsed,
* they can be encoded with the before value.
*
* Returns:
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed or the
* index does not fit in an int type.
*
* Side effects:
* When TCL_OK is returned, the encoded index value is written
* to *indexPtr.
*
*----------------------------------------------------------------------
*/
int
TclIndexEncode(
Tcl_Interp *interp, /* For error reporting, may be NULL */
|
| ︙ | ︙ | |||
4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 |
}
endValue += encoded - TCL_INDEX_END;
if (endValue >= 0) {
return endValue;
}
return TCL_INDEX_NONE;
}
/*
*----------------------------------------------------------------------
*
* ClearHash --
*
* Remove all the entries in the hash table *tablePtr.
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 |
}
endValue += encoded - TCL_INDEX_END;
if (endValue >= 0) {
return endValue;
}
return TCL_INDEX_NONE;
}
/*
*------------------------------------------------------------------------
*
* TclCommandWordLimitErrpr --
*
* Generates an error message limit on number of command words exceeded.
*
* Results:
* Always return TCL_ERROR.
*
* Side effects:
* If interp is not-NULL, an error message is stored in it.
*
*------------------------------------------------------------------------
*/
int
TclCommandWordLimitError(
Tcl_Interp *interp, /* May be NULL */
Tcl_Size count) /* If <= 0, "unknown" */
{
if (interp) {
if (count > 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Number of words (%" TCL_SIZE_MODIFIER
"d) in command exceeds limit %" TCL_SIZE_MODIFIER "d.",
count, (Tcl_Size)INT_MAX));
} else {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"Number of words in command exceeds limit %"
TCL_SIZE_MODIFIER "d.",
(Tcl_Size)INT_MAX));
}
}
return TCL_ERROR; /* Always */
}
/*
*----------------------------------------------------------------------
*
* ClearHash --
*
* Remove all the entries in the hash table *tablePtr.
|
| ︙ | ︙ | |||
4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 |
TclSetProcessGlobalValue(
ProcessGlobalValue *pgvPtr,
Tcl_Obj *newValue)
{
const char *bytes;
Tcl_HashTable *cacheMap;
Tcl_HashEntry *hPtr;
Tcl_DString ds;
Tcl_MutexLock(&pgvPtr->mutex);
/*
* Fill the global string value.
*/
| > | 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 |
TclSetProcessGlobalValue(
ProcessGlobalValue *pgvPtr,
Tcl_Obj *newValue)
{
const char *bytes;
Tcl_HashTable *cacheMap;
Tcl_HashEntry *hPtr;
int dummy;
Tcl_DString ds;
Tcl_MutexLock(&pgvPtr->mutex);
/*
* Fill the global string value.
*/
|
| ︙ | ︙ | |||
4218 4219 4220 4221 4222 4223 4224 |
* loss of the internalrep. Increment newValue refCount early to handle case
* where we set a PGV to itself.
*/
Tcl_IncrRefCount(newValue);
cacheMap = GetThreadHash(&pgvPtr->key);
ClearHash(cacheMap);
| | | 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 |
* loss of the internalrep. Increment newValue refCount early to handle case
* where we set a PGV to itself.
*/
Tcl_IncrRefCount(newValue);
cacheMap = GetThreadHash(&pgvPtr->key);
ClearHash(cacheMap);
hPtr = Tcl_CreateHashEntry(cacheMap, INT2PTR(pgvPtr->epoch), &dummy);
Tcl_SetHashValue(hPtr, newValue);
Tcl_MutexUnlock(&pgvPtr->mutex);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4262 4263 4264 4265 4266 4267 4268 | */ Tcl_DString native; Tcl_MutexLock(&pgvPtr->mutex); epoch = ++pgvPtr->epoch; Tcl_UtfToExternalDStringEx(NULL, pgvPtr->encoding, pgvPtr->value, | | | | > > | 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 |
*/
Tcl_DString native;
Tcl_MutexLock(&pgvPtr->mutex);
epoch = ++pgvPtr->epoch;
Tcl_UtfToExternalDStringEx(NULL, pgvPtr->encoding, pgvPtr->value,
pgvPtr->numBytes, TCL_ENCODING_PROFILE_TCL8, &native, NULL);
Tcl_ExternalToUtfDStringEx(NULL, current, Tcl_DStringValue(&native),
Tcl_DStringLength(&native), TCL_ENCODING_PROFILE_TCL8,
&newValue, NULL);
Tcl_DStringFree(&native);
Tcl_Free(pgvPtr->value);
pgvPtr->value = (char *)Tcl_Alloc(Tcl_DStringLength(&newValue) + 1);
memcpy(pgvPtr->value, Tcl_DStringValue(&newValue),
Tcl_DStringLength(&newValue) + 1);
Tcl_DStringFree(&newValue);
Tcl_FreeEncoding(pgvPtr->encoding);
pgvPtr->encoding = current;
Tcl_MutexUnlock(&pgvPtr->mutex);
} else {
Tcl_FreeEncoding(current);
}
}
cacheMap = GetThreadHash(&pgvPtr->key);
hPtr = Tcl_FindHashEntry(cacheMap, INT2PTR(epoch));
if (NULL == hPtr) {
int dummy;
/*
* No cache for the current epoch - must be a new one.
*
* First, clear the cacheMap, as anything in it must refer to some
* expired epoch.
*/
|
| ︙ | ︙ | |||
4313 4314 4315 4316 4317 4318 4319 | * Store a copy of the shared value (but then in utf-8) * in our epoch-indexed cache. */ Tcl_ExternalToUtfDString(NULL, pgvPtr->value, pgvPtr->numBytes, &newValue); value = Tcl_DStringToObj(&newValue); hPtr = Tcl_CreateHashEntry(cacheMap, | | | 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 |
* Store a copy of the shared value (but then in utf-8)
* in our epoch-indexed cache.
*/
Tcl_ExternalToUtfDString(NULL, pgvPtr->value, pgvPtr->numBytes, &newValue);
value = Tcl_DStringToObj(&newValue);
hPtr = Tcl_CreateHashEntry(cacheMap,
INT2PTR(pgvPtr->epoch), &dummy);
Tcl_MutexUnlock(&pgvPtr->mutex);
Tcl_SetHashValue(hPtr, value);
Tcl_IncrRefCount(value);
}
return (Tcl_Obj *)Tcl_GetHashValue(hPtr);
}
|
| ︙ | ︙ | |||
4377 4378 4379 4380 4381 4382 4383 |
{
return TclGetProcessGlobalValue(&executableName);
}
/*
*----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 |
{
return TclGetProcessGlobalValue(&executableName);
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetNameOfExecutable --
*
* This function retrieves the absolute pathname of the application in
* which the Tcl library is running, and returns it in string form.
*
* The returned string belongs to Tcl and should be copied if the caller
* plans to keep it, to guard against it becoming invalid.
|
| ︙ | ︙ | |||
4451 4452 4453 4454 4455 4456 4457 |
return NULL;
}
return bytes;
}
#if !defined(STATIC_BUILD)
/*
| < < | | < | | 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 |
return NULL;
}
return bytes;
}
#if !defined(STATIC_BUILD)
/*
* TclSetObjNameOfShlib --
*
* This function stores the absolute pathname of the Tcl shared library.
*
* Results:
* None.
*
* Side effects:
* Stores the shared library name in the process global database.
*/
void
TclSetObjNameOfShlib(
Tcl_Obj *name,
TCL_UNUSED(Tcl_Encoding))
{
TclSetProcessGlobalValue(&shlibName, name);
}
/*
*----------------------------------------------------------------------
*
* TclGetObjNameOfShlib --
*
* This function retrieves the absolute pathname of the Tcl shared
* library.
|
| ︙ | ︙ | |||
4760 4761 4762 4763 4764 4765 4766 | * integer k such that 2^k <= n. * * This routine is adapted from Andrej Brodnik, "Computation of the * Least Significant Set Bit", pp 7-10, Proceedings of the 2nd * Electrotechnical and Computer Science Conference, Portoroz, * Slovenia, 1993. The adaptations permit the computation to take * place within unsigned long long values without the need for double | | | | | 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 |
* integer k such that 2^k <= n.
*
* This routine is adapted from Andrej Brodnik, "Computation of the
* Least Significant Set Bit", pp 7-10, Proceedings of the 2nd
* Electrotechnical and Computer Science Conference, Portoroz,
* Slovenia, 1993. The adaptations permit the computation to take
* place within unsigned long long values without the need for double
* length buffers for calculation. They also fill in a number of
* details the paper omits or leaves unclear.
*
* Results:
* The index of the most significant set bit in n, a value between
* 0 and 63, inclusive.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TclMSB(
unsigned long long n)
{
/* assert ( 64 == CHAR_BIT * sizeof(unsigned long long) ); */
/* assert ( n != 0 ); */
/*
* Many platforms offer access to this functionality through
* compiler specific incantations that exploit processor
* instructions. Add more as appropriate.
*/
|
| ︙ | ︙ | |||
4914 4915 4916 4917 4918 4919 4920 | * wins and should be used wherever possible, but this isn't bad. */ #undef SUM #undef LEAD #endif } | | | 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 | * wins and should be used wherever possible, but this isn't bad. */ #undef SUM #undef LEAD #endif } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to generic/tclVar.c.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 |
static inline Var *
VarHashCreateVar(
TclVarHashTable *tablePtr,
Tcl_Obj *key,
int *newPtr)
{
| | < | < < < < | < < < < < | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
static inline Var *
VarHashCreateVar(
TclVarHashTable *tablePtr,
Tcl_Obj *key,
int *newPtr)
{
Tcl_HashEntry *hPtr = Tcl_CreateHashEntry(&tablePtr->table, key, newPtr);
if (!hPtr) {
return NULL;
}
return VarHashGetValue(hPtr);
}
#define VarHashFindVar(tablePtr, key) \
VarHashCreateVar((tablePtr), (key), NULL)
#define VarHashInvalidateEntry(varPtr) \
((varPtr)->flags |= VAR_DEAD_HASH)
#define VarHashDeleteEntry(varPtr) \
Tcl_DeleteHashEntry(&(((VarInHash *) varPtr)->entry))
|
| ︙ | ︙ | |||
123 124 125 126 127 128 129 | /* * The strings below are used to indicate what went wrong when a variable * access is denied. */ static const char NOSUCHVAR[] = "no such variable"; | < | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | /* * The strings below are used to indicate what went wrong when a variable * access is denied. */ static const char NOSUCHVAR[] = "no such variable"; static const char ISARRAY[] = "variable is array"; static const char NEEDARRAY[] = "variable isn't array"; static const char NOSUCHELEMENT[] = "no such element in array"; static const char DANGLINGELEMENT[] = "upvar refers to element in deleted array"; static const char DANGLINGVAR[] = "upvar refers to variable in deleted namespace"; |
| ︙ | ︙ | |||
189 190 191 192 193 194 195 | /* * Forward references to functions defined later in this file: */ static void AppendLocals(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *patternPtr, bool includeLinks, bool justConstants); | < < < < < < | < | < < < < < | | | | | < < < < < < < < < < < < < < < < < | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | /* * Forward references to functions defined later in this file: */ static void AppendLocals(Tcl_Interp *interp, Tcl_Obj *listPtr, Tcl_Obj *patternPtr, bool includeLinks, bool justConstants); static void ArrayPopulateSearch(Tcl_Interp *interp, Tcl_Obj *arrayNameObj, Var *varPtr, ArraySearch *searchPtr); static void ArrayDoneSearch(Interp *iPtr, Var *varPtr, ArraySearch *searchPtr); static Tcl_NRPostProc ArrayForLoopCallback; static Tcl_ObjCmdProc ArrayForNRCmd; static void DeleteSearches(Interp *iPtr, Var *arrayVarPtr); static void DeleteArray(Interp *iPtr, Tcl_Obj *arrayNamePtr, Var *varPtr, int flags, int index); static int LocateArray(Tcl_Interp *interp, Tcl_Obj *name, Var **varPtrPtr, int *isArrayPtr); static int NotArrayError(Tcl_Interp *interp, Tcl_Obj *name); static Tcl_Var ObjFindNamespaceVar(Tcl_Interp *interp, Tcl_Obj *namePtr, Tcl_Namespace *contextNsPtr, int flags); static int ObjMakeUpvar(Tcl_Interp *interp, CallFrame *framePtr, Tcl_Obj *otherP1Ptr, const char *otherP2, int otherFlags, Tcl_Obj *myNamePtr, int myFlags, int index); static ArraySearch * ParseSearchId(Tcl_Interp *interp, const Var *varPtr, Tcl_Obj *varNamePtr, Tcl_Obj *handleObj); static void UnsetVarStruct(Var *varPtr, Var *arrayPtr, Interp *iPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int flags, int index); /* * TIP #508: [array default] */ static Tcl_ObjCmdProc ArrayDefaultCmd; static void DeleteArrayVar(Var *arrayPtr); static void SetArrayDefault(Var *arrayPtr, Tcl_Obj *defaultObj); /* * Functions defined in this file that may be exported in the future for use * by the bytecode compiler and engine or to the public interface. */ MODULE_SCOPE Var * TclLookupSimpleVar(Tcl_Interp *interp, Tcl_Obj *varNamePtr, int flags, int create, const char **errMsgPtr, int *indexPtr); static Tcl_DupInternalRepProc DupLocalVarName; static Tcl_FreeInternalRepProc FreeLocalVarName; static Tcl_FreeInternalRepProc FreeParsedVarName; static Tcl_DupInternalRepProc DupParsedVarName; /* * Types of Tcl_Objs used to cache variable lookups. * * localVarName - INTERNALREP DEFINITION: * twoPtrValue.ptr1: pointer to name obj in varFramePtr->localCache * or NULL if it is this same obj * twoPtrValue.ptr2: index into locals table |
| ︙ | ︙ | |||
652 653 654 655 656 657 658 |
Var **arrayPtrPtr) /* If the name refers to an element of an
* array, *arrayPtrPtr gets filled in with
* address of array variable. Otherwise this
* is set to NULL. */
{
Interp *iPtr = (Interp *) interp;
CallFrame *varFramePtr = iPtr->varFramePtr;
| | | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
Var **arrayPtrPtr) /* If the name refers to an element of an
* array, *arrayPtrPtr gets filled in with
* address of array variable. Otherwise this
* is set to NULL. */
{
Interp *iPtr = (Interp *) interp;
CallFrame *varFramePtr = iPtr->varFramePtr;
Var *varPtr; /* Points to the variable's in-frame Var
* structure. */
const char *errMsg = NULL;
int index;
bool parsed = false;
Tcl_Size localIndex;
Tcl_Obj *namePtr, *arrayPtr, *elem;
*arrayPtrPtr = NULL;
restart:
|
| ︙ | ︙ | |||
690 691 692 693 694 695 696 |
/*
* If part1Ptr is a parsedVarNameType, retrieve the preparsed parts.
*/
ParsedGetInternalRep(part1Ptr, parsed, arrayPtr, elem);
if (parsed && arrayPtr) {
| | | | | | | | | | | | | | | | | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
/*
* If part1Ptr is a parsedVarNameType, retrieve the preparsed parts.
*/
ParsedGetInternalRep(part1Ptr, parsed, arrayPtr, elem);
if (parsed && arrayPtr) {
if (part2Ptr != NULL) {
/*
* ERROR: part1Ptr is already an array element, cannot specify
* a part2.
*/
if (flags & TCL_LEAVE_ERR_MSG) {
TclObjVarErrMsg(interp, part1Ptr, part2Ptr, msg,
NOSUCHVAR, -1);
Tcl_SetErrorCode(interp, "TCL", "VALUE", "VARNAME", (char *)NULL);
}
return NULL;
}
part2Ptr = elem;
part1Ptr = arrayPtr;
goto restart;
}
if (!parsed) {
/*
* part1Ptr is possibly an unparsed array element.
*/
|
| ︙ | ︙ | |||
880 881 882 883 884 885 886 |
int flags, /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
* TCL_AVOID_RESOLVERS and TCL_LEAVE_ERR_MSG
* bits matter. */
int create, /* If 1, create hash table entry for varname,
* if it doesn't already exist. If 0, return
* error if it doesn't exist. */
const char **errMsgPtr,
| | | | 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
int flags, /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
* TCL_AVOID_RESOLVERS and TCL_LEAVE_ERR_MSG
* bits matter. */
int create, /* If 1, create hash table entry for varname,
* if it doesn't already exist. If 0, return
* error if it doesn't exist. */
const char **errMsgPtr,
int *indexPtr)
{
Interp *iPtr = (Interp *) interp;
CallFrame *varFramePtr = iPtr->varFramePtr;
/* Points to the procedure call frame whose
* variables are currently in use. Same as the
* current procedure's frame, if any, unless
* an "uplevel" is executing. */
TclVarHashTable *tablePtr; /* Points to the hashtable, if any, in which
* to look up the variable. */
Tcl_Var var; /* Used to search for global names. */
Var *varPtr; /* Points to the Var structure returned for
* the variable. */
Namespace *varNsPtr, *cxtNsPtr, *dummy1Ptr, *dummy2Ptr;
ResolverScheme *resPtr;
int isNew, result;
Tcl_Size i, varLen;
const char *varName = TclGetStringFromObj(varNamePtr, &varLen);
varPtr = NULL;
varNsPtr = NULL; /* Set non-NULL if a nonlocal variable. */
*indexPtr = -3;
|
| ︙ | ︙ | |||
1007 1008 1009 1010 1011 1012 1013 |
return NULL;
}
if (tail != varName) {
tailPtr = Tcl_NewStringObj(tail, -1);
} else {
tailPtr = varNamePtr;
}
| | < < < < | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 |
return NULL;
}
if (tail != varName) {
tailPtr = Tcl_NewStringObj(tail, -1);
} else {
tailPtr = varNamePtr;
}
varPtr = VarHashCreateVar(&varNsPtr->varTable, tailPtr, &isNew);
if (lookGlobal) {
/*
* The variable was created starting from the global
* namespace: a global reference is returned even if it wasn't
* explicitly requested.
*/
|
| ︙ | ︙ | |||
1054 1055 1056 1057 1058 1059 1060 |
if (create) {
if (tablePtr == NULL) {
tablePtr = (TclVarHashTable *)Tcl_Alloc(sizeof(TclVarHashTable));
TclInitVarHashTable(tablePtr, NULL);
tablePtr->arrayPtr = varPtr;
varFramePtr->varTablePtr = tablePtr;
}
| | < < < | 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 |
if (create) {
if (tablePtr == NULL) {
tablePtr = (TclVarHashTable *)Tcl_Alloc(sizeof(TclVarHashTable));
TclInitVarHashTable(tablePtr, NULL);
tablePtr->arrayPtr = varPtr;
varFramePtr->varTablePtr = tablePtr;
}
varPtr = VarHashCreateVar(tablePtr, varNamePtr, &isNew);
} else {
varPtr = NULL;
if (tablePtr != NULL) {
varPtr = VarHashFindVar(tablePtr, varNamePtr);
}
if (varPtr == NULL) {
*errMsgPtr = NOSUCHVAR;
|
| ︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 |
* it isn't one yet and the transformation is
* possible. If 0, return error if it isn't
* already an array. */
int createElem, /* If 1, create hash table entry for the
* element, if it doesn't already exist. If 0,
* return error if it doesn't exist. */
Var *arrayPtr, /* Pointer to the array's Var structure. */
| | | 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 |
* it isn't one yet and the transformation is
* possible. If 0, return error if it isn't
* already an array. */
int createElem, /* If 1, create hash table entry for the
* element, if it doesn't already exist. If 0,
* return error if it doesn't exist. */
Var *arrayPtr, /* Pointer to the array's Var structure. */
int index) /* If >=0, the index of the local array. */
{
int isNew;
Var *varPtr;
/*
* We're dealing with an array element. Make sure the variable is an array
* and look up the element (create the element if desired).
|
| ︙ | ︙ | |||
1178 1179 1180 1181 1182 1183 1184 |
}
return NULL;
}
if (createElem) {
varPtr = VarHashCreateVar(arrayPtr->value.tablePtr, elNamePtr,
&isNew);
| < < < < < < < | | 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 |
}
return NULL;
}
if (createElem) {
varPtr = VarHashCreateVar(arrayPtr->value.tablePtr, elNamePtr,
&isNew);
if (isNew) {
if (arrayPtr->flags & VAR_SEARCH_ACTIVE) {
DeleteSearches((Interp *) interp, arrayPtr);
}
TclSetVarArrayElement(varPtr);
}
} else {
varPtr = VarHashFindVar(arrayPtr->value.tablePtr, elNamePtr);
|
| ︙ | ︙ | |||
1447 1448 1449 1450 1451 1452 1453 |
* containing array otherwise. */
Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or
* the name of a variable. */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, and
* TCL_LEAVE_ERR_MSG bits. */
| | | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 |
* containing array otherwise. */
Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or
* the name of a variable. */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, and
* TCL_LEAVE_ERR_MSG bits. */
int index) /* Index into the local variable table of the
* variable, or -1. Only used when part1Ptr is
* NULL. */
{
Interp *iPtr = (Interp *) interp;
const char *msg;
Var *initialArrayPtr = arrayPtr;
|
| ︙ | ︙ | |||
1547 1548 1549 1550 1551 1552 1553 |
*----------------------------------------------------------------------
*/
int
Tcl_SetObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 |
*----------------------------------------------------------------------
*/
int
Tcl_SetObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *varValueObj;
if (objc == 2) {
varValueObj = Tcl_ObjGetVar2(interp, objv[1], NULL,TCL_LEAVE_ERR_MSG);
if (varValueObj == NULL) {
return TCL_ERROR;
|
| ︙ | ︙ | |||
1975 1976 1977 1978 1979 1980 1981 |
* the name of a variable. NULL if the 'index'
* parameter is >= 0 */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
Tcl_Obj *newValuePtr, /* New value for variable. */
int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, and
* TCL_LEAVE_ERR_MSG bits. */
| | | 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 |
* the name of a variable. NULL if the 'index'
* parameter is >= 0 */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
Tcl_Obj *newValuePtr, /* New value for variable. */
int flags, /* OR-ed combination of TCL_GLOBAL_ONLY, and
* TCL_LEAVE_ERR_MSG bits. */
int index) /* Index of local var where part1 is to be
* found. */
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *oldValuePtr;
Tcl_Obj *resultPtr = NULL;
int result;
int cleanupOnEarlyError = (newValuePtr->refCount == 0);
|
| ︙ | ︙ | |||
2292 2293 2294 2295 2296 2297 2298 |
* part1Ptr. */
Tcl_Obj *incrPtr, /* Increment value. */
/* TODO: Which of these flag values really make sense? */
int flags, /* Various flags that tell how to incr value:
* any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
* TCL_APPEND_VALUE, TCL_LIST_ELEMENT,
* TCL_LEAVE_ERR_MSG. */
| | | 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 |
* part1Ptr. */
Tcl_Obj *incrPtr, /* Increment value. */
/* TODO: Which of these flag values really make sense? */
int flags, /* Various flags that tell how to incr value:
* any of TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
* TCL_APPEND_VALUE, TCL_LIST_ELEMENT,
* TCL_LEAVE_ERR_MSG. */
int index) /* Index into the local variable table of the
* variable, or -1. Only used when part1Ptr is
* NULL. */
{
Tcl_Obj *varValuePtr;
/*
* It's an error to try to increment a constant.
|
| ︙ | ︙ | |||
2527 2528 2529 2530 2531 2532 2533 |
Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or
* the name of a variable. */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
int flags, /* OR-ed combination of any of
* TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
* TCL_LEAVE_ERR_MSG. */
| | | 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 |
Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or
* the name of a variable. */
Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element
* in the array part1. */
int flags, /* OR-ed combination of any of
* TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
* TCL_LEAVE_ERR_MSG. */
int index) /* Index into the local variable table of the
* variable, or -1. Only used when part1Ptr is
* NULL. */
{
Interp *iPtr = (Interp *) interp;
int result = (TclIsVarUndefined(varPtr)? TCL_ERROR : TCL_OK);
Var *initialArrayPtr = arrayPtr;
|
| ︙ | ︙ | |||
2614 2615 2616 2617 2618 2619 2620 |
UnsetVarStruct(
Var *varPtr,
Var *arrayPtr,
Interp *iPtr,
Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr,
int flags,
| | | 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 |
UnsetVarStruct(
Var *varPtr,
Var *arrayPtr,
Interp *iPtr,
Tcl_Obj *part1Ptr,
Tcl_Obj *part2Ptr,
int flags,
int index)
{
Var dummyVar;
int traced = TclIsVarTraced(varPtr)
|| (arrayPtr && (arrayPtr->flags & VAR_TRACED_UNSET));
if (arrayPtr && (arrayPtr->flags & VAR_SEARCH_ACTIVE)) {
DeleteSearches(iPtr, arrayPtr);
|
| ︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 |
Tcl_HashEntry *tPtr;
if (TclIsVarTraced(&dummyVar)) {
/*
* Transfer any existing traces on var, IF there are unset traces.
* Otherwise just delete them.
*/
tPtr = Tcl_FindHashEntry(&iPtr->varTraces, varPtr);
tracePtr = (VarTrace *)Tcl_GetHashValue(tPtr);
varPtr->flags &= ~VAR_ALL_TRACES;
Tcl_DeleteHashEntry(tPtr);
if (dummyVar.flags & VAR_TRACED_UNSET) {
tPtr = Tcl_CreateHashEntry(&iPtr->varTraces,
| > > | > | 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 |
Tcl_HashEntry *tPtr;
if (TclIsVarTraced(&dummyVar)) {
/*
* Transfer any existing traces on var, IF there are unset traces.
* Otherwise just delete them.
*/
int isNew;
tPtr = Tcl_FindHashEntry(&iPtr->varTraces, varPtr);
tracePtr = (VarTrace *)Tcl_GetHashValue(tPtr);
varPtr->flags &= ~VAR_ALL_TRACES;
Tcl_DeleteHashEntry(tPtr);
if (dummyVar.flags & VAR_TRACED_UNSET) {
tPtr = Tcl_CreateHashEntry(&iPtr->varTraces,
&dummyVar, &isNew);
Tcl_SetHashValue(tPtr, tracePtr);
}
}
if ((dummyVar.flags & VAR_TRACED_UNSET)
|| (arrayPtr && (arrayPtr->flags & VAR_TRACED_UNSET))) {
/*
* Pass the array element name to TclObjCallVarTraces(), because
* it cannot be determined from dummyVar. Alternatively, indicate
* via flags whether the variable involved in the code that caused
* the trace to be triggered was an array element, for the correct
* formatting of error messages.
*/
|
| ︙ | ︙ | |||
2793 2794 2795 2796 2797 2798 2799 |
*----------------------------------------------------------------------
*/
int
Tcl_UnsetObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 |
*----------------------------------------------------------------------
*/
int
Tcl_UnsetObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int i;
int flags = TCL_LEAVE_ERR_MSG;
const char *name;
if (objc == 1) {
/*
* Do nothing if no arguments supplied, so as to match command
* documentation.
|
| ︙ | ︙ | |||
2861 2862 2863 2864 2865 2866 2867 |
*----------------------------------------------------------------------
*/
int
Tcl_AppendObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 |
*----------------------------------------------------------------------
*/
int
Tcl_AppendObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Var *varPtr, *arrayPtr;
Tcl_Obj *varValuePtr = NULL;
/* Initialized to avoid compiler warning. */
int i;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "varName ?value ...?");
return TCL_ERROR;
}
if (objc == 2) {
|
| ︙ | ︙ | |||
2926 2927 2928 2929 2930 2931 2932 |
*----------------------------------------------------------------------
*/
int
Tcl_LappendObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 |
*----------------------------------------------------------------------
*/
int
Tcl_LappendObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *varValuePtr, *newValuePtr;
Tcl_Size numElems;
Var *varPtr, *arrayPtr;
int result, createdNewObj;
if (objc < 2) {
|
| ︙ | ︙ | |||
3132 3133 3134 3135 3136 3137 3138 |
return donerc;
}
static int
ArrayForObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 |
return donerc;
}
static int
ArrayForObjCmd(
void *clientData,
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
return Tcl_NRCallObjProc(interp, ArrayForNRCmd, clientData, objc, objv);
}
static int
ArrayForNRCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const *objv)
{
Tcl_Obj *varListObj, *arrayNameObj, *scriptObj;
ArraySearch *searchPtr = NULL;
Var *varPtr;
int isArray;
Tcl_Size numVars;
|
| ︙ | ︙ | |||
3326 3327 3328 3329 3330 3331 3332 |
TclDecrRefCount(varListObj);
TclDecrRefCount(scriptObj);
return result;
}
/*
| < < | | < | < < | 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 |
TclDecrRefCount(varListObj);
TclDecrRefCount(scriptObj);
return result;
}
/*
* ArrayPopulateSearch
*/
static void
ArrayPopulateSearch(
Tcl_Interp *interp,
Tcl_Obj *arrayNameObj,
Var *varPtr,
ArraySearch *searchPtr)
{
|
| ︙ | ︙ | |||
3384 3385 3386 3387 3388 3389 3390 |
*----------------------------------------------------------------------
*/
static int
ArrayStartSearchCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 |
*----------------------------------------------------------------------
*/
static int
ArrayStartSearchCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Var *varPtr;
int isArray;
ArraySearch *searchPtr;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "arrayName");
|
| ︙ | ︙ | |||
3479 3480 3481 3482 3483 3484 3485 |
*----------------------------------------------------------------------
*/
static int
ArrayAnyMoreCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 |
*----------------------------------------------------------------------
*/
static int
ArrayAnyMoreCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Interp *iPtr = (Interp *) interp;
Var *varPtr;
Tcl_Obj *varNameObj, *searchObj;
int gotValue, isArray;
ArraySearch *searchPtr;
|
| ︙ | ︙ | |||
3557 3558 3559 3560 3561 3562 3563 |
*----------------------------------------------------------------------
*/
static int
ArrayNextElementCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 |
*----------------------------------------------------------------------
*/
static int
ArrayNextElementCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Var *varPtr;
Tcl_Obj *varNameObj, *searchObj;
ArraySearch *searchPtr;
int isArray;
if (objc != 3) {
|
| ︙ | ︙ | |||
3637 3638 3639 3640 3641 3642 3643 |
*----------------------------------------------------------------------
*/
static int
ArrayDoneSearchCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 |
*----------------------------------------------------------------------
*/
static int
ArrayDoneSearchCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Interp *iPtr = (Interp *) interp;
Var *varPtr;
Tcl_Obj *varNameObj, *searchObj;
ArraySearch *searchPtr;
int isArray;
|
| ︙ | ︙ | |||
3697 3698 3699 3700 3701 3702 3703 |
*----------------------------------------------------------------------
*/
static int
ArrayExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 |
*----------------------------------------------------------------------
*/
static int
ArrayExistsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Interp *iPtr = (Interp *)interp;
int isArray;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "arrayName");
return TCL_ERROR;
|
| ︙ | ︙ | |||
3737 3738 3739 3740 3741 3742 3743 |
*----------------------------------------------------------------------
*/
static int
ArrayGetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 |
*----------------------------------------------------------------------
*/
static int
ArrayGetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Var *varPtr, *varPtr2;
Tcl_Obj *varNameObj, *nameObj, *valueObj, *nameLstObj, *tmpResObj;
Tcl_Obj **nameObjPtr, *patternObj;
Tcl_HashSearch search;
const char *pattern;
Tcl_Size i, count;
|
| ︙ | ︙ | |||
3897 3898 3899 3900 3901 3902 3903 |
*----------------------------------------------------------------------
*/
static int
ArrayNamesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 |
*----------------------------------------------------------------------
*/
static int
ArrayNamesCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const options[] = {
"-exact", "-glob", "-regexp", NULL
};
enum arrayNamesOptionsEnum {OPT_EXACT, OPT_GLOB, OPT_REGEXP} mode = OPT_GLOB;
Var *varPtr, *varPtr2;
Tcl_Obj *nameObj, *resultObj, *patternObj;
|
| ︙ | ︙ | |||
4003 4004 4005 4006 4007 4008 4009 | } /* *---------------------------------------------------------------------- * * TclFindArrayPtrElements -- * | | | 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 | } /* *---------------------------------------------------------------------- * * TclFindArrayPtrElements -- * * Fill out a hash table (which *must* use Tcl_Obj* keys) with an entry * for each existing element of the given array. The provided hash table * is assumed to be initially empty. * * Result: * none * * Side effects: |
| ︙ | ︙ | |||
4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 |
return;
}
for (varPtr=VarHashFirstVar(arrayPtr->value.tablePtr, &search);
varPtr!=NULL ; varPtr=VarHashNextVar(&search)) {
Tcl_HashEntry *hPtr;
Tcl_Obj *nameObj;
if (TclIsVarUndefined(varPtr)) {
continue;
}
nameObj = VarHashGetKey(varPtr);
| > | | 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 |
return;
}
for (varPtr=VarHashFirstVar(arrayPtr->value.tablePtr, &search);
varPtr!=NULL ; varPtr=VarHashNextVar(&search)) {
Tcl_HashEntry *hPtr;
Tcl_Obj *nameObj;
int dummy;
if (TclIsVarUndefined(varPtr)) {
continue;
}
nameObj = VarHashGetKey(varPtr);
hPtr = Tcl_CreateHashEntry(tablePtr, nameObj, &dummy);
Tcl_SetHashValue(hPtr, nameObj);
}
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
4065 4066 4067 4068 4069 4070 4071 |
*----------------------------------------------------------------------
*/
static int
ArraySetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 |
*----------------------------------------------------------------------
*/
static int
ArraySetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *arrayNameObj;
Tcl_Obj *arrayElemObj;
Var *varPtr, *arrayPtr;
int result;
if (objc != 3) {
|
| ︙ | ︙ | |||
4249 4250 4251 4252 4253 4254 4255 |
*----------------------------------------------------------------------
*/
static int
ArraySizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 |
*----------------------------------------------------------------------
*/
static int
ArraySizeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Var *varPtr;
Tcl_HashSearch search;
Var *varPtr2;
int isArray, size = 0;
if (objc != 2) {
|
| ︙ | ︙ | |||
4308 4309 4310 4311 4312 4313 4314 |
*----------------------------------------------------------------------
*/
static int
ArrayStatsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 |
*----------------------------------------------------------------------
*/
static int
ArrayStatsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Var *varPtr;
Tcl_Obj *varNameObj;
char *stats;
int isArray;
if (objc != 2) {
|
| ︙ | ︙ | |||
4362 4363 4364 4365 4366 4367 4368 |
*----------------------------------------------------------------------
*/
static int
ArrayUnsetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | | 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 |
*----------------------------------------------------------------------
*/
static int
ArrayUnsetCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Var *varPtr, *varPtr2, *protectedVarPtr;
Tcl_Obj *varNameObj, *patternObj, *nameObj;
Tcl_HashSearch search;
const char *pattern;
int unsetFlags = 0; /* Should this be TCL_LEAVE_ERR_MSG? */
int isArray;
switch (objc) {
case 2:
varNameObj = objv[1];
patternObj = NULL;
break;
|
| ︙ | ︙ | |||
4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 |
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ObjMakeUpvar --
*
* This function does all of the work of the "global" and "upvar"
* commands.
*
* Results:
* A standard Tcl completion code. If an error occurs then an error
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 |
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclInitArrayCmd --
*
* This creates the ensemble for the "array" command.
*
* Results:
* The handle for the created ensemble.
*
* Side effects:
* Creates a command in the global namespace.
*
*----------------------------------------------------------------------
*/
Tcl_Command
TclInitArrayCmd(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap arrayImplMap[] = {
{"anymore", ArrayAnyMoreCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"default", ArrayDefaultCmd, TclCompileBasic2Or3ArgCmd, NULL, NULL, 0},
{"donesearch", ArrayDoneSearchCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"exists", ArrayExistsCmd, TclCompileArrayExistsCmd, NULL, NULL, 0},
{"for", ArrayForObjCmd, TclCompileBasic3ArgCmd, ArrayForNRCmd, NULL, 0},
{"get", ArrayGetCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"names", ArrayNamesCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0},
{"nextelement", ArrayNextElementCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"set", ArraySetCmd, TclCompileArraySetCmd, NULL, NULL, 0},
{"size", ArraySizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"startsearch", ArrayStartSearchCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"statistics", ArrayStatsCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"unset", ArrayUnsetCmd, TclCompileArrayUnsetCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
return TclMakeEnsemble(interp, "array", arrayImplMap);
}
/*
*----------------------------------------------------------------------
*
* ObjMakeUpvar --
*
* This function does all of the work of the "global" and "upvar"
* commands.
*
* Results:
* A standard Tcl completion code. If an error occurs then an error
|
| ︙ | ︙ | |||
4514 4515 4516 4517 4518 4519 4520 |
const char *otherP2, /* Two-part name of variable in framePtr. */
int otherFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of "other" variable. */
Tcl_Obj *myNamePtr, /* Name of variable which will refer to
* otherP1/otherP2. Must be a scalar. */
int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of myName. */
| | | 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 |
const char *otherP2, /* Two-part name of variable in framePtr. */
int otherFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of "other" variable. */
Tcl_Obj *myNamePtr, /* Name of variable which will refer to
* otherP1/otherP2. Must be a scalar. */
int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of myName. */
int index) /* If the variable to be linked is an indexed
* scalar, this is its index. Otherwise, -1 */
{
Interp *iPtr = (Interp *) interp;
Var *otherPtr, *arrayPtr;
CallFrame *varFramePtr;
/*
|
| ︙ | ︙ | |||
4601 4602 4603 4604 4605 4606 4607 |
Tcl_Interp *interp, /* Interpreter containing variables. Used for
* error messages, too. */
Var *otherPtr, /* Pointer to the variable being linked-to. */
const char *myName, /* Name of variable which will refer to
* otherP1/otherP2. Must be a scalar. */
int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of myName. */
| | | 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 |
Tcl_Interp *interp, /* Interpreter containing variables. Used for
* error messages, too. */
Var *otherPtr, /* Pointer to the variable being linked-to. */
const char *myName, /* Name of variable which will refer to
* otherP1/otherP2. Must be a scalar. */
int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of myName. */
int index) /* If the variable to be linked is an indexed
* scalar, this is its index. Otherwise, -1 */
{
Tcl_Obj *myNamePtr = NULL;
int result;
if (myName) {
myNamePtr = Tcl_NewStringObj(myName, -1);
|
| ︙ | ︙ | |||
4644 4645 4646 4647 4648 4649 4650 |
Tcl_Interp *interp, /* Interpreter containing variables. Used for
* error messages, too. */
Var *otherPtr, /* Pointer to the variable being linked-to. */
Tcl_Obj *myNamePtr, /* Name of variable which will refer to
* otherP1/otherP2. Must be a scalar. */
int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of myName. */
| | | 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 |
Tcl_Interp *interp, /* Interpreter containing variables. Used for
* error messages, too. */
Var *otherPtr, /* Pointer to the variable being linked-to. */
Tcl_Obj *myNamePtr, /* Name of variable which will refer to
* otherP1/otherP2. Must be a scalar. */
int myFlags, /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of myName. */
int index) /* If the variable to be linked is an indexed
* scalar, this is its index. Otherwise, -1 */
{
Interp *iPtr = (Interp *) interp;
CallFrame *varFramePtr = iPtr->varFramePtr;
const char *errMsg, *p, *myName;
Var *varPtr;
|
| ︙ | ︙ | |||
4890 4891 4892 4893 4894 4895 4896 |
*----------------------------------------------------------------------
*/
int
Tcl_ConstObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 |
*----------------------------------------------------------------------
*/
int
Tcl_ConstObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Var *varPtr, *arrayPtr;
Tcl_Obj *part1Ptr;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "varName value");
return TCL_ERROR;
|
| ︙ | ︙ | |||
4968 4969 4970 4971 4972 4973 4974 |
*----------------------------------------------------------------------
*/
int
Tcl_GlobalObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 |
*----------------------------------------------------------------------
*/
int
Tcl_GlobalObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *objPtr, *tailPtr;
const char *varName;
const char *tail;
int result;
int i;
/*
* If we are not executing inside a Tcl procedure, just return.
*/
if (!HasLocalVars(iPtr->varFramePtr)) {
return TCL_OK;
|
| ︙ | ︙ | |||
5073 5074 5075 5076 5077 5078 5079 |
*----------------------------------------------------------------------
*/
int
Tcl_VariableObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 |
*----------------------------------------------------------------------
*/
int
Tcl_VariableObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
const char *varName, *tail, *cp;
Var *varPtr, *arrayPtr;
Tcl_Obj *varValuePtr;
int i;
int result;
Tcl_Obj *varNamePtr, *tailPtr;
for (i=1 ; i<objc ; i+=2) {
/*
* Look up each variable in the current namespace context, creating it
* if necessary.
*/
|
| ︙ | ︙ | |||
5207 5208 5209 5210 5211 5212 5213 |
*----------------------------------------------------------------------
*/
int
Tcl_UpvarObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 |
*----------------------------------------------------------------------
*/
int
Tcl_UpvarObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
CallFrame *framePtr;
int result, hasLevel;
Tcl_Obj *levelObj;
if (objc < 3) {
Tcl_WrongNumArgs(interp, 1, objv,
|
| ︙ | ︙ | |||
5610 5611 5612 5613 5614 5615 5616 |
Tcl_Obj *arrayNamePtr, /* Name of array (used for trace callbacks),
* or NULL if it is to be computed on
* demand. */
Var *varPtr, /* Pointer to variable structure. */
int flags, /* Flags to pass to TclCallVarTraces:
* TCL_TRACE_UNSETS and sometimes
* TCL_NAMESPACE_ONLY or TCL_GLOBAL_ONLY. */
| | | 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 |
Tcl_Obj *arrayNamePtr, /* Name of array (used for trace callbacks),
* or NULL if it is to be computed on
* demand. */
Var *varPtr, /* Pointer to variable structure. */
int flags, /* Flags to pass to TclCallVarTraces:
* TCL_TRACE_UNSETS and sometimes
* TCL_NAMESPACE_ONLY or TCL_GLOBAL_ONLY. */
int index)
{
Tcl_HashSearch search;
Tcl_HashEntry *tPtr;
Var *elPtr;
ActiveVarTrace *activePtr;
Tcl_Obj *objPtr;
VarTrace *tracePtr;
|
| ︙ | ︙ | |||
5727 5728 5729 5730 5731 5732 5733 |
TclObjVarErrMsg(
Tcl_Interp *interp, /* Interpreter in which to record message. */
Tcl_Obj *part1Ptr, /* (may be NULL, if index >= 0) */
Tcl_Obj *part2Ptr, /* Variable's two-part name. */
const char *operation, /* String describing operation that failed,
* e.g. "read", "set", or "unset". */
const char *reason, /* String describing why operation failed. */
| | | 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 |
TclObjVarErrMsg(
Tcl_Interp *interp, /* Interpreter in which to record message. */
Tcl_Obj *part1Ptr, /* (may be NULL, if index >= 0) */
Tcl_Obj *part2Ptr, /* Variable's two-part name. */
const char *operation, /* String describing operation that failed,
* e.g. "read", "set", or "unset". */
const char *reason, /* String describing why operation failed. */
int index) /* Index into the local variable table of the
* variable, or -1. Only used when part1Ptr is
* NULL. */
{
if (!part1Ptr) {
if (index == -1) {
Tcl_Panic("invalid part1Ptr and invalid index together");
}
|
| ︙ | ︙ | |||
6023 6024 6025 6026 6027 6028 6029 |
*----------------------------------------------------------------------
*/
int
TclInfoVarsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 |
*----------------------------------------------------------------------
*/
int
TclInfoVarsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
const char *varName, *pattern, *simplePattern;
Tcl_HashSearch search;
Var *varPtr;
Namespace *nsPtr;
Namespace *currNsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
|
| ︙ | ︙ | |||
6174 6175 6176 6177 6178 6179 6180 |
*----------------------------------------------------------------------
*/
int
TclInfoGlobalsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 |
*----------------------------------------------------------------------
*/
int
TclInfoGlobalsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *varName, *pattern;
Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp);
Tcl_HashSearch search;
Var *varPtr;
Tcl_Obj *listPtr, *varNamePtr, *patternPtr;
|
| ︙ | ︙ | |||
6267 6268 6269 6270 6271 6272 6273 |
*----------------------------------------------------------------------
*/
int
TclInfoLocalsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 |
*----------------------------------------------------------------------
*/
int
TclInfoLocalsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
Tcl_Obj *patternPtr, *listPtr;
if (objc == 1) {
patternPtr = NULL;
} else if (objc == 2) {
|
| ︙ | ︙ | |||
6326 6327 6328 6329 6330 6331 6332 |
*----------------------------------------------------------------------
*/
int
TclInfoConstsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 |
*----------------------------------------------------------------------
*/
int
TclInfoConstsCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Interp *iPtr = (Interp *) interp;
const char *varName, *pattern, *simplePattern;
Tcl_HashSearch search;
Var *varPtr;
Namespace *nsPtr;
Namespace *globalNsPtr = (Namespace *) Tcl_GetGlobalNamespace(interp);
|
| ︙ | ︙ | |||
6725 6726 6727 6728 6729 6730 6731 |
*----------------------------------------------------------------------
*/
int
TclInfoConstantCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 |
*----------------------------------------------------------------------
*/
int
TclInfoConstantCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Var *varPtr, *arrayPtr;
int result;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "varName");
return TCL_ERROR;
|
| ︙ | ︙ | |||
6766 6767 6768 6769 6770 6771 6772 |
TCL_UNUSED(Tcl_HashTable *),
void *keyPtr) /* Key to store in the hash table entry. */
{
Tcl_Obj *objPtr = (Tcl_Obj *)keyPtr;
Tcl_HashEntry *hPtr;
Var *varPtr;
| | < < < | 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 |
TCL_UNUSED(Tcl_HashTable *),
void *keyPtr) /* Key to store in the hash table entry. */
{
Tcl_Obj *objPtr = (Tcl_Obj *)keyPtr;
Tcl_HashEntry *hPtr;
Var *varPtr;
varPtr = (Var *)Tcl_Alloc(sizeof(VarInHash));
varPtr->flags = VAR_IN_HASHTABLE;
varPtr->value.objPtr = NULL;
VarHashRefCount(varPtr) = 1;
hPtr = &(((VarInHash *) varPtr)->entry);
Tcl_SetHashValue(hPtr, varPtr);
hPtr->key.objPtr = objPtr;
|
| ︙ | ︙ | |||
6831 6832 6833 6834 6835 6836 6837 |
p2 = TclGetString(objPtr2);
l2 = objPtr2->length;
/*
* Only compare string representations of the same length.
*/
| | | 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 |
p2 = TclGetString(objPtr2);
l2 = objPtr2->length;
/*
* Only compare string representations of the same length.
*/
return ((l1 == l2) && !memcmp(p1, p2, l1));
}
/*----------------------------------------------------------------------
*
* ArrayDefaultCmd --
*
* This function implements the 'array default' Tcl command.
|
| ︙ | ︙ | |||
6854 6855 6856 6857 6858 6859 6860 |
*----------------------------------------------------------------------
*/
static int
ArrayDefaultCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 |
*----------------------------------------------------------------------
*/
static int
ArrayDefaultCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const options[] = {
"get", "set", "exists", "unset", NULL
};
enum arrayDefaultOptionsEnum { OPT_GET, OPT_SET, OPT_EXISTS, OPT_UNSET } option;
Tcl_Obj *arrayNameObj, *defaultValueObj;
Var *varPtr, *arrayPtr;
|
| ︙ | ︙ | |||
6991 6992 6993 6994 6995 6996 6997 |
default:
TCL_UNREACHABLE();
}
}
/*
| < < < < | | | < | < | 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 |
default:
TCL_UNREACHABLE();
}
}
/*
* Initialize array variable.
*/
void
TclInitArrayVar(
Var *arrayPtr)
{
ArrayVarHashTable *tablePtr = (ArrayVarHashTable *)Tcl_Alloc(sizeof(ArrayVarHashTable));
/*
* Mark the variable as an array.
*/
TclSetVarArray(arrayPtr);
|
| ︙ | ︙ | |||
7028 7029 7030 7031 7032 7033 7034 |
* Default value initialization.
*/
tablePtr->defaultObj = NULL;
}
/*
| < < < < | | | < | 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 |
* Default value initialization.
*/
tablePtr->defaultObj = NULL;
}
/*
* Cleanup array variable.
*/
static void
DeleteArrayVar(
Var *arrayPtr)
{
ArrayVarHashTable *tablePtr = (ArrayVarHashTable *)
arrayPtr->value.tablePtr;
|
| ︙ | ︙ | |||
7058 7059 7060 7061 7062 7063 7064 |
*/
VarHashDeleteTable(arrayPtr->value.tablePtr);
Tcl_Free(tablePtr);
}
/*
| < < < < | | | < < < < < | | | < | 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 |
*/
VarHashDeleteTable(arrayPtr->value.tablePtr);
Tcl_Free(tablePtr);
}
/*
* Get array default value if any.
*/
Tcl_Obj *
TclGetArrayDefault(
Var *arrayPtr)
{
ArrayVarHashTable *tablePtr = (ArrayVarHashTable *)
arrayPtr->value.tablePtr;
return tablePtr->defaultObj;
}
/*
* Set/replace/unset array default value.
*/
static void
SetArrayDefault(
Var *arrayPtr,
Tcl_Obj *defaultObj)
{
ArrayVarHashTable *tablePtr = (ArrayVarHashTable *)
arrayPtr->value.tablePtr;
|
| ︙ | ︙ |
Changes to generic/tclZipfs.c.
| ︙ | ︙ | |||
80 81 82 83 84 85 86 | #include "crypt.h" #include "zutil.h" #include "crc32.h" static const z_crc_t* crc32tab; /* | | | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #include "crypt.h" #include "zutil.h" #include "crc32.h" static const z_crc_t* crc32tab; /* ** We are compiling as part of the core. ** TIP430 style zipfs prefix */ #define ZIPFS_VOLUME "//zipfs:/" #define ZIPFS_ROOTDIR_DEPTH 3 /* Number of / in root mount */ #define ZIPFS_VOLUME_LEN 9 #define ZIPFS_APP_MOUNT ZIPFS_VOLUME "app" #define ZIPFS_ZIP_MOUNT ZIPFS_VOLUME "lib/tcl" #define ZIPFS_FALLBACK_ENCODING "cp437" |
| ︙ | ︙ | |||
474 475 476 477 478 479 480 | int mask); static int ZipChannelWrite(void *instanceData, const char *buf, int toWrite, int *errloc); static int TclZipfsInitEncodingDirs(void); static int TclZipfsMountExe(void); static int TclZipfsMountShlib(void); | < < < < < < < < < < < < < < | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
int mask);
static int ZipChannelWrite(void *instanceData,
const char *buf, int toWrite, int *errloc);
static int TclZipfsInitEncodingDirs(void);
static int TclZipfsMountExe(void);
static int TclZipfsMountShlib(void);
/*
* Define the ZIP filesystem dispatch table.
*/
static const Tcl_Filesystem zipfsFilesystem = {
"zipfs",
sizeof(Tcl_Filesystem),
|
| ︙ | ︙ | |||
548 549 550 551 552 553 554 |
NULL, /* Set blocking mode for raw channel. */
NULL, /* Function to flush channel. */
NULL, /* Function to handle bubbled events. */
ZipChannelWideSeek,
NULL, /* Thread action function. */
NULL, /* Truncate function. */
};
| < < < < < < < < < < < < < < < < < < < < < | | | | | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
NULL, /* Set blocking mode for raw channel. */
NULL, /* Function to flush channel. */
NULL, /* Function to handle bubbled events. */
ZipChannelWideSeek,
NULL, /* Thread action function. */
NULL, /* Truncate function. */
};
/*
*------------------------------------------------------------------------
*
* TclIsZipfsPath --
*
* Checks if the passed path has a zipfs volume prefix.
*
* Results:
* 0 if not a zipfs path
* else the length of the zipfs volume prefix
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
int
TclIsZipfsPath(
const char *path)
{
#ifdef _WIN32
return strncmp(path, ZIPFS_VOLUME, ZIPFS_VOLUME_LEN) ? 0 : ZIPFS_VOLUME_LEN;
#else
int i;
for (i = 0; i < ZIPFS_VOLUME_LEN; ++i) {
if (path[i] != ZIPFS_VOLUME[i] &&
(path[i] != '\\' || ZIPFS_VOLUME[i] != '/')) {
return 0;
}
}
return ZIPFS_VOLUME_LEN;
#endif
}
/*
*-------------------------------------------------------------------------
*
* ZipReadInt, ZipReadShort, ZipWriteInt, ZipWriteShort --
*
* Inline functions to read and write little-endian 16 and 32 bit
* integers from/to buffers representing parts of ZIP archives.
|
| ︙ | ︙ | |||
677 678 679 680 681 682 683 |
if (ptr < bufferStart || ptr + 2 > bufferEnd) {
Tcl_Panic("out of bounds write(2): start=%p, end=%p, ptr=%p",
bufferStart, bufferEnd, ptr);
}
ptr[0] = value & 0xff;
ptr[1] = (value >> 8) & 0xff;
}
| | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 |
if (ptr < bufferStart || ptr + 2 > bufferEnd) {
Tcl_Panic("out of bounds write(2): start=%p, end=%p, ptr=%p",
bufferStart, bufferEnd, ptr);
}
ptr[0] = value & 0xff;
ptr[1] = (value >> 8) & 0xff;
}
/*
* Need a separate mutex for locating libraries because the search calls
* TclZipfs_Mount which takes out a write lock on the ZipFSMutex. Since
* those cannot be nested, we need a separate mutex.
*/
TCL_DECLARE_MUTEX(ZipFSLocateLibMutex)
|
| ︙ | ︙ | |||
712 713 714 715 716 717 718 |
static inline void
ReadLock(void)
{
Tcl_MutexLock(&ZipFSMutex);
while (ZipFS.lock < 0) {
ZipFS.waiters++;
| | | | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
static inline void
ReadLock(void)
{
Tcl_MutexLock(&ZipFSMutex);
while (ZipFS.lock < 0) {
ZipFS.waiters++;
Tcl_ConditionWait(&ZipFSCond, &ZipFSMutex, NULL);
ZipFS.waiters--;
}
ZipFS.lock++;
Tcl_MutexUnlock(&ZipFSMutex);
}
static inline void
WriteLock(void)
{
Tcl_MutexLock(&ZipFSMutex);
while (ZipFS.lock != 0) {
ZipFS.waiters++;
Tcl_ConditionWait(&ZipFSCond, &ZipFSMutex, NULL);
ZipFS.waiters--;
}
ZipFS.lock = -1;
Tcl_MutexUnlock(&ZipFSMutex);
}
static inline void
|
| ︙ | ︙ | |||
873 874 875 876 877 878 879 | } /* *------------------------------------------------------------------------ * * IsCryptHeaderValid -- * | | | | | 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 |
}
/*
*------------------------------------------------------------------------
*
* IsCryptHeaderValid --
*
* Computes the validity of the encryption header CRC for a ZipEntry.
*
* Results:
* Returns 1 if the header is valid else 0.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static int
IsCryptHeaderValid(
ZipEntry *z,
unsigned char cryptHeader[ZIP_CRYPT_HDR_LEN])
|
| ︙ | ︙ | |||
908 909 910 911 912 913 914 |
if (cryptHeader[11] == (unsigned char)(dosTime >> 8)) {
/* Infozip style - Tested with test-password.zip */
return 1;
}
/* DOS time did not match, may be CRC does */
if (z->crc32) {
/* Pkware style - Tested with test-password2.zip */
| | | | | | | | 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 |
if (cryptHeader[11] == (unsigned char)(dosTime >> 8)) {
/* Infozip style - Tested with test-password.zip */
return 1;
}
/* DOS time did not match, may be CRC does */
if (z->crc32) {
/* Pkware style - Tested with test-password2.zip */
return (cryptHeader[11] == (unsigned char)(z->crc32 >> 24));
}
/* No CRC, no way to verify. Assume valid */
return 1;
}
/*
*------------------------------------------------------------------------
*
* DecodeCryptHeader --
*
* Decodes the crypt header and validates it.
*
* Results:
* TCL_OK on success, TCL_ERROR on failure.
*
* Side effects:
* On success, keys[] are updated. On failure, an error message is
* left in interp if not NULL.
*
*------------------------------------------------------------------------
*/
static int
DecodeCryptHeader(
Tcl_Interp *interp,
ZipEntry *z,
|
| ︙ | ︙ | |||
967 968 969 970 971 972 973 |
if (!IsCryptHeaderValid(z, encheader)) {
ZIPFS_ERROR(interp, "invalid password");
ZIPFS_ERROR_CODE(interp, "PASSWORD");
return TCL_ERROR;
}
return TCL_OK;
}
| | | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 |
if (!IsCryptHeaderValid(z, encheader)) {
ZIPFS_ERROR(interp, "invalid password");
ZIPFS_ERROR_CODE(interp, "PASSWORD");
return TCL_ERROR;
}
return TCL_OK;
}
/*
*-------------------------------------------------------------------------
*
* DecodeZipEntryText --
*
* Given a sequence of bytes from an entry in a ZIP central directory,
* convert that into a Tcl string. This is complicated because we don't
|
| ︙ | ︙ | |||
1000 1001 1002 1003 1004 1005 1006 |
static char *
DecodeZipEntryText(
const unsigned char *inputBytes,
unsigned int inputLength,
Tcl_DString *dstPtr) /* Must have been initialized by caller! */
{
Tcl_Encoding encoding;
| | | | < < < < < < < < < < | | > | | | < < < | > > > | > > > > > > > > | > > > > > > > > > > > > > | 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 |
static char *
DecodeZipEntryText(
const unsigned char *inputBytes,
unsigned int inputLength,
Tcl_DString *dstPtr) /* Must have been initialized by caller! */
{
Tcl_Encoding encoding;
const char *src;
char *dst;
int dstLen, srcLen = inputLength, flags;
Tcl_EncodingState state;
if (inputLength < 1) {
return Tcl_DStringValue(dstPtr);
}
/*
* We can't use Tcl_ExternalToUtfDString at this point; it has no way to
* fail. So we use this modified version of it that can report encoding
* errors to us (so we can fall back to something else).
*
* The utf-8 encoding is implemented internally, and so is guaranteed to
* be present.
*/
src = (const char *) inputBytes;
dst = Tcl_DStringValue(dstPtr);
dstLen = dstPtr->spaceAvl - 1;
flags = TCL_ENCODING_START | TCL_ENCODING_END; /* Special flag! */
while (1) {
int srcRead, dstWrote;
int result = Tcl_ExternalToUtf(NULL, tclUtf8Encoding, src, srcLen, flags,
&state, dst, dstLen, &srcRead, &dstWrote, NULL);
int soFar = dst + dstWrote - Tcl_DStringValue(dstPtr);
if (result == TCL_OK) {
Tcl_DStringSetLength(dstPtr, soFar);
return Tcl_DStringValue(dstPtr);
} else if (result != TCL_CONVERT_NOSPACE) {
break;
}
flags &= ~TCL_ENCODING_START;
src += srcRead;
srcLen -= srcRead;
if (Tcl_DStringLength(dstPtr) == 0) {
Tcl_DStringSetLength(dstPtr, dstLen);
}
Tcl_DStringSetLength(dstPtr, 2 * Tcl_DStringLength(dstPtr) + 1);
dst = Tcl_DStringValue(dstPtr) + soFar;
dstLen = Tcl_DStringLength(dstPtr) - soFar - 1;
}
/*
* Something went wrong. Fall back to another encoding. Those *can* use
* Tcl_ExternalToUtfDString().
*/
|
| ︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | } /* *------------------------------------------------------------------------ * * NormalizeMountPoint -- * | | | | | | | | | | | | | | 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 |
}
/*
*------------------------------------------------------------------------
*
* NormalizeMountPoint --
*
* Converts the passed path into a normalized zipfs mount point
* of the form //zipfs:/some/path. On Windows any \ path separators
* are converted to /.
*
* Mount points with a volume will raise an error unless the volume is
* zipfs root. Thus D:/foo is not a valid mount point.
*
* Relative paths and absolute paths without a volume are mapped under
* the zipfs root.
*
* The empty string is mapped to the zipfs root.
*
* dsPtr is initialized by the function and must be cleared by caller
* on a successful return.
*
* Results:
* TCL_OK on success with normalized mount path in dsPtr
* TCL_ERROR on fail with error message in interp if not NULL
*
*------------------------------------------------------------------------
*/
static int
NormalizeMountPoint(
Tcl_Interp *interp,
const char *mountPath,
|
| ︙ | ︙ | |||
1157 1158 1159 1160 1161 1162 1163 |
ZIPFS_ERROR_CODE(interp, "MOUNT_PATH");
}
errorReturn:
Tcl_DStringFree(&dsJoin);
return TCL_ERROR;
}
| | | | | | | | | | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 |
ZIPFS_ERROR_CODE(interp, "MOUNT_PATH");
}
errorReturn:
Tcl_DStringFree(&dsJoin);
return TCL_ERROR;
}
/*
*------------------------------------------------------------------------
*
* MapPathToZipfs --
*
* Maps a path as stored in a zip archive to its normalized location
* under a given zipfs mount point. Relative paths and Unix style
* absolute paths go directly under the mount point. Volume relative
* paths and absolute paths that have a volume (drive or UNC) are
* stripped of the volume before joining the mount point.
*
* Results:
* Pointer to normalized path.
*
* Side effects:
* Stores mapped path in dsPtr.
*
*------------------------------------------------------------------------
*/
static char *
MapPathToZipfs(
Tcl_Interp *interp,
const char *mountPath, /* Must be fully normalized */
|
| ︙ | ︙ | |||
1303 1304 1305 1306 1307 1308 1309 | } /* *------------------------------------------------------------------------ * * ContainsMountPoint -- * | | | | | | | | | | 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 |
}
/*
*------------------------------------------------------------------------
*
* ContainsMountPoint --
*
* Check if there is a mount point anywhere under the specified path.
* Although the function will work for any path, for efficiency reasons
* it should be called only after checking ZipFSLookup does not find
* the path.
*
* Caller must hold read lock before calling.
*
* Results:
* 1 - there is at least one mount point under the path
* 0 - otherwise
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static int
ContainsMountPoint(
const char *path,
int pathLen)
|
| ︙ | ︙ | |||
1369 1370 1371 1372 1373 1374 1375 |
&& (strncmp(zf->mountPoint, path, pathLen) == 0)) {
/* Matched standard mount */
return 1;
}
}
return 0;
}
| | | 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 |
&& (strncmp(zf->mountPoint, path, pathLen) == 0)) {
/* Matched standard mount */
return 1;
}
}
return 0;
}
/*
*-------------------------------------------------------------------------
*
* AllocateZipFile, AllocateZipEntry, AllocateZipChannel --
*
* Allocates the memory for a datastructure. Always ensures that it is
* zeroed out for safety.
|
| ︙ | ︙ | |||
1505 1506 1507 1508 1509 1510 1511 | * is accepted. Note that we do not support ZIP64. * * Results: * TCL_OK on success, TCL_ERROR otherwise with an error message placed * into the given "interp" if it is not NULL. * * Side effects: | | | | | 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 |
* is accepted. Note that we do not support ZIP64.
*
* Results:
* TCL_OK on success, TCL_ERROR otherwise with an error message placed
* into the given "interp" if it is not NULL.
*
* Side effects:
* The given ZipFile struct is filled with information about the ZIP
* archive file. On error, ZipFSCloseArchive is called on zf but
* it is not freed.
*
*-------------------------------------------------------------------------
*/
static int
ZipFSFindTOC(
Tcl_Interp *interp, /* Current interpreter. NULLable. */
|
| ︙ | ︙ | |||
1553 1554 1555 1556 1557 1558 1559 |
if (!needZip) {
zf->baseOffset = zf->passOffset = zf->length;
return TCL_OK;
}
ZIPFS_ERROR(interp, "archive directory end signature not found");
ZIPFS_ERROR_CODE(interp, "END_SIG");
| | > | 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 |
if (!needZip) {
zf->baseOffset = zf->passOffset = zf->length;
return TCL_OK;
}
ZIPFS_ERROR(interp, "archive directory end signature not found");
ZIPFS_ERROR_CODE(interp, "END_SIG");
error:
ZipFSCloseArchive(interp, zf);
return TCL_ERROR;
}
/*
* eocdPtr -> End of Central Directory (EOCD) record at this point.
* Note this is not same as "end of Central Directory" :-) as EOCD
* is a record/structure in the ZIP spec terminology
*/
|
| ︙ | ︙ | |||
1705 1706 1707 1708 1709 1710 1711 | * buffer. The ZIP archive header is verified and must be valid for the * function to succeed. When "needZip" is zero an embedded ZIP archive in * an executable file is accepted. * * Results: * TCL_OK on success, TCL_ERROR otherwise with an error message placed * into the given "interp" if it is not NULL. On error, ZipFSCloseArchive | | | 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 | * buffer. The ZIP archive header is verified and must be valid for the * function to succeed. When "needZip" is zero an embedded ZIP archive in * an executable file is accepted. * * Results: * TCL_OK on success, TCL_ERROR otherwise with an error message placed * into the given "interp" if it is not NULL. On error, ZipFSCloseArchive * is called on zf but it is not freed. * * Side effects: * ZIP archive is memory mapped or read into allocated memory, the given * ZipFile struct is filled with information about the ZIP archive file. * *------------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
2053 2054 2055 2056 2057 2058 2059 |
z->isDirectory = (zf->baseOffset == 0) ? 1 : -1; /* root marker */
z->offset = zf->baseOffset;
z->compressMethod = ZIP_COMPMETH_STORED;
z->name = (char *) Tcl_GetHashKey(&ZipFS.fileHash, hPtr);
if (!strcmp(z->name, ZIPFS_VOLUME)) {
z->flags |= ZE_F_VOLUME; /* Mark as root volume */
}
| > > | > | 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 |
z->isDirectory = (zf->baseOffset == 0) ? 1 : -1; /* root marker */
z->offset = zf->baseOffset;
z->compressMethod = ZIP_COMPMETH_STORED;
z->name = (char *) Tcl_GetHashKey(&ZipFS.fileHash, hPtr);
if (!strcmp(z->name, ZIPFS_VOLUME)) {
z->flags |= ZE_F_VOLUME; /* Mark as root volume */
}
Tcl_Time t;
Tcl_GetTime(&t);
z->timestamp = t.sec;
z->next = zf->entries;
zf->entries = z;
}
}
q = zf->data + zf->directoryOffset;
Tcl_DStringInit(&fpBuf);
for (i = 0; i < zf->numFiles; i++) {
const unsigned char *start = zf->data;
const unsigned char *end = zf->data + zf->length;
int extra, isdir = 0, dosTime, dosDate, nbcompr;
size_t offs, pathlen, comlen;
unsigned char *lq, *gq = NULL;
char *fullpath, *path;
pathlen = ZipReadShort(start, end, q + ZIP_CENTRAL_PATHLEN_OFFS);
comlen = ZipReadShort(start, end, q + ZIP_CENTRAL_FCOMMENTLEN_OFFS);
extra = ZipReadShort(start, end, q + ZIP_CENTRAL_EXTRALEN_OFFS);
Tcl_DStringSetLength(&ds, 0);
path = DecodeZipEntryText(q + ZIP_CENTRAL_HEADER_LEN, pathlen, &ds);
if ((pathlen > 0) && (path[pathlen - 1] == '/')) {
Tcl_DStringSetLength(&ds, pathlen - 1);
path = Tcl_DStringValue(&ds);
isdir = 1;
}
if ((strcmp(path, ".") == 0) || (strcmp(path, "..") == 0)) {
|
| ︙ | ︙ | |||
2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 |
*-------------------------------------------------------------------------
*/
static void
ZipfsSetup(void)
{
#if TCL_THREADS
/*
* Inflate condition variable.
*/
Tcl_MutexLock(&ZipFSMutex);
| > > | | 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 |
*-------------------------------------------------------------------------
*/
static void
ZipfsSetup(void)
{
#if TCL_THREADS
static const Tcl_Time t = { 0, 0 };
/*
* Inflate condition variable.
*/
Tcl_MutexLock(&ZipFSMutex);
Tcl_ConditionWait(&ZipFSCond, &ZipFSMutex, &t);
Tcl_MutexUnlock(&ZipFSMutex);
#endif /* TCL_THREADS */
crc32tab = get_crc_table();
Tcl_FSRegister(NULL, &zipfsFilesystem);
Tcl_InitHashTable(&ZipFS.fileHash, TCL_STRING_KEYS);
Tcl_InitHashTable(&ZipFS.zipHash, TCL_STRING_KEYS);
|
| ︙ | ︙ | |||
2323 2324 2325 2326 2327 2328 2329 | } /* *------------------------------------------------------------------------ * * CleanupMount -- * | | | | | | < | 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 |
}
/*
*------------------------------------------------------------------------
*
* CleanupMount --
*
* Releases all resources associated with a mounted archive. There
* must not be any open files in the archive.
*
* Caller MUST be holding WriteLock() before calling this function.
*
* Results:
* None.
*
* Side effects:
* Memory associated with the mounted archive is deallocated.
*------------------------------------------------------------------------
*/
static void
CleanupMount(
ZipFile *zf) /* Mount point */
{
ZipEntry *z, *znext;
|
| ︙ | ︙ | |||
2355 2356 2357 2358 2359 2360 2361 |
if (z->data) {
Tcl_Free(z->data);
}
Tcl_Free(z);
}
zf->entries = NULL;
}
| | > | 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 |
if (z->data) {
Tcl_Free(z->data);
}
Tcl_Free(z);
}
zf->entries = NULL;
}
/*
*-------------------------------------------------------------------------
*
* DescribeMounted --
*
* This procedure describes what is mounted at the given the mount point.
* The interpreter result is not updated if there is nothing mounted at
* the given point. The read lock must be held by the caller.
*
* Results:
* A standard Tcl result. TCL_OK (or TCL_BREAK if nothing mounted there
* and no interpreter).
*
* Side effects:
* Interpreter result may be updated.
*
*-------------------------------------------------------------------------
*/
static int
DescribeMounted(
Tcl_Interp *interp,
const char *mountPoint)
{
if (interp) {
ZipFile *zf = ZipFSLookupZip(mountPoint);
|
| ︙ | ︙ | |||
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 |
*
* Side effects:
* A ZIP archive file is read, analyzed and mounted, resources are
* allocated.
*
*-------------------------------------------------------------------------
*/
int
TclZipfs_Mount(
Tcl_Interp *interp, /* Current interpreter. NULLable. */
const char *zipname, /* Path to ZIP file to mount */
const char *mountPoint, /* Mount point path. */
const char *passwd) /* Password for opening the ZIP, or NULL if
* the ZIP is unprotected. */
| > | 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 |
*
* Side effects:
* A ZIP archive file is read, analyzed and mounted, resources are
* allocated.
*
*-------------------------------------------------------------------------
*/
int
TclZipfs_Mount(
Tcl_Interp *interp, /* Current interpreter. NULLable. */
const char *zipname, /* Path to ZIP file to mount */
const char *mountPoint, /* Mount point path. */
const char *passwd) /* Password for opening the ZIP, or NULL if
* the ZIP is unprotected. */
|
| ︙ | ︙ | |||
2480 2481 2482 2483 2484 2485 2486 |
if (zf == NULL) {
ret = TCL_ERROR;
} else {
ret = ZipFSOpenArchive(interp, normPath, 1, zf);
if (ret != TCL_OK) {
Tcl_Free(zf);
} else {
| | | | 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 |
if (zf == NULL) {
ret = TCL_ERROR;
} else {
ret = ZipFSOpenArchive(interp, normPath, 1, zf);
if (ret != TCL_OK) {
Tcl_Free(zf);
} else {
ret = ZipFSCatalogFilesystem(
interp, zf, mountPoint, passwd, normPath);
/* Note zf is already freed on error! */
}
}
}
Tcl_DecrRefCount(normZipPathObj);
if (ret == TCL_OK && interp) {
Tcl_DStringResult(interp, &ds);
|
| ︙ | ︙ | |||
2587 2588 2589 2590 2591 2592 2593 |
zf->ptrToFree = NULL;
}
ret = ZipFSFindTOC(interp, 1, zf);
if (ret != TCL_OK) {
Tcl_Free(zf);
} else {
/* Note ZipFSCatalogFilesystem will free zf on error */
| | | | 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 |
zf->ptrToFree = NULL;
}
ret = ZipFSFindTOC(interp, 1, zf);
if (ret != TCL_OK) {
Tcl_Free(zf);
} else {
/* Note ZipFSCatalogFilesystem will free zf on error */
ret = ZipFSCatalogFilesystem(
interp, zf, mountPoint, NULL, "Memory Buffer");
}
if (ret == TCL_OK && interp) {
Tcl_DStringResult(interp, &ds);
}
done:
Tcl_DStringFree(&ds);
|
| ︙ | ︙ | |||
2697 2698 2699 2700 2701 2702 2703 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMountObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMountObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *mountPoint = NULL, *zipFile = NULL, *password = NULL;
int result;
if (objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "?zipfile? ?mountpoint? ?password?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
2748 2749 2750 2751 2752 2753 2754 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMountBufferObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMountBufferObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *mountPoint = NULL; /* Mount point path. */
unsigned char *data = NULL;
Tcl_Size length;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data mountpoint");
|
| ︙ | ︙ | |||
2787 2788 2789 2790 2791 2792 2793 |
*-------------------------------------------------------------------------
*/
static int
ZipFSRootObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 |
*-------------------------------------------------------------------------
*/
static int
ZipFSRootObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc,
Tcl_Obj *const *objv)
{
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(ZIPFS_VOLUME, -1));
|
| ︙ | ︙ | |||
2818 2819 2820 2821 2822 2823 2824 |
*-------------------------------------------------------------------------
*/
static int
ZipFSUnmountObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 |
*-------------------------------------------------------------------------
*/
static int
ZipFSUnmountObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "mountpoint");
return TCL_ERROR;
}
return TclZipfs_Unmount(interp, TclGetString(objv[1]));
}
|
| ︙ | ︙ | |||
2849 2850 2851 2852 2853 2854 2855 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMkKeyObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMkKeyObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Size len, i = 0;
const char *pw;
Tcl_Obj *passObj;
unsigned char *passBuf;
if (objc != 2) {
|
| ︙ | ︙ | |||
3289 3290 3291 3292 3293 3294 3295 |
* Remember that we've written the file (for central directory generation)
* and generate the local (per-file) header in the space that we reserved
* earlier.
*/
z = AllocateZipEntry();
Tcl_SetHashValue(hPtr, z);
| | | 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 |
* Remember that we've written the file (for central directory generation)
* and generate the local (per-file) header in the space that we reserved
* earlier.
*/
z = AllocateZipEntry();
Tcl_SetHashValue(hPtr, z);
z->isEncrypted = (passwd ? 1 : 0);
z->offset = headerStartOffset;
z->crc32 = crc;
z->timestamp = mtime;
z->numBytes = nbyte;
z->numCompressedBytes = nbytecompr;
z->compressMethod = compMeth;
z->name = (char *) Tcl_GetHashKey(fileHash, hPtr);
|
| ︙ | ︙ | |||
3948 3949 3950 3951 3952 3953 3954 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMkZipObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMkZipObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *stripPrefix, *password;
if (objc < 3 || objc > 5) {
Tcl_WrongNumArgs(interp, 1, objv, "outfile indir ?strip? ?password?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
3973 3974 3975 3976 3977 3978 3979 |
stripPrefix, password);
}
static int
ZipFSLMkZipObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 |
stripPrefix, password);
}
static int
ZipFSLMkZipObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *password;
if (objc < 3 || objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv, "outfile inlist ?password?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
4014 4015 4016 4017 4018 4019 4020 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMkImgObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 |
*-------------------------------------------------------------------------
*/
static int
ZipFSMkImgObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *originFile, *stripPrefix, *password;
if (objc < 3 || objc > 6) {
Tcl_WrongNumArgs(interp, 1, objv,
"outfile indir ?strip? ?password? ?infile?");
return TCL_ERROR;
|
| ︙ | ︙ | |||
4041 4042 4043 4044 4045 4046 4047 |
originFile, stripPrefix, password);
}
static int
ZipFSLMkImgObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 |
originFile, stripPrefix, password);
}
static int
ZipFSLMkImgObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_Obj *originFile, *password;
if (objc < 3 || objc > 5) {
Tcl_WrongNumArgs(interp, 1, objv, "outfile inlist ?password? ?infile?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
4083 4084 4085 4086 4087 4088 4089 |
*-------------------------------------------------------------------------
*/
static int
ZipFSCanonicalObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 |
*-------------------------------------------------------------------------
*/
static int
ZipFSCanonicalObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *mntPoint = NULL;
Tcl_DString dsPath, dsMount;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "?mountpoint? filename");
return TCL_ERROR;
|
| ︙ | ︙ | |||
4133 4134 4135 4136 4137 4138 4139 |
*-------------------------------------------------------------------------
*/
static int
ZipFSExistsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 |
*-------------------------------------------------------------------------
*/
static int
ZipFSExistsObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
char *filename;
int exists;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "filename");
return TCL_ERROR;
|
| ︙ | ︙ | |||
4182 4183 4184 4185 4186 4187 4188 |
*-------------------------------------------------------------------------
*/
static int
ZipFSInfoObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 |
*-------------------------------------------------------------------------
*/
static int
ZipFSInfoObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
char *filename;
ZipEntry *z;
int ret;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "filename");
|
| ︙ | ︙ | |||
4219 4220 4221 4222 4223 4224 4225 |
filename));
}
ret = TCL_ERROR;
}
Unlock();
return ret;
}
| | | | | | 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 |
filename));
}
ret = TCL_ERROR;
}
Unlock();
return ret;
}
/*
*-------------------------------------------------------------------------
*
* ZipFSListObjCmd --
*
* This procedure is invoked to process the [zipfs list] command. On
* success, it returns a Tcl list of files of the ZIP filesystem which
* match a search pattern (glob or regexp).
*
* Results:
* A standard Tcl result.
*
* Side effects:
* None.
*
*-------------------------------------------------------------------------
*/
static int
ZipFSListObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
const char *pattern = NULL;
Tcl_RegExp regexp = NULL;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
Tcl_Obj *result = Tcl_GetObjResult(interp);
static const char *const options[] = {"-glob", "-regexp", NULL};
|
| ︙ | ︙ | |||
4332 4333 4334 4335 4336 4337 4338 | * * TclZipfsMountExe -- * * Checks if an archive is mounted on the ZIPFS_APP_MOUNT mount point. * If not, attempts to mount the zip archive attached to the application * executable on to ZIPFS_APP_MOUNT. * | | | 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 | * * TclZipfsMountExe -- * * Checks if an archive is mounted on the ZIPFS_APP_MOUNT mount point. * If not, attempts to mount the zip archive attached to the application * executable on to ZIPFS_APP_MOUNT. * * Caller should not be holding any locks when calling this function. * * Results: * 1 -> if an archive is present on ZIPFS_APP_MOUNT * 0 -> otherwise * * Side effects: * May mount the archive at the ZIPFS_APP_MOUNT mount point. |
| ︙ | ︙ | |||
4381 4382 4383 4384 4385 4386 4387 | * * TclZipfsMountShlib -- * * Checks if an archive is mounted on the ZIPFS_ZIP_MOUNT mount point. * If not, attempts to mount the zip archive attached to the application * executable on to ZIPFS_ZIP_MOUNT. * | | | 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 | * * TclZipfsMountShlib -- * * Checks if an archive is mounted on the ZIPFS_ZIP_MOUNT mount point. * If not, attempts to mount the zip archive attached to the application * executable on to ZIPFS_ZIP_MOUNT. * * Caller should not be holding any locks when calling this function. * * Results: * 1 -> if an archive is present on ZIPFS_ZIP_MOUNT * 0 -> otherwise * * Side effects: * May mount the archive at the ZIPFS_ZIP_MOUNT mount point. |
| ︙ | ︙ | |||
4410 4411 4412 4413 4414 4415 4416 |
int mounted = (ZipFSLookupZip(ZIPFS_ZIP_MOUNT) != NULL);
Unlock();
if (!mounted) {
Tcl_Obj *shlibPathObj = TclGetObjNameOfShlib();
if (shlibPathObj) {
mounted = (TclZipfs_Mount(NULL, Tcl_GetString(shlibPathObj),
| | | > | 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 |
int mounted = (ZipFSLookupZip(ZIPFS_ZIP_MOUNT) != NULL);
Unlock();
if (!mounted) {
Tcl_Obj *shlibPathObj = TclGetObjNameOfShlib();
if (shlibPathObj) {
mounted = (TclZipfs_Mount(NULL, Tcl_GetString(shlibPathObj),
ZIPFS_ZIP_MOUNT, NULL) == TCL_OK);
if (!mounted) {
/*
* Even if TclZipFS_Mount returns error, it could be some
* other thread mount it in the meanwhile leading to a mount
* busy error when this thread tries. Unlikely, but...
*/
ReadLock();
mounted = ZipFSLookupZip(ZIPFS_ZIP_MOUNT) != NULL;
Unlock();
}
}
}
return mounted;
#endif
}
/*
*-------------------------------------------------------------------------
*
* TclZipfsLocateTclLibrary --
*
* This procedure locates the root that Tcl's library files are mounted
* under if they are under a zipfs file system archive attached to the
|
| ︙ | ︙ | |||
4452 4453 4454 4455 4456 4457 4458 | * never be cleared. The encoding directory paths are modified. * *------------------------------------------------------------------------- */ static void TclZipfsLocateTclLibrary( | | | | 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 |
* never be cleared. The encoding directory paths are modified.
*
*-------------------------------------------------------------------------
*/
static void
TclZipfsLocateTclLibrary(
int appZipfsPresent, /* non-0 if app zipfs is to be checked */
int shlibZipfsPresent) /* non-0 if shared lib is to be checked */
{
Tcl_Obj *vfsInitScript;
int found;
if (zipfs_tcl_library_init) {
return;
}
|
| ︙ | ︙ | |||
4504 4505 4506 4507 4508 4509 4510 |
Tcl_MutexUnlock(&ZipFSLocateLibMutex);
if (zipfs_literal_tcl_library) {
/* Found it, set up encoding dirs */
(void)TclZipfsInitEncodingDirs();
}
return;
}
| | | 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 |
Tcl_MutexUnlock(&ZipFSLocateLibMutex);
if (zipfs_literal_tcl_library) {
/* Found it, set up encoding dirs */
(void)TclZipfsInitEncodingDirs();
}
return;
}
/*
*-------------------------------------------------------------------------
*
* TclZipfs_TclLibrary --
*
* This procedure gets the root that Tcl's library
* files are mounted under if they are under a zipfs file system.
|
| ︙ | ︙ | |||
4562 4563 4564 4565 4566 4567 4568 |
*-------------------------------------------------------------------------
*/
static int
ZipFSTclLibraryObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 |
*-------------------------------------------------------------------------
*/
static int
ZipFSTclLibraryObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *)) /*objv*/
{
if (!Tcl_IsSafe(interp)) {
Tcl_Obj *pResult = TclZipfs_TclLibrary();
if (!pResult) {
TclNewObj(pResult);
|
| ︙ | ︙ | |||
5048 5049 5050 5051 5052 5053 5054 |
/* Read-only */
flags |= TCL_READABLE;
}
if (z->isEncrypted) {
if (z->numCompressedBytes < ZIP_CRYPT_HDR_LEN) {
ZIPFS_ERROR(interp,
| | | 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 |
/* Read-only */
flags |= TCL_READABLE;
}
if (z->isEncrypted) {
if (z->numCompressedBytes < ZIP_CRYPT_HDR_LEN) {
ZIPFS_ERROR(interp,
"decryption failed: truncated decryption header");
ZIPFS_ERROR_CODE(interp, "DECRYPT");
goto error;
}
if (z->zipFilePtr->passBuf[0] == 0) {
ZIPFS_ERROR(interp, "decryption failed - no password provided");
ZIPFS_ERROR_CODE(interp, "DECRYPT");
goto error;
|
| ︙ | ︙ | |||
5512 5513 5514 5515 5516 5517 5518 |
buf->st_mtime = z->timestamp;
buf->st_ctime = z->timestamp;
buf->st_atime = z->timestamp;
ret = 0;
} else if (ContainsMountPoint(path, -1)) {
/* An intermediate dir under which a mount exists */
memset(buf, 0, sizeof(Tcl_StatBuf));
| > > | | 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 |
buf->st_mtime = z->timestamp;
buf->st_ctime = z->timestamp;
buf->st_atime = z->timestamp;
ret = 0;
} else if (ContainsMountPoint(path, -1)) {
/* An intermediate dir under which a mount exists */
memset(buf, 0, sizeof(Tcl_StatBuf));
Tcl_Time t;
Tcl_GetTime(&t);
buf->st_atime = buf->st_mtime = buf->st_ctime = t.sec;
buf->st_mode = S_IFDIR | 0555;
ret = 0;
} else {
Tcl_SetErrno(ENOENT);
ret = -1;
}
Unlock();
|
| ︙ | ︙ | |||
5569 5570 5571 5572 5573 5574 5575 |
*/
access = ContainsMountPoint(path, -1) ? 0 : -1;
}
}
Unlock();
return access;
}
| | | 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 |
*/
access = ContainsMountPoint(path, -1) ? 0 : -1;
}
}
Unlock();
return access;
}
/*
*-------------------------------------------------------------------------
*
* ZipFSOpenFileChannelProc --
*
* Open a channel to a file in a mounted ZIP archive. Delegates to
* ZipChannelOpen().
|
| ︙ | ︙ | |||
5601 5602 5603 5604 5605 5606 5607 |
pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
if (!pathPtr) {
return NULL;
}
return ZipChannelOpen(interp, Tcl_GetString(pathPtr), mode);
}
| | | 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 |
pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
if (!pathPtr) {
return NULL;
}
return ZipChannelOpen(interp, Tcl_GetString(pathPtr), mode);
}
/*
*-------------------------------------------------------------------------
*
* ZipFSStatProc --
*
* This function implements the ZIP filesystem specific version of the
* library version of stat.
|
| ︙ | ︙ | |||
5772 5773 5774 5775 5776 5777 5778 |
return TCL_ERROR;
}
if ((wanted & (TCL_GLOB_TYPE_DIR | TCL_GLOB_TYPE_FILE |
TCL_GLOB_TYPE_MOUNT)) == 0) {
/* Not looking for files,dirs,mounts. zipfs cannot have others */
return TCL_OK;
}
| > | | 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 |
return TCL_ERROR;
}
if ((wanted & (TCL_GLOB_TYPE_DIR | TCL_GLOB_TYPE_FILE |
TCL_GLOB_TYPE_MOUNT)) == 0) {
/* Not looking for files,dirs,mounts. zipfs cannot have others */
return TCL_OK;
}
wanted &=
(TCL_GLOB_TYPE_DIR | TCL_GLOB_TYPE_FILE | TCL_GLOB_TYPE_MOUNT);
} else {
wanted = TCL_GLOB_TYPE_DIR | TCL_GLOB_TYPE_FILE;
}
/*
* The prefix that gets prepended to results.
*/
|
| ︙ | ︙ | |||
5914 5915 5916 5917 5918 5919 5920 |
if (*tail == '\0') {
continue;
}
const char *end = strchr(tail, '/');
Tcl_DStringAppend(&ds, zf->mountPoint + strip,
end ? (Tcl_Size)(end - tail + len - strip) : -1);
const char *matchedPath = Tcl_DStringValue(&ds);
| | | | | | 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 |
if (*tail == '\0') {
continue;
}
const char *end = strchr(tail, '/');
Tcl_DStringAppend(&ds, zf->mountPoint + strip,
end ? (Tcl_Size)(end - tail + len - strip) : -1);
const char *matchedPath = Tcl_DStringValue(&ds);
(void)Tcl_CreateHashEntry(
&duplicates, matchedPath, ¬Duplicate);
if (notDuplicate) {
AppendWithPrefix(
result, prefixBuf, matchedPath, Tcl_DStringLength(&ds));
}
Tcl_DStringFree(&ds);
}
}
}
Tcl_DeleteHashTable(&duplicates);
Tcl_Free(pat);
|
| ︙ | ︙ | |||
6391 6392 6393 6394 6395 6396 6397 |
}
}
if (!objs[0]) {
objs[0] = TclPathPart(interp, TclGetObjNameOfExecutable(),
TCL_PATH_DIRNAME);
}
if (objs[0]) {
| | | 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 |
}
}
if (!objs[0]) {
objs[0] = TclPathPart(interp, TclGetObjNameOfExecutable(),
TCL_PATH_DIRNAME);
}
if (objs[0]) {
altPath = TclJoinPath(2, objs, 0);
if (altPath) {
Tcl_IncrRefCount(altPath);
if (Tcl_FSAccess(altPath, R_OK) == 0) {
path = altPath;
}
}
}
|
| ︙ | ︙ | |||
6423 6424 6425 6426 6427 6428 6429 |
Tcl_DecrRefCount(altPath);
}
return ret;
#endif /* ANDROID */
}
/*
| | | | < > | | > | | > > > > > > > > > > > > > > > > | 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 |
Tcl_DecrRefCount(altPath);
}
return ret;
#endif /* ANDROID */
}
/*
*-------------------------------------------------------------------------
*
* TclZipfs_Init --
*
* Perform per interpreter initialization of this module.
*
* Results:
* The return value is a standard Tcl result.
*
* Side effects:
* Initializes this module if not already initialized, and adds module
* related commands to the given interpreter.
*
*-------------------------------------------------------------------------
*/
int
TclZipfs_Init(
Tcl_Interp *interp) /* Current interpreter. */
{
static const EnsembleImplMap initMap[] = {
{"mkimg", ZipFSMkImgObjCmd, NULL, NULL, NULL, 1},
{"mkzip", ZipFSMkZipObjCmd, NULL, NULL, NULL, 1},
{"lmkimg", ZipFSLMkImgObjCmd, NULL, NULL, NULL, 1},
{"lmkzip", ZipFSLMkZipObjCmd, NULL, NULL, NULL, 1},
{"mount", ZipFSMountObjCmd, NULL, NULL, NULL, 1},
{"mountdata", ZipFSMountBufferObjCmd, NULL, NULL, NULL, 1},
{"unmount", ZipFSUnmountObjCmd, NULL, NULL, NULL, 1},
{"mkkey", ZipFSMkKeyObjCmd, NULL, NULL, NULL, 1},
{"exists", ZipFSExistsObjCmd, NULL, NULL, NULL, 1},
{"info", ZipFSInfoObjCmd, NULL, NULL, NULL, 1},
{"list", ZipFSListObjCmd, NULL, NULL, NULL, 1},
{"canonical", ZipFSCanonicalObjCmd, NULL, NULL, NULL, 1},
{"root", ZipFSRootObjCmd, NULL, NULL, NULL, 1},
{NULL, NULL, NULL, NULL, NULL, 0}
};
static const char findproc[] =
"namespace eval ::tcl::zipfs {}\n"
"proc ::tcl::zipfs::Find dir {\n"
" set result {}\n"
" try {\n"
" set normal [glob -directory $dir -nocomplain *]\n"
" set hidden [glob -directory $dir -types hidden -nocomplain *]\n"
|
| ︙ | ︙ | |||
6464 6465 6466 6467 6468 6469 6470 |
" }\n"
" return $result\n"
"}\n"
"proc ::tcl::zipfs::find {directoryName} {\n"
" return [lsort [Find $directoryName]]\n"
"}\n";
| < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < < | < < | > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 |
" }\n"
" return $result\n"
"}\n"
"proc ::tcl::zipfs::find {directoryName} {\n"
" return [lsort [Find $directoryName]]\n"
"}\n";
/*
* One-time initialization.
*/
WriteLock();
if (!ZipFS.initialized) {
ZipfsSetup();
}
Unlock();
if (interp) {
Tcl_Command ensemble;
Tcl_Obj *mapObj;
Tcl_EvalEx(interp, findproc, TCL_INDEX_NONE, TCL_EVAL_GLOBAL);
if (!Tcl_IsSafe(interp)) {
Tcl_LinkVar(interp, "::tcl::zipfs::wrmax", (char *) &ZipFS.wrmax,
TCL_LINK_INT);
Tcl_LinkVar(interp, "::tcl::zipfs::fallbackEntryEncoding",
(char *) &ZipFS.fallbackEntryEncoding, TCL_LINK_STRING);
}
ensemble = TclMakeEnsemble(interp, "zipfs",
Tcl_IsSafe(interp) ? (initMap + 4) : initMap);
/*
* Add the [zipfs find] subcommand.
*/
Tcl_GetEnsembleMappingDict(NULL, ensemble, &mapObj);
TclDictPutString(NULL, mapObj, "find", "::tcl::zipfs::find");
Tcl_CreateObjCommand(interp, "::tcl::zipfs::tcl_library_init",
ZipFSTclLibraryObjCmd, NULL, NULL);
}
return TCL_OK;
}
/*
*------------------------------------------------------------------------
*
* TclZipfsFinalize --
*
* Frees all zipfs resources IRRESPECTIVE of open channels (there should
* not be any!) etc. To be called at process exit time (from
* Tcl_Finalize->TclFinalizeFilesystem)
*
* Results:
* None.
*
* Side effects:
* Frees up archives loaded into memory.
*
*------------------------------------------------------------------------
*/
void
TclZipfsFinalize(void)
{
WriteLock();
|
| ︙ | ︙ | |||
6557 6558 6559 6560 6561 6562 6563 |
}
ZipFS.initialized = 0;
Unlock();
}
/*
| < < < < | 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 |
}
ZipFS.initialized = 0;
Unlock();
}
/*
* TclZipfsInitEncodingDirs --
*
* Appends the encoding directory under the tcl_library directory
* within a ZipFS mount to the encoding directory search path.
*/
static int
TclZipfsInitEncodingDirs(void)
{
if (zipfs_literal_tcl_library == NULL) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
6596 6597 6598 6599 6600 6601 6602 |
Tcl_DecrRefCount(libDirObj);
Tcl_SetEncodingSearchPath(searchPathObj);
Tcl_DecrRefCount(searchPathObj);
/* Reinit system encoding after setting search path */
TclpSetInitialEncodings();
return TCL_OK;
}
| | > < < < < > | 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 |
Tcl_DecrRefCount(libDirObj);
Tcl_SetEncodingSearchPath(searchPathObj);
Tcl_DecrRefCount(searchPathObj);
/* Reinit system encoding after setting search path */
TclpSetInitialEncodings();
return TCL_OK;
}
/*
*-------------------------------------------------------------------------
*
* TclZipfs_AppHook --
*
* Performs the argument munging for the shell
*
*-------------------------------------------------------------------------
*/
const char *
TclZipfs_AppHook(
#ifdef SUPPORT_BUILTIN_ZIP_INSTALL
int *argcPtr, /* Pointer to argc */
#else
TCL_UNUSED(int *), /*argcPtr*/
#endif
#ifdef _WIN32
TCL_UNUSED(unsigned short ***)) /* argvPtr */
#else /* !_WIN32 */
char ***argvPtr) /* Pointer to argv */
#endif /* _WIN32 */
{
const char *result;
#ifdef _WIN32
result = Tcl_FindExecutable(NULL);
#else
result = Tcl_FindExecutable((*argvPtr)[0]);
#endif
TclZipfs_Init(NULL);
/* Always mount archives attached to the application and shared library */
int appZipfsPresent = TclZipfsMountExe();
int shlibZipfsPresent = TclZipfsMountShlib();
/*
* After BOTH are mounted, look for init.tcl in one of the mounts.
|
| ︙ | ︙ |
Changes to generic/tclZlib.c.
| ︙ | ︙ | |||
169 170 171 172 173 174 175 | static Tcl_DriverGetHandleProc ZlibTransformGetHandle; static Tcl_DriverGetOptionProc ZlibTransformGetOption; static Tcl_DriverHandlerProc ZlibTransformEventHandler; static Tcl_DriverInputProc ZlibTransformInput; static Tcl_DriverOutputProc ZlibTransformOutput; static Tcl_DriverSetOptionProc ZlibTransformSetOption; static Tcl_DriverWatchProc ZlibTransformWatch; | | | | | | | | | | | | | | | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | static Tcl_DriverGetHandleProc ZlibTransformGetHandle; static Tcl_DriverGetOptionProc ZlibTransformGetOption; static Tcl_DriverHandlerProc ZlibTransformEventHandler; static Tcl_DriverInputProc ZlibTransformInput; static Tcl_DriverOutputProc ZlibTransformOutput; static Tcl_DriverSetOptionProc ZlibTransformSetOption; static Tcl_DriverWatchProc ZlibTransformWatch; static Tcl_ObjCmdProc ZlibAdler32Cmd; static Tcl_ObjCmdProc ZlibCompressCmd; static Tcl_ObjCmdProc ZlibCRC32Cmd; static Tcl_ObjCmdProc ZlibDecompressCmd; static Tcl_ObjCmdProc ZlibDeflateCmd; static Tcl_ObjCmdProc ZlibGunzipCmd; static Tcl_ObjCmdProc ZlibGzipCmd; static Tcl_ObjCmdProc ZlibInflateCmd; static Tcl_ObjCmdProc ZlibPushCmd; static Tcl_ObjCmdProc ZlibStreamCmd; static Tcl_ObjCmdProc ZlibStreamImplCmd; static Tcl_ObjCmdProc ZlibStreamAddCmd; static Tcl_ObjCmdProc ZlibStreamHeaderCmd; static Tcl_ObjCmdProc ZlibStreamPutCmd; static void ConvertError(Tcl_Interp *interp, int code, uLong adler); static Tcl_Obj * ConvertErrorToList(int code, uLong adler); static inline int Deflate(z_streamp strm, void *bufferPtr, size_t bufferSize, int flush, size_t *writtenPtr); static void ExtractHeader(gz_header *headerPtr, Tcl_Obj *dictObj); |
| ︙ | ︙ | |||
228 229 230 231 232 233 234 |
NULL, /* Flush proc. */
ZlibTransformEventHandler,
NULL, /* Seek proc. */
NULL, /* Thread action proc. */
NULL /* Truncate proc. */
};
| | < | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
NULL, /* Flush proc. */
ZlibTransformEventHandler,
NULL, /* Seek proc. */
NULL, /* Thread action proc. */
NULL /* Truncate proc. */
};
static const EnsembleImplMap zlibImplMap[] = {
{"adler32", ZlibAdler32Cmd, NULL, NULL, NULL, 0},
{"compress", ZlibCompressCmd, NULL, NULL, NULL, 0},
{"crc32", ZlibCRC32Cmd, NULL, NULL, NULL, 0},
{"decompress", ZlibDecompressCmd, NULL, NULL, NULL, 0},
{"deflate", ZlibDeflateCmd, NULL, NULL, NULL, 0},
{"gunzip", ZlibGunzipCmd, NULL, NULL, NULL, 0},
{"gzip", ZlibGzipCmd, NULL, NULL, NULL, 0},
{"inflate", ZlibInflateCmd, NULL, NULL, NULL, 0},
{"push", ZlibPushCmd, NULL, NULL, NULL, 0},
{"stream", ZlibStreamCmd, NULL, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
};
/*
*----------------------------------------------------------------------
*
* Latin1 --
* Helper to definitely get the ISO 8859-1 encoding. It's internally
* defined by Tcl so this operation should always succeed.
*
*----------------------------------------------------------------------
*/
static inline Tcl_Encoding
Latin1(void)
|
| ︙ | ︙ | |||
859 860 861 862 863 864 865 | } Tcl_ResetResult(interp); /* * Create the command. */ | | | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 |
}
Tcl_ResetResult(interp);
/*
* Create the command.
*/
zshPtr->cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&cmdname),
ZlibStreamImplCmd, zshPtr, ZlibStreamCmdDelete);
Tcl_DStringFree(&cmdname);
if (zshPtr->cmd == NULL) {
goto error;
}
} else {
zshPtr->cmd = NULL;
|
| ︙ | ︙ | |||
1457 1458 1459 1460 1461 1462 1463 |
e = inflate(&zshPtr->stream, zshPtr->flush);
if (e == Z_NEED_DICT && HaveDictToSet(zshPtr)) {
e = SetInflateDictionary(&zshPtr->stream, zshPtr->compDictObj);
if (e == Z_OK) {
DictWasSet(zshPtr);
e = inflate(&zshPtr->stream, zshPtr->flush);
}
| | | 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 |
e = inflate(&zshPtr->stream, zshPtr->flush);
if (e == Z_NEED_DICT && HaveDictToSet(zshPtr)) {
e = SetInflateDictionary(&zshPtr->stream, zshPtr->compDictObj);
if (e == Z_OK) {
DictWasSet(zshPtr);
e = inflate(&zshPtr->stream, zshPtr->flush);
}
};
TclListObjLength(NULL, zshPtr->inData, &listLen);
while ((zshPtr->stream.avail_out > 0)
&& (e == Z_OK || e == Z_BUF_ERROR) && (listLen > 0)) {
/*
* State: We have not satisfied the request yet and there may be
* more to inflate.
|
| ︙ | ︙ | |||
2063 2064 2065 2066 2067 2068 2069 |
*
*----------------------------------------------------------------------
*/
static int
ZlibAdler32Cmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 |
*
*----------------------------------------------------------------------
*/
static int
ZlibAdler32Cmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Size dlen = 0;
const unsigned char *data;
unsigned int start;
if (objc < 1 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data ?startValue?");
|
| ︙ | ︙ | |||
2101 2102 2103 2104 2105 2106 2107 |
*
*----------------------------------------------------------------------
*/
static int
ZlibCRC32Cmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 |
*
*----------------------------------------------------------------------
*/
static int
ZlibCRC32Cmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_Size dlen = 0;
const unsigned char *data;
unsigned int start;
if (objc < 1 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data ?startValue?");
|
| ︙ | ︙ | |||
2139 2140 2141 2142 2143 2144 2145 |
*
*----------------------------------------------------------------------
*/
static int
ZlibDeflateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 |
*
*----------------------------------------------------------------------
*/
static int
ZlibDeflateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int level;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data ?level?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2167 2168 2169 2170 2171 2172 2173 |
*
*----------------------------------------------------------------------
*/
static int
ZlibCompressCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 |
*
*----------------------------------------------------------------------
*/
static int
ZlibCompressCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int level;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data ?level?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
2195 2196 2197 2198 2199 2200 2201 |
*
*----------------------------------------------------------------------
*/
static int
ZlibGzipCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 |
*
*----------------------------------------------------------------------
*/
static int
ZlibGzipCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const gzipopts[] = {
"-header", "-level", NULL
};
Tcl_Obj *headerDictObj = NULL;
int level = Z_DEFAULT_COMPRESSION, i, option;
|
| ︙ | ︙ | |||
2258 2259 2260 2261 2262 2263 2264 |
*
*----------------------------------------------------------------------
*/
static int
ZlibInflateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 |
*
*----------------------------------------------------------------------
*/
static int
ZlibInflateCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
size_t buffersize = 0;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data ?bufferSize?");
return TCL_ERROR;
}
if (objc > 2 && GetBufferSizeFromObj(interp, objv[2], &buffersize) != TCL_OK) {
|
| ︙ | ︙ | |||
2285 2286 2287 2288 2289 2290 2291 |
*
*----------------------------------------------------------------------
*/
static int
ZlibDecompressCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 |
*
*----------------------------------------------------------------------
*/
static int
ZlibDecompressCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
size_t buffersize = 0;
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "data ?bufferSize?");
return TCL_ERROR;
}
if (objc > 2 && GetBufferSizeFromObj(interp, objv[2], &buffersize) != TCL_OK) {
|
| ︙ | ︙ | |||
2312 2313 2314 2315 2316 2317 2318 |
*
*----------------------------------------------------------------------
*/
static int
ZlibGunzipCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 |
*
*----------------------------------------------------------------------
*/
static int
ZlibGunzipCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const gunzipopts[] = {
"-buffersize", "-headerVar", NULL
};
Tcl_Obj *headerVarObj = NULL, *headerDictObj = NULL;
size_t buffersize = 0;
int i, option;
|
| ︙ | ︙ | |||
2375 2376 2377 2378 2379 2380 2381 |
*
*----------------------------------------------------------------------
*/
static int
ZlibStreamCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 |
*
*----------------------------------------------------------------------
*/
static int
ZlibStreamCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const stream_formats[] = {
"compress", "decompress", "deflate", "gunzip", "gzip", "inflate",
NULL
};
enum zlibFormats {
FMT_COMPRESS, FMT_DECOMPRESS, FMT_DEFLATE, FMT_GUNZIP, FMT_GZIP,
|
| ︙ | ︙ | |||
2529 2530 2531 2532 2533 2534 2535 |
*
*----------------------------------------------------------------------
*/
static int
ZlibPushCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
| | | | 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 |
*
*----------------------------------------------------------------------
*/
static int
ZlibPushCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
static const char *const stream_formats[] = {
"compress", "decompress", "deflate", "gunzip", "gzip", "inflate",
NULL
};
enum zlibFormats {
FMT_COMPRESS, FMT_DECOMPRESS, FMT_DEFLATE, FMT_GUNZIP, FMT_GZIP,
|
| ︙ | ︙ | |||
2705 2706 2707 2708 2709 2710 2711 |
*
*----------------------------------------------------------------------
*/
static int
ZlibStreamImplCmd(
void *clientData,
Tcl_Interp *interp,
| | | | 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 |
*
*----------------------------------------------------------------------
*/
static int
ZlibStreamImplCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_ZlibStream zstream = (Tcl_ZlibStream) clientData;
int count, code;
Tcl_Obj *obj;
static const char *const cmds[] = {
"add", "checksum", "close", "eof", "finalize", "flush",
"fullflush", "get", "header", "put", "reset",
|
| ︙ | ︙ | |||
2831 2832 2833 2834 2835 2836 2837 |
}
}
static int
ZlibStreamAddCmd(
void *clientData,
Tcl_Interp *interp,
| | | | 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 |
}
}
static int
ZlibStreamAddCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_ZlibStream zstream = (Tcl_ZlibStream) clientData;
int code, buffersize = -1, flush = -1, i;
Tcl_Obj *obj, *compDictObj = NULL;
static const char *const add_options[] = {
"-buffer", "-dictionary", "-finalize", "-flush", "-fullflush", NULL
};
|
| ︙ | ︙ | |||
2960 2961 2962 2963 2964 2965 2966 |
return code;
}
static int
ZlibStreamPutCmd(
void *clientData,
Tcl_Interp *interp,
| | | | 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 |
return code;
}
static int
ZlibStreamPutCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
Tcl_ZlibStream zstream = (Tcl_ZlibStream) clientData;
int flush = -1, i;
Tcl_Obj *compDictObj = NULL;
static const char *const put_options[] = {
"-dictionary", "-finalize", "-flush", "-fullflush", NULL
};
|
| ︙ | ︙ | |||
3053 3054 3055 3056 3057 3058 3059 |
return Tcl_ZlibStreamPut(zstream, objv[objc - 1], flush);
}
static int
ZlibStreamHeaderCmd(
void *clientData,
Tcl_Interp *interp,
| | | | 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 |
return Tcl_ZlibStreamPut(zstream, objv[objc - 1], flush);
}
static int
ZlibStreamHeaderCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
ZlibStreamHandle *zshPtr = (ZlibStreamHandle *) clientData;
Tcl_Obj *resultObj;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 2, objv, NULL);
return TCL_ERROR;
|
| ︙ | ︙ | |||
3090 3091 3092 3093 3094 3095 3096 |
static inline int
HaveFlag(
ZlibChannelData *chanDataPtr,
int flag)
{
return (chanDataPtr->flags & flag) != 0;
}
| | < > | 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 |
static inline int
HaveFlag(
ZlibChannelData *chanDataPtr,
int flag)
{
return (chanDataPtr->flags & flag) != 0;
}
/*
*
* ZlibTransformClose --
*
* How to shut down a stacked compressing/decompressing transform.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformClose(
void *instanceData,
Tcl_Interp *interp,
int flags)
{
ZlibChannelData *chanDataPtr = (ZlibChannelData *) instanceData;
|
| ︙ | ︙ | |||
3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 |
*
* ZlibTransformInput --
*
* Reader filter that does decompression.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformInput(
void *instanceData,
char *buf,
int toRead,
int *errorCodePtr)
{
| > | 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 |
*
* ZlibTransformInput --
*
* Reader filter that does decompression.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformInput(
void *instanceData,
char *buf,
int toRead,
int *errorCodePtr)
{
|
| ︙ | ︙ | |||
3288 3289 3290 3291 3292 3293 3294 | *errorCodePtr = Tcl_GetErrno(); return -1; } /* more bytes (or Eof if readBytes == 0) */ chanDataPtr->inStream.avail_in += readBytes; | | | 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 | *errorCodePtr = Tcl_GetErrno(); return -1; } /* more bytes (or Eof if readBytes == 0) */ chanDataPtr->inStream.avail_in += readBytes; copyDecompressed: /* * Transform the read chunk, if not empty. Anything we get * back is a transformation result to be put into our buffers, and * the next iteration will put it into the result. * For the case readBytes is 0 which signaling Eof in parent, the * partial data waiting is converted and returned. |
| ︙ | ︙ | |||
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 |
*
* ZlibTransformOutput --
*
* Writer filter that does compression.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformOutput(
void *instanceData,
const char *buf,
int toWrite,
int *errorCodePtr)
{
| > | 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 |
*
* ZlibTransformOutput --
*
* Writer filter that does compression.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformOutput(
void *instanceData,
const char *buf,
int toWrite,
int *errorCodePtr)
{
|
| ︙ | ︙ | |||
3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 |
*
* ZlibTransformFlush --
*
* How to perform a flush of a compressing transform.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformFlush(
Tcl_Interp *interp,
ZlibChannelData *chanDataPtr,
int flushType)
{
int e;
| > | 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 |
*
* ZlibTransformFlush --
*
* How to perform a flush of a compressing transform.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformFlush(
Tcl_Interp *interp,
ZlibChannelData *chanDataPtr,
int flushType)
{
int e;
|
| ︙ | ︙ | |||
3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 |
*
* ZlibTransformSetOption --
*
* Writing side of [fconfigure] on our channel.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformSetOption( /* not used */
void *instanceData,
Tcl_Interp *interp,
const char *optionName,
const char *value)
{
| > | 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 |
*
* ZlibTransformSetOption --
*
* Writing side of [fconfigure] on our channel.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformSetOption( /* not used */
void *instanceData,
Tcl_Interp *interp,
const char *optionName,
const char *value)
{
|
| ︙ | ︙ | |||
3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 |
*
* ZlibTransformGetOption --
*
* Reading side of [fconfigure] on our channel.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformGetOption(
void *instanceData,
Tcl_Interp *interp,
const char *optionName,
Tcl_DString *dsPtr)
{
| > | 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 |
*
* ZlibTransformGetOption --
*
* Reading side of [fconfigure] on our channel.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformGetOption(
void *instanceData,
Tcl_Interp *interp,
const char *optionName,
Tcl_DString *dsPtr)
{
|
| ︙ | ︙ | |||
3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 |
* ZlibTransformGetHandle --
*
* Anything that needs the OS handle is told to get it from what we are
* stacked on top of.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformGetHandle(
void *instanceData,
int direction,
void **handlePtr)
{
ZlibChannelData *chanDataPtr = (ZlibChannelData *) instanceData;
return Tcl_GetChannelHandle(chanDataPtr->parent, direction, handlePtr);
}
/*
*----------------------------------------------------------------------
*
* ZlibTransformBlockMode --
*
* We need to keep track of the blocking mode; it changes our behavior.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformBlockMode(
void *instanceData,
int mode)
{
ZlibChannelData *chanDataPtr = (ZlibChannelData *) instanceData;
| > > | 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 |
* ZlibTransformGetHandle --
*
* Anything that needs the OS handle is told to get it from what we are
* stacked on top of.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformGetHandle(
void *instanceData,
int direction,
void **handlePtr)
{
ZlibChannelData *chanDataPtr = (ZlibChannelData *) instanceData;
return Tcl_GetChannelHandle(chanDataPtr->parent, direction, handlePtr);
}
/*
*----------------------------------------------------------------------
*
* ZlibTransformBlockMode --
*
* We need to keep track of the blocking mode; it changes our behavior.
*
*----------------------------------------------------------------------
*/
static int
ZlibTransformBlockMode(
void *instanceData,
int mode)
{
ZlibChannelData *chanDataPtr = (ZlibChannelData *) instanceData;
|
| ︙ | ︙ | |||
3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 |
* Stacks either compression or decompression onto a channel.
*
* Results:
* The stacked channel, or NULL if there was an error.
*
*----------------------------------------------------------------------
*/
static Tcl_Channel
ZlibStackChannelTransform(
Tcl_Interp *interp, /* Where to write error messages. */
int mode, /* Whether this is a compressing transform
* (TCL_ZLIB_STREAM_DEFLATE) or a
* decompressing transform
* (TCL_ZLIB_STREAM_INFLATE). Note that
| > | 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 |
* Stacks either compression or decompression onto a channel.
*
* Results:
* The stacked channel, or NULL if there was an error.
*
*----------------------------------------------------------------------
*/
static Tcl_Channel
ZlibStackChannelTransform(
Tcl_Interp *interp, /* Where to write error messages. */
int mode, /* Whether this is a compressing transform
* (TCL_ZLIB_STREAM_DEFLATE) or a
* decompressing transform
* (TCL_ZLIB_STREAM_INFLATE). Note that
|
| ︙ | ︙ | |||
3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 |
*
* Side effects:
* After execution it updates chanDataPtr->inStream (next_in, avail_in) to
* reflect the data that has been decompressed.
*
*----------------------------------------------------------------------
*/
static int
ResultDecompress(
ZlibChannelData *chanDataPtr,
char *buf,
int toRead,
int flush,
int *errorCodePtr)
| > | 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 |
*
* Side effects:
* After execution it updates chanDataPtr->inStream (next_in, avail_in) to
* reflect the data that has been decompressed.
*
*----------------------------------------------------------------------
*/
static int
ResultDecompress(
ZlibChannelData *chanDataPtr,
char *buf,
int toRead,
int flush,
int *errorCodePtr)
|
| ︙ | ︙ | |||
4099 4100 4101 4102 4103 4104 4105 |
Tcl_SetChannelError(chanDataPtr->parent, errObj);
*errorCodePtr = EINVAL;
return -1;
}
/*
*----------------------------------------------------------------------
| < | < < > > > > > > | 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 |
Tcl_SetChannelError(chanDataPtr->parent, errObj);
*errorCodePtr = EINVAL;
return -1;
}
/*
*----------------------------------------------------------------------
* Finally, the TclZlibInit function. Used to install the zlib API.
*----------------------------------------------------------------------
*/
int
TclZlibInit(
Tcl_Interp *interp)
{
Tcl_Config cfg[2];
/*
* This does two things. It creates a counter used in the creation of
* stream commands, and it creates the namespace that will contain those
* commands.
*/
Tcl_EvalEx(interp, "namespace eval ::tcl::zlib {variable cmdcounter 0}",
TCL_AUTO_LENGTH, 0);
/*
* Create the public scripted interface to this file's functionality.
*/
TclMakeEnsemble(interp, "zlib", zlibImplMap);
/*
* Store the underlying configuration information.
*
* TODO: Describe whether we're using the system version of the library or
* a compatibility version built into Tcl?
*/
|
| ︙ | ︙ |
Changes to library/auto.tcl.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
# the information gets recomputed the next time it's needed. Also delete any
# commands that are listed in the auto-load index.
#
# Arguments:
# None.
proc auto_reset {} {
| | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# the information gets recomputed the next time it's needed. Also delete any
# commands that are listed in the auto-load index.
#
# Arguments:
# None.
proc auto_reset {} {
global auto_execs auto_index auto_path
if {[array exists auto_index]} {
foreach cmdName [array names auto_index] {
set fqcn [namespace which $cmdName]
if {$fqcn eq ""} {
continue
}
rename $fqcn {}
}
}
unset -nocomplain auto_execs auto_index ::tcl::auto_oldpath
if {[catch {llength $auto_path}]} {
set auto_path [list [info library]]
} elseif {[info library] ni $auto_path} {
lappend auto_path [info library]
}
}
|
| ︙ | ︙ |
Deleted library/autoexecok.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to library/clock.tcl.
| ︙ | ︙ | |||
664 665 666 667 668 669 670 671 672 |
# Select the locale, eventually load it
mcpackagelocale set $locale
return $locale
}
#----------------------------------------------------------------------
#
# _hasRegistry --
#
| > | > < > > > > > > > > > > > > > > > > > > > > | | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
# Select the locale, eventually load it
mcpackagelocale set $locale
return $locale
}
#----------------------------------------------------------------------
#
# _registryExists --
# _hasRegistry --
#
# Helpers that checks whether registry module is available (Windows only)
# and loads it on demand.
#
# Side effects:
# _hasRegistry does it only once, and hereafter simply returns 1 or 0.
#
#----------------------------------------------------------------------
proc ::tcl::clock::_registryExists {} {
if { $::tcl_platform(platform) eq {windows} } {
if { [catch { package require registry 1.3 }] } {
# try to load registry directly from root (if uninstalled / development env):
if {[regexp {[/\\]library$} [info library]]} {catch {
load [lindex \
[glob -tails -directory [file dirname [info nameofexecutable]] \
tcl9registry*[expr {[::tcl::pkgconfig get debug] ? {g} : {}}].dll] 0 \
] Registry
}}
}
if { [namespace which -command ::registry] ne "" } {
return 1
}
}
return 0
}
proc ::tcl::clock::_hasRegistry {} {
set res [_registryExists]
proc ::tcl::clock::_hasRegistry {} [list return $res]
return $res
}
#----------------------------------------------------------------------
#
# LoadWindowsDateTimeFormats --
#
# Load the date/time formats from the Control Panel in Windows and
|
| ︙ | ︙ |
Changes to library/cookiejar/idna.tcl.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 |
set part [punydecode [string range $part 4 end]]
}
lappend parts $part
}
return [join $parts .]
}
| | | | | | | | | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
set part [punydecode [string range $part 4 end]]
}
lappend parts $part
}
return [join $parts .]
}
variable digits [split "abcdefghijklmnopqrstuvwxyz0123456789" ""]
# Bootstring parameters for Punycode
variable base 36
variable tmin 1
variable tmax 26
variable skew 38
variable damp 700
variable initial_bias 72
variable initial_n 0x80
variable max_codepoint 0x10FFFF
proc adapt {delta first numchars} {
variable base
variable tmin
variable tmax
variable damp
variable skew
|
| ︙ | ︙ |
Changes to library/cookiejar/pkgIndex.tcl.
|
| | | 1 2 3 |
if {![package vsatisfies [package provide Tcl] 8.6-]} {return}
package ifneeded cookiejar 0.2.0 [list source [file join $dir cookiejar.tcl]]
package ifneeded tcl::idna 1.0.1 [list source [file join $dir idna.tcl]]
|
Changes to library/dde/pkgIndex.tcl.
|
| < > | | | | > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
if {[info sharedlibextension] != ".dll"} return
if {[package vsatisfies [package provide Tcl] 9.0-]} {
# On static builds, dde command is a static package
if {![::tcl::build-info static]} {
package ifneeded dde 1.4.6 \
[list load [file join $dir tcl9dde14.dll] Dde]
}
} elseif {[::tcl::pkgconfig get debug]} {
package ifneeded dde 1.4.6 \
[list load [file join $dir tcldde14g.dll] Dde]
} else {
package ifneeded dde 1.4.6 \
[list load [file join $dir tcldde14.dll] Dde]
}
|
Changes to library/icu.tcl.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
::tcl::unsupported::loadIcu
namespace eval ::tcl::unsupported::icu {
# Map Tcl encoding names to ICU and back. Note ICU has multiple aliases
# for the same encoding.
variable tclToIcu
variable icuToTcl
| < < < < < < < < | | | | | < | > > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
::tcl::unsupported::loadIcu
namespace eval ::tcl::unsupported::icu {
# Map Tcl encoding names to ICU and back. Note ICU has multiple aliases
# for the same encoding.
variable tclToIcu
variable icuToTcl
proc LogError {message} {
puts stderr $message
}
proc Init {} {
variable tclToIcu
variable icuToTcl
# There are some special cases where names do not line up
# at all. Map Tcl -> ICU
array set specialCases {
ebcdic ebcdic-cp-us
macCentEuro maccentraleurope
utf16 UTF16_PlatformEndian
utf-16be UnicodeBig
utf-16le UnicodeLittle
utf32 UTF32_PlatformEndian
}
# Ignore all errors. Do not want to hold up Tcl
# if ICU not available
if {[catch {
foreach tclName [encoding names] {
if {[catch {
set icuNames [aliases $tclName]
} erMsg]} {
LogError "Could not get aliases for $tclName: $erMsg"
continue
}
if {[llength $icuNames] == 0} {
# E.g. macGreek -> x-MacGreek
set icuNames [aliases x-$tclName]
if {[llength $icuNames] == 0} {
# Still no joy, check for special cases
if {[info exists specialCases($tclName)]} {
set icuNames [aliases $specialCases($tclName)]
}
}
}
# If the Tcl name is also an ICU name use it else use
# the first name which is the canonical ICU name
set pos [lsearch -exact -nocase $icuNames $tclName]
if {$pos >= 0} {
lappend tclToIcu($tclName) [lindex $icuNames $pos] {*}[lreplace $icuNames $pos $pos]
} else {
set tclToIcu($tclName) $icuNames
}
foreach icuName $icuNames {
lappend icuToTcl($icuName) $tclName
}
}
} errMsg]} {
LogError $errMsg
}
array default set tclToIcu ""
array default set icuToTcl ""
# Redefine ourselves to no-op.
proc Init {} {}
}
# Primarily used during development
proc MappedIcuNames {{pat *}} {
Init
variable icuToTcl
return [array names icuToTcl $pat]
}
|
| ︙ | ︙ | |||
127 128 129 130 131 132 133 |
# the empty string in case not found.
proc icuToTcl {icuName} {
Init
proc icuToTcl {icuName} {
variable icuToTcl
return [lindex $icuToTcl($icuName) 0]
}
| | | > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# the empty string in case not found.
proc icuToTcl {icuName} {
Init
proc icuToTcl {icuName} {
variable icuToTcl
return [lindex $icuToTcl($icuName) 0]
}
icuToTcl $icuName
}
# Returns the ICU equivalent of an Tcl encoding name or
# the empty string in case not found.
proc tclToIcu {tclName} {
Init
proc tclToIcu {tclName} {
variable tclToIcu
return [lindex $tclToIcu($tclName) 0]
}
tclToIcu $tclName
}
namespace export {[a-z]*}
namespace ensemble create
}
|
Changes to library/init.tcl.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | # # All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # | | > > > > > > > > > > > > > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
#
# All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
package require -exact tcl 9.0.5
# Compute the auto path to use in this interpreter.
# The values on the path come from several locations:
#
# The environment variable TCLLIBPATH
#
# tcl_library, which is the directory containing this init.tcl script.
# [tclInit] (Tcl_Init()) searches around for the directory containing this
# init.tcl and defines tcl_library to that location before sourcing it.
#
# The parent directory of tcl_library. Adding the parent
# means that packages in peer directories will be found automatically.
#
# Also add the directory ../lib relative to the directory where the
# executable is located. This is meant to find binary packages for the
# same architecture as the current executable.
#
# tcl_pkgPath, which is set by the platform-specific initialization routines
# On UNIX it is compiled in
# On Windows, it is not used
#
# (Ticket 41c9857bdd) In a safe interpreter, this file does not set
# ::auto_path (other than to {} if it is undefined). The caller, typically
# a Safe Base command, is responsible for setting ::auto_path.
if {![info exists auto_path]} {
if {[info exists env(TCLLIBPATH)] && (![interp issafe])} {
set auto_path [apply {{} {
lmap path $::env(TCLLIBPATH) {
# Paths relative to unresolvable home dirs are ignored
if {[catch {file tildeexpand $path} expanded_path]} {
continue
}
set expanded_path
}
}}]
} else {
set auto_path ""
}
}
namespace eval tcl {
if {![interp issafe]} {
variable Dir
foreach Dir [list $::tcl_library [file dirname $::tcl_library]] {
if {$Dir ni $::auto_path} {
lappend ::auto_path $Dir
}
}
set Dir [file join [file dirname [file dirname \
[info nameofexecutable]]] lib]
if {$Dir ni $::auto_path} {
lappend ::auto_path $Dir
}
if {[info exists ::tcl_pkgPath]} { catch {
foreach Dir $::tcl_pkgPath {
if {$Dir ni $::auto_path} {
lappend ::auto_path $Dir
}
}
}}
variable Path [encoding dirs]
set Dir [file join $::tcl_library encoding]
if {$Dir ni $Path} {
lappend Path $Dir
encoding dirs $Path
}
unset Dir Path
}
}
namespace eval tcl::Pkg {}
# Setup the unknown package handler
if {[interp issafe]} {
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
} else {
# Set up search for Tcl Modules (TIP #189).
# and setup platform specific unknown package handlers
if {$tcl_platform(os) eq "Darwin"
&& $tcl_platform(platform) eq "unix"} {
package unknown {::tcl::tm::UnknownHandler \
{::tcl::MacOSXPkgUnknown ::tclPkgUnknown}}
} else {
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
}
# Set up the 'clock' ensemble
apply {{} {
set cmdmap [dict create]
foreach cmd {add clicks format microseconds milliseconds scan seconds} {
dict set cmdmap $cmd ::tcl::clock::$cmd
}
namespace inscope ::tcl::clock [list namespace ensemble create -command \
::clock -map $cmdmap]
::tcl::unsupported::clock::configure -init-complete
}}
}
# Conditionalize for presence of exec.
if {[namespace which -command exec] eq ""} {
# Some machines do not have exec. Also, on all
|
| ︙ | ︙ | |||
498 499 500 501 502 503 504 |
namespace inscope :: $auto_index($name)
}
}
}
}
# auto_execok --
| > > > > > > > > > | > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
namespace inscope :: $auto_index($name)
}
}
}
}
# auto_execok --
#
# Returns string that indicates name of program to execute if
# name corresponds to a shell builtin or an executable in the
# Windows search path, or "" otherwise. Builds an associative
# array auto_execs that caches information about previous checks,
# for speed.
#
# Arguments:
# name - Name of a command.
if {$tcl_platform(platform) eq "windows"} {
# Windows version.
#
# Note that file executable doesn't work under Windows, so we have to
# look for files with .exe, .com, or .bat extensions. Also, the path
# may be in the Path or PATH environment variables, and path
# components are separated with semicolons, not colons as under Unix.
#
proc auto_execok name {
global auto_execs env tcl_platform
if {[info exists auto_execs($name)]} {
return $auto_execs($name)
}
set auto_execs($name) ""
set shellBuiltins [list assoc call cd cls color copy date del dir echo \
erase exit ftype for if md mkdir mklink move path \
pause prompt rd ren rename rmdir set start time \
title type ver vol]
if {[info exists env(PATHEXT)]} {
# Add an initial ; to have the {} extension check first.
set execExtensions [split ";$env(PATHEXT)" ";"]
} else {
set execExtensions [list {} .com .exe .bat .cmd]
}
if {[string tolower $name] in $shellBuiltins} {
# When this is command.com for some reason on Win2K, Tcl won't
# exec it unless the case is right, which this corrects. COMSPEC
# may not point to a real file, so do the check.
set cmd $env(COMSPEC)
if {[file exists $cmd]} {
set cmd [file attributes $cmd -shortname]
}
return [set auto_execs($name) [list $cmd /c $name]]
}
if {[llength [file split $name]] != 1} {
foreach ext $execExtensions {
set file ${name}${ext}
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
return ""
}
set path "[file dirname [info nameofexecutable]];.;"
if {[info exists env(SystemRoot)]} {
set windir $env(SystemRoot)
} elseif {[info exists env(WINDIR)]} {
set windir $env(WINDIR)
}
if {[info exists windir]} {
append path "$windir/system32;$windir/system;$windir;"
}
foreach var {PATH Path path} {
if {[info exists env($var)]} {
append path ";$env($var)"
}
}
foreach ext $execExtensions {
unset -nocomplain checked
foreach dir [split $path {;}] {
# Skip already checked directories
if {[info exists checked($dir)] || ($dir eq "")} {
continue
}
set checked($dir) {}
set file [file join $dir ${name}${ext}]
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
}
return ""
}
} else {
# Unix version.
#
proc auto_execok name {
global auto_execs env
if {[info exists auto_execs($name)]} {
return $auto_execs($name)
}
set auto_execs($name) ""
if {[llength [file split $name]] != 1} {
if {[file executable $name] && ![file isdirectory $name]} {
set auto_execs($name) [list $name]
}
return $auto_execs($name)
}
foreach dir [split $env(PATH) :] {
if {$dir eq ""} {
set dir .
}
set file [file join $dir $name]
if {[file executable $file] && ![file isdirectory $file]} {
set auto_execs($name) [list $file]
return $auto_execs($name)
}
}
return ""
}
}
# ::tcl::CopyDirectory --
#
# This procedure is called by Tcl's core when attempts to call the
# filesystem's copydirectory function fail. The semantics of the call
# are that 'dest' does not yet exist, i.e. dest should become the exact
|
| ︙ | ︙ |
Changes to library/manifest.txt.
1 2 3 4 5 6 7 8 9 10 11 |
###
# Package manifest for all Tcl packages included in the /library file system
###
apply {{dir} {
set isafe [interp issafe]
foreach {safe package version file} {
0 http 2.10.2 {http http.tcl}
1 msgcat 1.7.1 {msgcat msgcat.tcl}
1 opt 0.4.10 {opt optparse.tcl}
0 cookiejar 0.2.0 {cookiejar cookiejar.tcl}
0 tcl::idna 1.0.1 {cookiejar idna.tcl}
| | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
###
# Package manifest for all Tcl packages included in the /library file system
###
apply {{dir} {
set isafe [interp issafe]
foreach {safe package version file} {
0 http 2.10.2 {http http.tcl}
1 msgcat 1.7.1 {msgcat msgcat.tcl}
1 opt 0.4.10 {opt optparse.tcl}
0 cookiejar 0.2.0 {cookiejar cookiejar.tcl}
0 tcl::idna 1.0.1 {cookiejar idna.tcl}
0 platform 1.1.0 {platform platform.tcl}
0 platform::shell 1.1.4 {platform shell.tcl}
1 tcltest 2.5.11 {tcltest tcltest.tcl}
} {
if {$isafe && !$safe} continue
package ifneeded $package $version [list source [file join $dir {*}$file]]
}
}} $dir
|
Changes to library/msgcat/msgcat.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # msgcat.tcl -- # # This file defines various procedures which implement a # message catalog facility for Tcl programs. It should be # loaded with the command "package require msgcat". # # Copyright © 2010-2018 Harald Oehlmann. # Copyright © 1998-2000 Ajuba Solutions. # Copyright © 1998 Mark Harrison. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# msgcat.tcl --
#
# This file defines various procedures which implement a
# message catalog facility for Tcl programs. It should be
# loaded with the command "package require msgcat".
#
# Copyright © 2010-2018 Harald Oehlmann.
# Copyright © 1998-2000 Ajuba Solutions.
# Copyright © 1998 Mark Harrison.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# We use oo::define::self, which is new in Tcl 9.0
package require Tcl 9.0-
# When the version number changes, be sure to update the pkgIndex.tcl file,
# and the installation directory in the Makefiles.
package provide msgcat 1.7.1
namespace eval msgcat {
namespace export mc mcn mcexists mcload mclocale mcmax\
mcmset mcpreferences mcset\
|
| ︙ | ︙ |
Changes to library/msgcat/pkgIndex.tcl.
|
| | | 1 2 |
if {![package vsatisfies [package provide Tcl] 9.0-]} {return}
package ifneeded msgcat 1.7.1 [list source -encoding utf-8 [file join $dir msgcat.tcl]]
|
Changes to library/opt/optparse.tcl.
| ︙ | ︙ | |||
739 740 741 742 743 744 745 | set state "args" } # apply 'smart' 'fuzzy' logic to try to make # description writer's life easy, and our's difficult : # let's guess the missing arguments :-) | | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 |
set state "args"
}
# apply 'smart' 'fuzzy' logic to try to make
# description writer's life easy, and our's difficult :
# let's guess the missing arguments :-)
switch $lg {
1 {
if {$isflag} {
return [OptNewInst $state $varname boolflag false ""]
} else {
return [OptNewInst $state $varname any "" ""]
}
}
|
| ︙ | ︙ |
Changes to library/package.tcl.
| ︙ | ︙ | |||
218 219 220 221 222 223 224 |
proc auto_import {args} {}
# reserve the ::tcl namespace for support procs and temporary
# variables. This might make it awkward to generate a
# pkgIndex.tcl file for the ::tcl namespace.
namespace eval ::tcl {
| | | | > | | > > > | | < < < < | < | | < < < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < > < | | | | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
proc auto_import {args} {}
# reserve the ::tcl namespace for support procs and temporary
# variables. This might make it awkward to generate a
# pkgIndex.tcl file for the ::tcl namespace.
namespace eval ::tcl {
variable dir ;# Current directory being processed
variable file ;# Current file being processed
variable direct ;# -direct flag value
variable x ;# Loop variable
variable debug ;# For debugging
variable type ;# "load" or "source", for -direct
variable namespaces ;# Existing namespaces (e.g., ::tcl)
variable packages ;# Existing packages (e.g., Tcl)
variable origCmds ;# Existing commands
variable newCmds ;# Newly created commands
variable newPkgs {} ;# Newly created packages
}
}
$c eval [list set ::tcl::dir $dir]
$c eval [list set ::tcl::file $file]
$c eval [list set ::tcl::direct $direct]
# Download needed procedures into the child because we've just deleted
# the unknown procedure. This doesn't handle procedures with default
# arguments.
foreach p {::tcl::Pkg::CompareExtension} {
$c eval [list namespace eval [namespace qualifiers $p] {}]
$c eval [list proc $p [info args $p] [info body $p]]
}
try {
$c eval {
set ::tcl::debug "loading or sourcing"
# we need to track command defined by each package even in the
# -direct case, because they are needed internally by the
# "partial pkgIndex.tcl" step above.
proc ::tcl::GetAllNamespaces {{root ::}} {
set list $root
foreach ns [namespace children $root] {
lappend list {*}[::tcl::GetAllNamespaces $ns]
}
return $list
}
# init the list of existing namespaces, packages, commands
foreach ::tcl::x [::tcl::GetAllNamespaces] {
set ::tcl::namespaces($::tcl::x) 1
}
foreach ::tcl::x [package names] {
if {[package provide $::tcl::x] ne ""} {
set ::tcl::packages($::tcl::x) 1
}
}
set ::tcl::origCmds [info commands]
# Try to load the file if it has the shared library extension,
# otherwise source it. It's important not to try to load
# files that aren't shared libraries, because on some systems
# (like SunOS) the loader will abort the whole application
# when it gets an error.
if {[::tcl::Pkg::CompareExtension $::tcl::file [info sharedlibextension]]} {
# The "file join ." command below is necessary. Without
# it, if the file name has no \'s and we're on UNIX, the
# load command will invoke the LD_LIBRARY_PATH search
# mechanism, which could cause the wrong file to be used.
set ::tcl::debug loading
load [file join $::tcl::dir $::tcl::file]
set ::tcl::type load
} else {
set ::tcl::debug sourcing
source [file join $::tcl::dir $::tcl::file]
set ::tcl::type source
}
# As a performance optimization, if we are creating direct
# load packages, don't bother figuring out the set of commands
# created by the new packages. We only need that list for
# setting up the autoloading used in the non-direct case.
if {!$::tcl::direct} {
# See what new namespaces appeared, and import commands
# from them. Only exported commands go into the index.
foreach ::tcl::x [::tcl::GetAllNamespaces] {
if {![info exists ::tcl::namespaces($::tcl::x)]} {
namespace import -force ${::tcl::x}::*
}
# Figure out what commands appeared
foreach ::tcl::x [info commands] {
set ::tcl::newCmds($::tcl::x) 1
}
foreach ::tcl::x $::tcl::origCmds {
unset -nocomplain ::tcl::newCmds($::tcl::x)
}
foreach ::tcl::x [array names ::tcl::newCmds] {
# determine which namespace a command comes from
set ::tcl::abs [namespace origin $::tcl::x]
# special case so that global names have no
# leading ::, this is required by the unknown
# command
set ::tcl::abs \
[lindex [auto_qualify $::tcl::abs ::] 0]
if {$::tcl::x ne $::tcl::abs} {
# Name changed during qualification
set ::tcl::newCmds($::tcl::abs) 1
unset ::tcl::newCmds($::tcl::x)
}
}
}
}
# Look through the packages that appeared, and if there is a
# version provided, then record it
foreach ::tcl::x [package names] {
if {[package provide $::tcl::x] ne ""
&& ![info exists ::tcl::packages($::tcl::x)]} {
lappend ::tcl::newPkgs \
[list $::tcl::x [package provide $::tcl::x]]
}
}
}
} on error msg {
set what [$c eval set ::tcl::debug]
if {$doVerbose} {
tclLog "warning: error while $what $file: $msg"
}
} on ok {} {
set what [$c eval set ::tcl::debug]
if {$doVerbose} {
tclLog "successful $what of $file"
}
set type [$c eval set ::tcl::type]
set cmds [lsort [$c eval array names ::tcl::newCmds]]
set pkgs [$c eval set ::tcl::newPkgs]
if {$doVerbose} {
if {!$direct} {
tclLog "commands provided were $cmds"
}
tclLog "packages provided were $pkgs"
}
if {[llength $pkgs] > 1} {
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 |
append index "# \"package ifneeded\" command to set up package-related\n"
append index "# information so that packages will be loaded automatically\n"
append index "# in response to \"package require\" commands. When this\n"
append index "# script is sourced, the variable \$dir must contain the\n"
append index "# full path name of this file's directory.\n"
foreach pkg [lsort [array names files]] {
| | > | | < | | < | < | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
append index "# \"package ifneeded\" command to set up package-related\n"
append index "# information so that packages will be loaded automatically\n"
append index "# in response to \"package require\" commands. When this\n"
append index "# script is sourced, the variable \$dir must contain the\n"
append index "# full path name of this file's directory.\n"
foreach pkg [lsort [array names files]] {
set cmd {}
lassign $pkg name version
lappend cmd ::tcl::Pkg::Create -name $name -version $version
foreach spec [lsort -index 0 $files($pkg)] {
foreach {file type procs} $spec {
if {$direct} {
set procs {}
}
lappend cmd "-$type" [list $file $procs]
}
}
append index "\n[eval $cmd]"
}
set f [open [file join $dir pkgIndex.tcl] w]
fconfigure $f -encoding utf-8 -translation lf
puts $f $index
close $f
}
# tclPkgSetup --
# This is a utility procedure use by pkgIndex.tcl files. It is invoked as
# part of a "package ifneeded" script. It calls "package provide" to indicate
# that a package is available, then sets entries in the auto_index array so
# that the package's files will be auto-loaded when the commands are used.
|
| ︙ | ︙ | |||
495 496 497 498 499 500 501 502 503 504 505 506 507 508 |
} trap {POSIX EACCES} {} {
# $file was not readable; silently ignore
continue
} trap {TCL PACKAGE VERSIONCONFLICT} {} {
# In case of version conflict, silently ignore
continue
} on error msg {
tclLog "error reading package index file $file: $msg"
} on ok {} {
set procdDirs($dir) 1
}
}
}
}
| > > > > | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
} trap {POSIX EACCES} {} {
# $file was not readable; silently ignore
continue
} trap {TCL PACKAGE VERSIONCONFLICT} {} {
# In case of version conflict, silently ignore
continue
} on error msg {
if {[regexp {version conflict for package} $msg]} {
# In case of version conflict, silently ignore
continue
}
tclLog "error reading package index file $file: $msg"
} on ok {} {
set procdDirs($dir) 1
}
}
}
}
|
| ︙ | ︙ | |||
516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
} trap {POSIX EACCES} {} {
# $file was not readable; silently ignore
continue
} trap {TCL PACKAGE VERSIONCONFLICT} {} {
# In case of version conflict, silently ignore
continue
} on error msg {
tclLog "error reading package index file $file: $msg"
} on ok {} {
set procdDirs($dir) 1
}
}
}
| > > > > | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
} trap {POSIX EACCES} {} {
# $file was not readable; silently ignore
continue
} trap {TCL PACKAGE VERSIONCONFLICT} {} {
# In case of version conflict, silently ignore
continue
} on error msg {
if {[regexp {version conflict for package} $msg]} {
# In case of version conflict, silently ignore
continue
}
tclLog "error reading package index file $file: $msg"
} on ok {} {
set procdDirs($dir) 1
}
}
}
|
| ︙ | ︙ | |||
604 605 606 607 608 609 610 611 612 613 614 615 616 617 |
} trap {POSIX EACCES} {} {
# $file was not readable; silently ignore
continue
} trap {TCL PACKAGE VERSIONCONFLICT} {} {
# In case of version conflict, silently ignore
continue
} on error msg {
tclLog "error reading package index file $file: $msg"
} on ok {} {
set procdDirs($dir) 1
}
}
}
set use_path [lrange $use_path 0 end-1]
| > > > > | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
} trap {POSIX EACCES} {} {
# $file was not readable; silently ignore
continue
} trap {TCL PACKAGE VERSIONCONFLICT} {} {
# In case of version conflict, silently ignore
continue
} on error msg {
if {[regexp {version conflict for package} $msg]} {
# In case of version conflict, silently ignore
continue
}
tclLog "error reading package index file $file: $msg"
} on ok {} {
set procdDirs($dir) 1
}
}
}
set use_path [lrange $use_path 0 end-1]
|
| ︙ | ︙ |
Changes to library/platform/pkgIndex.tcl.
1 |
if {![package vsatisfies [package provide Tcl] 8.6-]} {return}
| | | 1 2 3 |
if {![package vsatisfies [package provide Tcl] 8.6-]} {return}
package ifneeded platform 1.1.1 [list source -encoding utf-8 [file join $dir platform.tcl]]
package ifneeded platform::shell 1.1.4 [list source -encoding utf-8 [file join $dir shell.tcl]]
|
Changes to library/platform/platform.tcl.
| ︙ | ︙ | |||
193 194 195 196 197 198 199 |
} else {
incr major -4
append plat 10.$major
}
return "${plat}-${cpu}"
}
linux {
| | > | | > > > > > > > > > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
} else {
incr major -4
append plat 10.$major
}
return "${plat}-${cpu}"
}
linux {
# Look for the libc*.so and determine its version
# (libc5/6, libc6 further glibc 2.X)
set v unknown
# Determine in which directory to look. /lib, or /lib64.
# For that we use the tcl_platform(wordSize).
#
# We could use the 'cpu' info, per the equivalence below,
# that however would be restricted to intel. And this may
# be a arm, mips, etc. system. The wordsize is more
# fundamental.
#
# ix86 <=> (wordSize == 4) <=> 32 bit ==> /lib
# x86_64 <=> (wordSize == 8) <=> 64 bit ==> /lib64
#
# Do not look into /lib64 even if present, if the cpu
# doesn't fit.
# TODO: Determine the prefixes (i386, x86_64, ...) for
# other cpus. The path after the generic one is utterly
# specific to intel right now. Ok, on Ubuntu, possibly
# other Debian systems we may apparently be able to query
# the necessary CPU code. If we can't we simply use the
# hardwired fallback.
switch -- $tcl_platform(wordSize) {
4 {
lappend bases /lib
try {
set res [exec dpkg-architecture -qDEB_HOST_MULTIARCH]
# dpkg-arch returns the full triple, not just cpu.
lappend bases /lib/$res
} on error {} {
lappend bases /lib/i386-linux-gnu
}
}
8 {
lappend bases /lib64
try {
set res [exec dpkg-architecture -qDEB_HOST_MULTIARCH]
# dpkg-arch returns the full triple, not just cpu.
lappend bases /lib/$res
} on error {} {
lappend bases /lib/x86_64-linux-gnu
}
}
default {
return -code error "Bad wordSize $tcl_platform(wordSize), expected 4 or 8"
}
}
foreach base $bases {
if {[LibcVersion $base -> v]} break
}
append plat -$v
return "${plat}-${cpu}"
}
}
return $id
}
proc ::platform::LibcVersion {base _->_ vv} {
upvar 1 $vv v
set libclist [lsort [glob -nocomplain -directory $base libc.so.*]]
if {![llength $libclist]} { return 0 }
set libc [lindex $libclist 0]
# Try executing the library first. This should succeed
# for a glibc library, and return the version information.
try {
set vdata [lindex [split [exec $libc] \n] 0]
} on ok {} {
regexp {version ([0-9]+(\.[0-9]+)*)} $vdata -> v
lassign [split $v .] major minor
set v glibc${major}.${minor}
return 1
} on error {} {
# We had trouble executing the library. We are now
# inspecting its name to determine the version
# number. This code by Larry McVoy.
if {[regexp -- {libc-([0-9]+)\.([0-9]+)} $libc -> major minor]} {
set v glibc${major}.${minor}
return 1
}
}
return 0
}
# -- platform::patterns
#
# Given an exact platform identifier, i.e. _not_ the generic
# identifier it assembles a list of exact platform identifier
# describing platform which should be compatible with the
# input.
|
| ︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 |
# no v, no cpu ... nothing
}
}
}
lappend res tcl ; # Pure tcl packages are always compatible.
return $res
}
# ### ### ### ######### ######### #########
## Ready
| > | | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
# no v, no cpu ... nothing
}
}
}
lappend res tcl ; # Pure tcl packages are always compatible.
return $res
}
# ### ### ### ######### ######### #########
## Ready
package provide platform 1.1.1
# ### ### ### ######### ######### #########
## Demo application
if {[info exists argv0] && ($argv0 eq [info script])} {
puts ====================================
parray tcl_platform
|
| ︙ | ︙ |
Changes to library/registry/pkgIndex.tcl.
|
| > | > | | | | > > | < > > | 1 2 3 4 5 6 7 8 9 10 11 12 |
if {![package vsatisfies [package provide Tcl] 8.5-]} return
if {[info sharedlibextension] != ".dll"} return
if {[package vsatisfies [package provide Tcl] 9.0-]} {
# On static builds, registry command is a static package
if {![::tcl::build-info static]} {
package ifneeded registry 1.3.7 \
[list load [file join $dir tcl9registry13.dll] Registry]
}
} else {
package ifneeded registry 1.3.7 \
[list load [file join $dir tclregistry13.dll] Registry]
}
|
Changes to library/safe.tcl.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 |
namespace export interpCreate interpInit interpConfigure interpDelete \
interpAddToAccessPath interpFindInAccessPath setLogCmd
}
# Helper function to resolve the dual way of specifying staticsok (either
# by -noStatics or -statics 0)
proc ::safe::InterpStatics {} {
| | > > | | > | > > | | > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
namespace export interpCreate interpInit interpConfigure interpDelete \
interpAddToAccessPath interpFindInAccessPath setLogCmd
}
# Helper function to resolve the dual way of specifying staticsok (either
# by -noStatics or -statics 0)
proc ::safe::InterpStatics {} {
foreach v {Args statics noStatics} {
upvar $v $v
}
set flag [::tcl::OptProcArgGiven -noStatics]
if {$flag && (!$noStatics == !$statics)
&& ([::tcl::OptProcArgGiven -statics])} {
return -code error\
"conflicting values given for -statics and -noStatics"
}
if {$flag} {
return [expr {!$noStatics}]
} else {
return $statics
}
}
# Helper function to resolve the dual way of specifying nested loading
# (either by -nestedLoadOk or -nested 1)
proc ::safe::InterpNested {} {
foreach v {Args nested nestedLoadOk} {
upvar $v $v
}
set flag [::tcl::OptProcArgGiven -nestedLoadOk]
# note that the test here is the opposite of the "InterpStatics" one
# (it is not -noNested... because of the wanted default value)
if {$flag && (!$nestedLoadOk != !$nested)
&& ([::tcl::OptProcArgGiven -nested])} {
return -code error\
"conflicting values given for -nested and -nestedLoadOk"
}
if {$flag} {
# another difference with "InterpStatics"
return $nestedLoadOk
} else {
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
variable AutoPathSync
if {$AutoPathSync} {
set autoPath {}
}
set Args [::tcl::OptKeyParse ::safe::interpCreate $args]
RejectExcessColons $child
| | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
variable AutoPathSync
if {$AutoPathSync} {
set autoPath {}
}
set Args [::tcl::OptKeyParse ::safe::interpCreate $args]
RejectExcessColons $child
set withAutoPath [::tcl::OptProcArgGiven -autoPath]
InterpCreate $child $accessPath \
[InterpStatics] [InterpNested] $deleteHook $autoPath $withAutoPath
}
proc ::safe::interpInit {args} {
variable AutoPathSync
if {$AutoPathSync} {
set autoPath {}
}
set Args [::tcl::OptKeyParse ::safe::interpIC $args]
if {![::interp exists $child]} {
return -code error "\"$child\" is not an interpreter"
}
RejectExcessColons $child
set withAutoPath [::tcl::OptProcArgGiven -autoPath]
InterpInit $child $accessPath \
[InterpStatics] [InterpNested] $deleteHook $autoPath $withAutoPath
}
# Check that the given child is "one of us"
proc ::safe::CheckInterp {child} {
namespace upvar ::safe [VarName $child] state
|
| ︙ | ︙ | |||
120 121 122 123 124 125 126 |
# This is even more complicated by the boolean flags with no values that
# we had the bad idea to support for the sake of user simplicity in
# create/init but which makes life hard in configure...
# So this will be hopefully written and some integrated with opt1.0
# (hopefully for tcl9.0 ?)
proc ::safe::interpConfigure {args} {
variable AutoPathSync
| | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# This is even more complicated by the boolean flags with no values that
# we had the bad idea to support for the sake of user simplicity in
# create/init but which makes life hard in configure...
# So this will be hopefully written and some integrated with opt1.0
# (hopefully for tcl9.0 ?)
proc ::safe::interpConfigure {args} {
variable AutoPathSync
switch [llength $args] {
1 {
# If we have exactly 1 argument the semantic is to return all
# the current configuration. We still call OptKeyParse though
# we know that "child" is our given argument because it also
# checks for the "-help" option.
set Args [::tcl::OptKeyParse ::safe::interpIC $args]
CheckInterp $child
|
| ︙ | ︙ | |||
208 209 210 211 212 213 214 | # create did set Args [::tcl::OptKeyParse ::safe::interpIC $args] CheckInterp $child namespace upvar ::safe [VarName $child] state # Get the current (and not the default) values of whatever has # not been given: | | | > > | > > > | > | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# create did
set Args [::tcl::OptKeyParse ::safe::interpIC $args]
CheckInterp $child
namespace upvar ::safe [VarName $child] state
# Get the current (and not the default) values of whatever has
# not been given:
if {![::tcl::OptProcArgGiven -accessPath]} {
set doreset 0
set accessPath $state(access_path)
} else {
set doreset 1
}
if {(!$AutoPathSync) && (![::tcl::OptProcArgGiven -autoPath])} {
set autoPath $state(auto_path)
} elseif {$AutoPathSync} {
set autoPath {}
} else {
}
if {
![::tcl::OptProcArgGiven -statics]
&& ![::tcl::OptProcArgGiven -noStatics]
} then {
set statics $state(staticsok)
} else {
set statics [InterpStatics]
}
if {
[::tcl::OptProcArgGiven -nested] ||
[::tcl::OptProcArgGiven -nestedLoadOk]
} then {
set nested [InterpNested]
} else {
set nested $state(nestedok)
}
if {![::tcl::OptProcArgGiven -deleteHook]} {
set deleteHook $state(cleanupHook)
}
# Now reconfigure
set withAutoPath [::tcl::OptProcArgGiven -autoPath]
InterpSetConfig $child $accessPath $statics $nested $deleteHook $autoPath $withAutoPath
# auto_reset the child (to completely sync the new access_path) tests safe-9.8 safe-9.9
if {$doreset} {
if {[catch {::interp eval $child {auto_reset}} msg]} {
Log $child "auto_reset failed: $msg"
} else {
|
| ︙ | ︙ | |||
345 346 347 348 349 350 351 |
set access_path $auto_path
# Make sure that tcl_library is in auto_path and at the first
# position (needed by setAccessPath)
set where [lsearch -exact $access_path [info library]]
if {$where < 0} {
# not found, add it.
| | | > | | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
set access_path $auto_path
# Make sure that tcl_library is in auto_path and at the first
# position (needed by setAccessPath)
set where [lsearch -exact $access_path [info library]]
if {$where < 0} {
# not found, add it.
set access_path [linsert $access_path 0 [info library]]
Log $child "tcl_library was not in auto_path,\
added it to child's access_path" NOTICE
} elseif {$where != 0} {
# not first, move it first
set access_path [linsert \
[lreplace $access_path $where $where] \
0 [info library]]
Log $child "tcl_libray was not in first in auto_path,\
moved it to front of child's access_path" NOTICE
}
set raw_auto_path $access_path
# Add 1st level subdirs (will searched by auto loading from tcl
|
| ︙ | ︙ | |||
393 394 395 396 397 398 399 |
set map_access_path {}
set remap_access_path {}
set child_tm_path {}
set i 0
foreach dir $access_path {
set token [PathToken $i]
| | | | | | | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
set map_access_path {}
set remap_access_path {}
set child_tm_path {}
set i 0
foreach dir $access_path {
set token [PathToken $i]
lappend child_access_path $token
lappend map_access_path $token $dir
lappend remap_access_path $dir $token
lappend norm_access_path [file normalize $dir]
incr i
}
# Set the child auto_path to a tokenized raw_auto_path.
# Silently ignore any directories that are not in the access path.
# If [setSyncMode], SyncAccessPath will overwrite this value with the
# full access path.
# If ![setSyncMode], Safe Base code will not change this value.
set tokens_auto_path {}
foreach dir $raw_auto_path {
if {[dict exists $remap_access_path $dir]} {
lappend tokens_auto_path [dict get $remap_access_path $dir]
}
}
::interp eval $child [list set auto_path $tokens_auto_path]
# Add the tcl::tm directories to the access path.
set morepaths [::tcl::tm::list]
set firstpass 1
while {[llength $morepaths]} {
set addpaths $morepaths
set morepaths {}
|
| ︙ | ︙ | |||
434 435 436 437 438 439 440 | # access path but not in the module path. lappend child_tm_path [dict get $remap_access_path $dir] } continue } set token [PathToken $i] | | | | | | | 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
# access path but not in the module path.
lappend child_tm_path [dict get $remap_access_path $dir]
}
continue
}
set token [PathToken $i]
lappend access_path $dir
lappend child_access_path $token
lappend map_access_path $token $dir
lappend remap_access_path $dir $token
lappend norm_access_path [file normalize $dir]
if {$firstpass} {
# $dir is in [::tcl::tm::list] and belongs in the child_tm_path.
# Later passes handle subdirectories, which belong in the
# access path but not in the module path.
lappend child_tm_path $token
}
incr i
|
| ︙ | ︙ | |||
485 486 487 488 489 490 491 |
# Convert tokens to directories where possible.
# Leave undefined tokens unconverted. They are
# nonsense in both the child and the parent.
#
proc ::safe::DetokPath {child tokenPath} {
namespace upvar ::safe [VarName $child] state
| > | | > | > > > > | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
# Convert tokens to directories where possible.
# Leave undefined tokens unconverted. They are
# nonsense in both the child and the parent.
#
proc ::safe::DetokPath {child tokenPath} {
namespace upvar ::safe [VarName $child] state
set childPath {}
foreach token $tokenPath {
if {[dict exists $state(access_path,map) $token]} {
lappend childPath [dict get $state(access_path,map) $token]
} else {
lappend childPath $token
}
}
return $childPath
}
#
#
# interpFindInAccessPath:
# Search for a real directory and returns its virtual Id (including the
# "$")
|
| ︙ | ︙ | |||
525 526 527 528 529 530 531 |
if {[dict exists $state(access_path,remap) $path]} {
return [dict get $state(access_path,remap) $path]
}
# new one, add it:
set token [PathToken [llength $state(access_path)]]
| | | | | | | 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
if {[dict exists $state(access_path,remap) $path]} {
return [dict get $state(access_path,remap) $path]
}
# new one, add it:
set token [PathToken [llength $state(access_path)]]
lappend state(access_path) $path
lappend state(access_path,child) $token
lappend state(access_path,map) $token $path
lappend state(access_path,remap) $path $token
lappend state(access_path,norm) [file normalize $path]
SyncAccessPath $child
return $token
}
# This procedure applies the initializations to an already existing
# interpreter. It is useful when you want to install the safe base aliases
|
| ︙ | ︙ | |||
597 598 599 600 601 602 603 |
# Subcommands of info
::interp alias $child ::tcl::info::nameofexecutable {} \
::safe::AliasExeName $child
# Source init.tcl and tm.tcl into the child, to get auto_load and
# other procedures defined:
| | | | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 |
# Subcommands of info
::interp alias $child ::tcl::info::nameofexecutable {} \
::safe::AliasExeName $child
# Source init.tcl and tm.tcl into the child, to get auto_load and
# other procedures defined:
if {[catch {::interp eval $child {
source [file join $tcl_library init.tcl]
}} msg opt]} {
Log $child "can't source init.tcl ($msg)"
return -options $opt "can't source init.tcl into child $child ($msg)"
}
if {[catch {::interp eval $child {
source [file join $tcl_library tm.tcl]
}} msg opt]} {
Log $child "can't source tm.tcl ($msg)"
return -options $opt "can't source tm.tcl into child $child ($msg)"
}
# Sync the paths used to search for Tcl modules. This can be done only
# now, after tm.tcl was loaded.
namespace upvar ::safe [VarName $child] state
|
| ︙ | ︙ | |||
706 707 708 709 710 711 712 |
return
}
# Set (or get) the logging mechanism
proc ::safe::setLogCmd {args} {
variable Log
| | > | > | > | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 |
return
}
# Set (or get) the logging mechanism
proc ::safe::setLogCmd {args} {
variable Log
set la [llength $args]
if {$la == 0} {
return $Log
} elseif {$la == 1} {
set Log [lindex $args 0]
} else {
set Log $args
}
if {$Log eq ""} {
# Disable logging completely. Calls to it will be compiled out
# of all users.
proc ::safe::Log {args} {}
} else {
|
| ︙ | ︙ | |||
739 740 741 742 743 744 745 |
#
proc ::safe::SyncAccessPath {child} {
variable AutoPathSync
namespace upvar ::safe [VarName $child] state
set child_access_path $state(access_path,child)
if {$AutoPathSync} {
| | > | | 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 |
#
proc ::safe::SyncAccessPath {child} {
variable AutoPathSync
namespace upvar ::safe [VarName $child] state
set child_access_path $state(access_path,child)
if {$AutoPathSync} {
::interp eval $child [list set auto_path $child_access_path]
Log $child "auto_path in $child has been set to $child_access_path"\
NOTICE
}
# This code assumes that info library is the first element in the
# list of access path's. See -> InterpSetConfig for the code which
# ensures this condition.
::interp eval $child [list \
set tcl_library [lindex $child_access_path 0]]
return
}
# Returns the virtual token for directory number N.
proc ::safe::PathToken {n} {
# We need to have a ":" in the token string so [file join] on the
# mac won't turn it into a relative path.
|
| ︙ | ︙ | |||
877 878 879 880 881 882 883 |
DirInAccessPath $child $dir
} on error msg {
Log $child $msg
if {$got(-nocomplain)} return
return -code error "permission denied"
}
if {$got(--)} {
| | | | 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 |
DirInAccessPath $child $dir
} on error msg {
Log $child $msg
if {$got(-nocomplain)} return
return -code error "permission denied"
}
if {$got(--)} {
set cmd [linsert $cmd end-1 -directory $dir]
} else {
lappend cmd -directory $dir
}
} else {
# The code after this "if ... else" block would conspire to return with
# no results in this case, if it were allowed to proceed. Instead,
# return now and reduce the number of cases to be considered later.
Log $child {option -directory must be supplied}
if {$got(-nocomplain)} return
return -code error "permission denied"
}
# Apply the -join semantics ourselves (hence -join not copied to $cmd)
if {$got(-join)} {
set args [lreplace $args $at end [join [lrange $args $at end] "/"]]
}
# Process the pattern arguments. If we've done a join there is only one
# pattern argument.
set firstPattern [llength $cmd]
foreach opt [lrange $args $at end] {
|
| ︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 |
set msg "wrong # args: should be \"source ?-encoding E? fileName\""
Log $child "$msg ($args)"
return -code error $msg
}
set file [lindex $args $at]
# get the real path from the virtual one.
| | | | | | | | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 |
set msg "wrong # args: should be \"source ?-encoding E? fileName\""
Log $child "$msg ($args)"
return -code error $msg
}
set file [lindex $args $at]
# get the real path from the virtual one.
if {[catch {
set realfile [TranslatePath $child $file]
} msg]} {
Log $child $msg
return -code error "permission denied"
}
# check that the path is in the access path of that child
if {[catch {
FileInAccessPath $child $realfile
} msg]} {
Log $child $msg
return -code error "permission denied"
}
# Check that the filename exists and is readable. If it is not, deliver
# this -errorcode so that caller in tclPkgUnknown does not write a message
# to tclLog. Has no effect on other callers of ::source, which are in
# "package ifneeded" scripts.
if {[catch {
CheckFileName $child $realfile
} msg]} {
Log $child "$realfile:$msg"
return -code error -errorcode {POSIX EACCES} $msg
}
# Passed all the tests, lets source it. Note that we do this all manually
# because we want to control [info script] in the child so information
# doesn't leak so much. [Bug 2913625]
|
| ︙ | ︙ | |||
1080 1081 1082 1083 1084 1085 1086 |
set argc [llength $args]
if {$argc > 2} {
set msg "load error: too many arguments"
Log $child "$msg ($argc) {$file $args}"
return -code error $msg
}
| < < > | > > | 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
set argc [llength $args]
if {$argc > 2} {
set msg "load error: too many arguments"
Log $child "$msg ($argc) {$file $args}"
return -code error $msg
}
# prefix (can be empty if file is not).
set prefix [lindex $args 0]
namespace upvar ::safe [VarName $child] state
# Determine where to load. load use a relative interp path and {}
# means self, so we can directly and safely use passed arg.
set target [lindex $args 1]
if {$target ne ""} {
# we will try to load into a sub sub interp; check that we want to
# authorize that.
if {!$state(nestedok)} {
Log $child "loading to a sub interp (nestedok)\
disabled (trying to load $prefix to $target)"
return -code error "permission denied (nested load)"
|
| ︙ | ︙ | |||
1135 1136 1137 1138 1139 1140 1141 |
}
try {
return [::interp invokehidden $child load $file $prefix $target]
} on error msg {
# Some libraries return no error message.
set msg0 "load of library for prefix $prefix failed"
| | | 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 |
}
try {
return [::interp invokehidden $child load $file $prefix $target]
} on error msg {
# Some libraries return no error message.
set msg0 "load of library for prefix $prefix failed"
if {$msg eq {}} {
set msg $msg0
} else {
set msg "$msg0: $msg"
}
Log $child $msg
return -code error $msg
}
|
| ︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 |
Log $child $msg
return -code error -errorcode {TCL SAFE SUBCOMMAND} $msg
}
# AliasEncodingSystem is the target of the "encoding system" alias in safe
# interpreters.
proc ::safe::AliasEncodingSystem {child args} {
| > | | | > | > > | | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 |
Log $child $msg
return -code error -errorcode {TCL SAFE SUBCOMMAND} $msg
}
# AliasEncodingSystem is the target of the "encoding system" alias in safe
# interpreters.
proc ::safe::AliasEncodingSystem {child args} {
try {
# Must not pass extra arguments; safe interpreters may not set the
# system encoding but they may read it.
if {[llength $args]} {
return -code error -errorcode {TCL WRONGARGS} \
"wrong # args: should be \"encoding system\""
}
} on error {msg options} {
Log $child $msg
return -options $options $msg
}
tailcall ::interp invokehidden $child tcl:encoding:system
}
# Various minor hiding of platform features. [Bug 2913625]
proc ::safe::AliasExeName {child} {
|
| ︙ | ︙ | |||
1249 1250 1251 1252 1253 1254 1255 |
# namespace upvar ::safe S$child state
# becomes
# namespace upvar ::safe [VarName $child] state
# ------------------------------------------------------------------------------
proc ::safe::RejectExcessColons {child} {
set stripped [regsub -all -- {:::*} $child ::]
| | | | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 |
# namespace upvar ::safe S$child state
# becomes
# namespace upvar ::safe [VarName $child] state
# ------------------------------------------------------------------------------
proc ::safe::RejectExcessColons {child} {
set stripped [regsub -all -- {:::*} $child ::]
if {[string range $stripped end-1 end] eq {::}} {
return -code error {interpreter name must not end in "::"}
}
if {$stripped ne $child} {
set msg {interpreter name has excess colons in namespace separators}
return -code error $msg
}
if {[string range $stripped 0 1] eq {::}} {
return -code error {interpreter name must not begin "::"}
}
return
}
proc ::safe::VarName {child} {
# return S$child
|
| ︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 |
# AGAIN.
# (The initialization of AutoPathSync at the end of this file is acceptable
# because Setup has not yet been called.)
proc ::safe::setSyncMode {args} {
variable AutoPathSync
| | | < < < | | | | | | | | | | | | | | | | | < | < | | | | > | 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 |
# AGAIN.
# (The initialization of AutoPathSync at the end of this file is acceptable
# because Setup has not yet been called.)
proc ::safe::setSyncMode {args} {
variable AutoPathSync
if {[llength $args] == 0} {
} elseif {[llength $args] == 1} {
set newValue [lindex $args 0]
if {![string is boolean -strict $newValue]} {
return -code error "new value must be a valid boolean"
}
set args [expr {$newValue && $newValue}]
if {([info vars ::safe::S*] ne {}) && ($args != $AutoPathSync)} {
return -code error \
"cannot set new value while Safe Base child interpreters exist"
}
if {($args != $AutoPathSync)} {
set AutoPathSync {*}$args
::tcl::OptKeyDelete ::safe::interpCreate
::tcl::OptKeyDelete ::safe::interpIC
set TmpLog [setLogCmd]
Setup
setLogCmd $TmpLog
}
} else {
set msg {wrong # args: should be "safe::setSyncMode ?newValue?"}
return -code error $msg
}
return $AutoPathSync
}
namespace eval ::safe {
# internal variables (must not begin with "S")
# AutoPathSync
#
|
| ︙ | ︙ |
Changes to library/tcltest/pkgIndex.tcl.
1 2 3 4 5 6 7 8 9 10 11 |
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex -direct" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
if {![package vsatisfies [package provide Tcl] 8.5-]} {return}
| | | 1 2 3 4 5 6 7 8 9 10 11 12 |
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex -direct" command
# and sourced either when an application starts up or
# by a "package unknown" script. It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands. When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.
if {![package vsatisfies [package provide Tcl] 8.5-]} {return}
package ifneeded tcltest 2.5.11 [list source -encoding utf-8 [file join $dir tcltest.tcl]]
|
Changes to library/tcltest/tcltest.tcl.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
# All rights reserved.
namespace eval tcltest {
# When the version number changes, be sure to update the pkgIndex.tcl file,
# and the install directory in the Makefiles. When the minor version
# changes (new feature) be sure to update the man page as well.
| | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# All rights reserved.
namespace eval tcltest {
# When the version number changes, be sure to update the pkgIndex.tcl file,
# and the install directory in the Makefiles. When the minor version
# changes (new feature) be sure to update the man page as well.
variable Version 2.5.11
# Compatibility support for dumb variables defined in tcltest 1
# Do not use these. Call [package require] and [info patchlevel]
# yourself. You don't need tcltest to wrap it for you.
variable version [package require Tcl 8.5-]
variable patchLevel [info patchlevel]
|
| ︙ | ︙ | |||
749 750 751 752 753 754 755 |
} AcceptScript loadScript
# Default is to run each test file in a separate process
Option -singleproc 0 {
whether to run all tests in one process
} AcceptBoolean singleProcess
| < < < < < | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
} AcceptScript loadScript
# Default is to run each test file in a separate process
Option -singleproc 0 {
whether to run all tests in one process
} AcceptBoolean singleProcess
proc AcceptTemporaryDirectory { directory } {
set directory [AcceptAbsolutePath $directory]
if {![file exists $directory]} {
file mkdir $directory
}
set directory [AcceptDirectory $directory]
if {![file writable $directory]} {
|
| ︙ | ︙ | |||
1600 1601 1602 1603 1604 1605 1606 |
}
DebugPuts 2 "tcltest::debug = [debug]"
DebugPuts 2 "tcltest::testsDirectory = [testsDirectory]"
DebugPuts 2 "tcltest::workingDirectory = [workingDirectory]"
DebugPuts 2 "tcltest::temporaryDirectory = [temporaryDirectory]"
DebugPuts 2 "tcltest::outputChannel = [outputChannel]"
DebugPuts 2 "tcltest::errorChannel = [errorChannel]"
| < | 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 |
}
DebugPuts 2 "tcltest::debug = [debug]"
DebugPuts 2 "tcltest::testsDirectory = [testsDirectory]"
DebugPuts 2 "tcltest::workingDirectory = [workingDirectory]"
DebugPuts 2 "tcltest::temporaryDirectory = [temporaryDirectory]"
DebugPuts 2 "tcltest::outputChannel = [outputChannel]"
DebugPuts 2 "tcltest::errorChannel = [errorChannel]"
DebugPuts 2 "Original environment (tcltest::originalEnv):"
DebugPArray 2 originalEnv
DebugPuts 2 "Constraints:"
DebugPArray 2 testConstraints
}
#####################################################################
|
| ︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 | # # Results: # None. # # Side effects: # Just about anything is possible depending on the test. # | < < < < | < < | | 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 |
#
# Results:
# None.
#
# Side effects:
# Just about anything is possible depending on the test.
#
proc tcltest::test {name description args} {
global tcl_platform
variable testLevel
variable coreModTime
variable fullutf
DebugPuts 3 "test $name $args"
DebugDo 1 {
|
| ︙ | ︙ |
Changes to library/writefile.tcl.
1 2 3 4 5 6 7 8 9 10 11 |
# writeFile:
# Write the contents of a file.
#
# Copyright © 2023 Donal K Fellows.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
proc writeFile {args} {
# Parse the arguments
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# writeFile:
# Write the contents of a file.
#
# Copyright © 2023 Donal K Fellows.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
proc writeFile {args} {
# Parse the arguments
switch [llength $args] {
2 {
lassign $args filename data
set mode text
}
3 {
lassign $args filename mode data
set MODES {binary text}
|
| ︙ | ︙ |
Changes to macosx/GNUmakefile.
1 2 3 4 5 6 | ######################################################################################################## # # Makefile wrapper to build tcl on Mac OS X in a way compatible with the tk/macosx Xcode buildsystem # uses the standard Unix build system in tcl/unix (which can be used directly instead of this # if you are not using the tk/macosx projects). # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ######################################################################################################## # # Makefile wrapper to build tcl on Mac OS X in a way compatible with the tk/macosx Xcode buildsystem # uses the standard Unix build system in tcl/unix (which can be used directly instead of this # if you are not using the tk/macosx projects). # # Copyright (c) 2002-2008 Daniel A. Steffen <das@users.sourceforge.net> # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. ######################################################################################################## #------------------------------------------------------------------------------------------------------- # customizable settings |
| ︙ | ︙ | |||
179 180 181 182 183 184 185 |
ifeq (${BUILD_STYLE}_${EMBEDDED_BUILD},Development_)
# keep copy of debug library around, so that
# Deployment build can be installed on top
# of Development build without overwriting
# the debug library
@if [ -d "${INSTALL_ROOT}${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION}" ]; then \
cd "${INSTALL_ROOT}${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION}"; \
| < | < < < | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
ifeq (${BUILD_STYLE}_${EMBEDDED_BUILD},Development_)
# keep copy of debug library around, so that
# Deployment build can be installed on top
# of Development build without overwriting
# the debug library
@if [ -d "${INSTALL_ROOT}${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION}" ]; then \
cd "${INSTALL_ROOT}${LIBDIR}/${PRODUCT_NAME}.framework/Versions/${VERSION}"; \
ln -f "${PRODUCT_NAME}" "${PRODUCT_NAME}_debug"; \
fi
endif
clean-${PROJECT}: %-${PROJECT}:
${DO_MAKE}
rm -rf "${SYMROOT}"/{${PRODUCT_NAME}.framework,${TCLSH},tcltest}
rm -f "${OBJ_DIR}"{"${LIBDIR}","${BINDIR}"} && \
|
| ︙ | ︙ |
Changes to macosx/README.
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
Detailed Instructions for building with macosx/GNUmakefile
----------------------------------------------------------
- Unpack the Tcl source release archive.
- The following instructions assume the Tcl source tree is named "tcl${ver}",
| | | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
Detailed Instructions for building with macosx/GNUmakefile
----------------------------------------------------------
- Unpack the Tcl source release archive.
- The following instructions assume the Tcl source tree is named "tcl${ver}",
(where ${ver} is a shell variable containing the Tcl version number e.g. '9.0').
Setup this shell variable as follows:
ver="9.0"
- Setup environment variables as desired, for example:
CFLAGS="-arch x86_64 -arch arm64 -mmacosx-version-min=10.13"
export CFLAGS
- Change to the directory containing the Tcl source tree and build:
make -C tcl${ver}/macosx
|
| ︙ | ︙ |
Changes to macosx/Tcl-Info.plist.in.
1 2 3 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!-- | | | 1 2 3 4 5 6 7 8 9 10 11 | <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!-- Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net> See the file "license.terms" for information on usage and redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. --> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> |
| ︙ | ︙ |
Changes to macosx/tclMacOSXBundle.c.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 |
OpenResourceMap(
CFBundleRef bundleRef)
{
static int initialized = FALSE;
static short (*openresourcemap)(CFBundleRef) = NULL;
if (!initialized) {
| > | | | | | | > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
OpenResourceMap(
CFBundleRef bundleRef)
{
static int initialized = FALSE;
static short (*openresourcemap)(CFBundleRef) = NULL;
if (!initialized) {
{
openresourcemap = (short (*)(CFBundleRef))dlsym(RTLD_NEXT,
"CFBundleOpenBundleResourceMap");
#ifdef TCL_DEBUG_LOAD
if (!openresourcemap) {
const char *errMsg = dlerror();
TclLoadDbgMsg("dlsym() failed: %s", errMsg);
}
#endif /* TCL_DEBUG_LOAD */
}
initialized = TRUE;
}
if (openresourcemap) {
return openresourcemap(bundleRef);
}
return -1;
|
| ︙ | ︙ | |||
186 187 188 189 190 191 192 |
*/
CFURLGetFileSystemRepresentation(libURL, TRUE,
(unsigned char *) libraryPath, maxPathLen);
CFRelease(libURL);
}
if (versionedBundleRef) {
| > | > | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
*/
CFURLGetFileSystemRepresentation(libURL, TRUE,
(unsigned char *) libraryPath, maxPathLen);
CFRelease(libURL);
}
if (versionedBundleRef) {
{
CFRelease(versionedBundleRef);
}
}
}
if (libraryPath[0]) {
return TCL_OK;
}
#endif /* HAVE_COREFOUNDATION */
|
| ︙ | ︙ |
Changes to macosx/tclMacOSXFCmd.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | /* Darwin 8 copyfile API. */ #ifdef HAVE_COPYFILE #ifdef HAVE_COPYFILE_H #include <copyfile.h> #else /* HAVE_COPYFILE_H */ int copyfile(const char *from, const char *to, void *state, uint32_t flags); | < | | | < | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
/* Darwin 8 copyfile API. */
#ifdef HAVE_COPYFILE
#ifdef HAVE_COPYFILE_H
#include <copyfile.h>
#else /* HAVE_COPYFILE_H */
int copyfile(const char *from, const char *to,
void *state, uint32_t flags);
#define COPYFILE_ACL (1<<0)
#define COPYFILE_XATTR (1<<2)
#define COPYFILE_NOFOLLOW_SRC (1<<18)
#endif /* HAVE_COPYFILE_H */
#endif /* HAVE_COPYFILE */
#ifdef WEAK_IMPORT_COPYFILE
#define MayUseCopyFile() (copyfile != NULL)
#elif defined(HAVE_COPYFILE)
#define MayUseCopyFile() (1)
#else
#define MayUseCopyFile() (0)
#endif
#include <libkern/OSByteOrder.h>
/*
* Constants for file attributes subcommand. Need to be kept in sync with
* tclUnixFCmd.c !
*/
enum {
UNIX_GROUP_ATTRIBUTE,
UNIX_OWNER_ATTRIBUTE,
UNIX_PERMISSIONS_ATTRIBUTE,
#ifdef HAVE_CHFLAGS
UNIX_READONLY_ATTRIBUTE,
#endif
#ifdef MAC_OSX_TCL
|
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
static int GetOSTypeFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, OSType *osTypePtr);
static Tcl_Obj * NewOSTypeObj(const OSType newOSType);
static int SetOSTypeFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void UpdateStringOfOSType(Tcl_Obj *objPtr);
static const Tcl_ObjType tclOSTypeType = {
| | | | | | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
static int GetOSTypeFromObj(Tcl_Interp *interp,
Tcl_Obj *objPtr, OSType *osTypePtr);
static Tcl_Obj * NewOSTypeObj(const OSType newOSType);
static int SetOSTypeFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
static void UpdateStringOfOSType(Tcl_Obj *objPtr);
static const Tcl_ObjType tclOSTypeType = {
"osType", /* name */
NULL, /* freeIntRepProc */
NULL, /* dupIntRepProc */
UpdateStringOfOSType, /* updateStringProc */
SetOSTypeFromAny, /* setFromAnyProc */
TCL_OBJTYPE_V0
};
enum {
kIsInvisible = 0x4000,
};
#define kFinfoIsInvisible (OSSwapHostToBigConstInt16(kIsInvisible))
typedef struct finderinfo {
u_int32_t type;
u_int32_t creator;
u_int16_t fdFlags;
u_int32_t location;
u_int16_t reserved;
u_int32_t extendedFileInfo[4];
} __attribute__ ((__packed__)) finderinfo;
|
| ︙ | ︙ | |||
118 119 120 121 122 123 124 | * A new object is allocated. * *---------------------------------------------------------------------- */ int TclMacOSXGetFileAttribute( | | | | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
* A new object is allocated.
*
*----------------------------------------------------------------------
*/
int
TclMacOSXGetFileAttribute(
Tcl_Interp *interp, /* The interp we are using for errors. */
int objIndex, /* The index of the attribute. */
Tcl_Obj *fileName, /* The name of the file (UTF-8). */
Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */
{
#ifdef HAVE_GETATTRLIST
int result;
Tcl_StatBuf statBuf;
struct attrlist alist;
fileinfobuf finfo;
finderinfo *finder = (finderinfo *) &finfo.data;
|
| ︙ | ︙ | |||
634 635 636 637 638 639 640 |
const char *string;
int result = TCL_OK;
Tcl_DString ds;
Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman");
Tcl_Size length;
string = TclGetStringFromObj(objPtr, &length);
| | < | | | | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
const char *string;
int result = TCL_OK;
Tcl_DString ds;
Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman");
Tcl_Size length;
string = TclGetStringFromObj(objPtr, &length);
Tcl_UtfToExternalDStringEx(NULL, encoding, string, length, TCL_ENCODING_PROFILE_TCL8, &ds, NULL);
if (Tcl_DStringLength(&ds) > 4) {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"expected Macintosh OS type but got \"%s\": ", string));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "MAC_OSTYPE", (char *)NULL);
}
result = TCL_ERROR;
} else {
OSType osType;
char bytes[4] = {'\0','\0','\0','\0'};
memcpy(bytes, Tcl_DStringValue(&ds), Tcl_DStringLength(&ds));
osType = (OSType) bytes[0] << 24 |
(OSType) bytes[1] << 16 |
(OSType) bytes[2] << 8 |
(OSType) bytes[3];
TclFreeInternalRep(objPtr);
objPtr->internalRep.wideValue = (Tcl_WideInt) osType;
objPtr->typePtr = &tclOSTypeType;
}
Tcl_DStringFree(&ds);
Tcl_FreeEncoding(encoding);
return result;
|
| ︙ | ︙ | |||
683 684 685 686 687 688 689 | * OSType-to-string conversion. * *---------------------------------------------------------------------- */ static void UpdateStringOfOSType( | | | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 |
* OSType-to-string conversion.
*
*----------------------------------------------------------------------
*/
static void
UpdateStringOfOSType(
Tcl_Obj *objPtr) /* OSType object whose string rep to
* update. */
{
const size_t size = TCL_UTF_MAX * 4;
char *dst = Tcl_InitStringRep(objPtr, NULL, size);
OSType osType = (OSType) objPtr->internalRep.wideValue;
int written = 0;
Tcl_Encoding encoding;
|
| ︙ | ︙ |
Changes to macosx/tclMacOSXNotify.c.
| ︙ | ︙ | |||
196 197 198 199 200 201 202 |
* select based implementation of the Tcl notifier. One of these structures is
* created for each thread that is using the notifier.
*/
typedef struct ThreadSpecificData {
FileHandler *firstFileHandlerPtr;
/* Pointer to head of file handler list. */
| | | | | | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
* select based implementation of the Tcl notifier. One of these structures is
* created for each thread that is using the notifier.
*/
typedef struct ThreadSpecificData {
FileHandler *firstFileHandlerPtr;
/* Pointer to head of file handler list. */
int polled; /* True if the notifier thread has polled for
* this thread. */
int sleeping; /* True if runloop is inside Tcl_Sleep. */
int runLoopSourcePerformed; /* True after the runLoopSource callack was
* performed. */
int runLoopRunning; /* True if this thread's Tcl runLoop is
* running. */
int runLoopNestingLevel; /* Level of nested runLoop invocations. */
/* Must hold the notifierLock before accessing the following fields: */
/* Start notifierLock section */
int onList; /* True if this thread is on the
* waitingList */
struct ThreadSpecificData *nextPtr, *prevPtr;
/* All threads that are currently waiting on
* an event have their ThreadSpecificData
* structure on a doubly-linked listed formed
* from these pointers. */
/* End notifierLock section */
|
| ︙ | ︙ | |||
235 236 237 238 239 240 241 |
* to Tcl_CreateFileHandler. */
SelectMasks readyMasks; /* This array reflects the readable/writable
* conditions that were found to exist by the
* last call to select. */
int numFdBits; /* Number of valid bits in checkMasks (one
* more than highest fd for which
* Tcl_WatchFile has been called). */
| | > > > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
* to Tcl_CreateFileHandler. */
SelectMasks readyMasks; /* This array reflects the readable/writable
* conditions that were found to exist by the
* last call to select. */
int numFdBits; /* Number of valid bits in checkMasks (one
* more than highest fd for which
* Tcl_WatchFile has been called). */
int polling; /* True if this thread is polling for
* events. */
CFRunLoopRef runLoop; /* This thread's CFRunLoop, needs to be woken
* up whenever the runLoopSource is
* signaled. */
CFRunLoopSourceRef runLoopSource;
/* Any other thread alerts a notifier that an
* event is ready to be processed by signaling
* this CFRunLoopSource. */
CFRunLoopObserverRef runLoopObserver, runLoopObserverTcl;
/* Adds/removes this thread from waitingList
* when the CFRunLoop starts/stops. */
CFRunLoopTimerRef runLoopTimer;
/* Wakes up CFRunLoop after given timeout when
* running embedded. */
/* End tsdLock section */
CFTimeInterval waitTime; /* runLoopTimer wait time when running
* embedded. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
* The following static indicates the number of threads that have initialized
* notifiers.
|
| ︙ | ︙ | |||
297 298 299 300 301 302 303 | /* * The following static indicates if the notifier thread is running. * * You must hold the notifierInitLock before accessing this variable. */ | | | | | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | /* * The following static indicates if the notifier thread is running. * * You must hold the notifierInitLock before accessing this variable. */ static int notifierThreadRunning; /* * The following static flag indicates that async handlers are pending. */ #if TCL_THREADS static int asyncPending = 0; #endif /* * Signal mask information for notifier thread. */ static sigset_t notifierSigMask; static sigset_t allSigMask; /* * This is the thread ID of the notifier thread that does select. Only valid * when notifierThreadRunning is non-zero. * * You must hold the notifierInitLock before accessing this variable. */ static pthread_t notifierThread; /* |
| ︙ | ︙ | |||
354 355 356 357 358 359 360 | static TCL_NORETURN void NotifierThreadProc(void *clientData); static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); static void TimerWakeUp(CFRunLoopTimerRef timer, void *info); static void QueueFileEvents(void *info); static void UpdateWaitingListAndServiceEvents( CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); | | | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | static TCL_NORETURN void NotifierThreadProc(void *clientData); static int FileHandlerEventProc(Tcl_Event *evPtr, int flags); static void TimerWakeUp(CFRunLoopTimerRef timer, void *info); static void QueueFileEvents(void *info); static void UpdateWaitingListAndServiceEvents( CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); static int OnOffWaitingList(ThreadSpecificData *tsdPtr, int onList, int signalNotifier); #ifdef HAVE_PTHREAD_ATFORK static int atForkInit = 0; static void AtForkPrepare(void); static void AtForkParent(void); static void AtForkChild(void); |
| ︙ | ︙ | |||
511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
tclEventsOnlyRunLoopMode);
tsdPtr->runLoop = runLoop;
tsdPtr->runLoopSource = runLoopSource;
tsdPtr->runLoopObserver = runLoopObserver;
tsdPtr->runLoopObserverTcl = runLoopObserverTcl;
tsdPtr->runLoopTimer = NULL;
#if defined(USE_OS_UNFAIR_LOCK)
tsdPtr->tsdLock = OS_UNFAIR_LOCK_INIT;
#else
tsdPtr->tsdLock = SPINLOCK_INIT;
#endif
}
| > | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
tclEventsOnlyRunLoopMode);
tsdPtr->runLoop = runLoop;
tsdPtr->runLoopSource = runLoopSource;
tsdPtr->runLoopObserver = runLoopObserver;
tsdPtr->runLoopObserverTcl = runLoopObserverTcl;
tsdPtr->runLoopTimer = NULL;
tsdPtr->waitTime = CF_TIMEINTERVAL_FOREVER;
#if defined(USE_OS_UNFAIR_LOCK)
tsdPtr->tsdLock = OS_UNFAIR_LOCK_INIT;
#else
tsdPtr->tsdLock = SPINLOCK_INIT;
#endif
}
|
| ︙ | ︙ | |||
562 563 564 565 566 567 568 | "could not make trigger pipe non-blocking"); } receivePipe = fds[0]; triggerPipe = fds[1]; /* | | | | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
"could not make trigger pipe non-blocking");
}
receivePipe = fds[0];
triggerPipe = fds[1];
/*
* Create notifier thread lazily in Tcl_WaitForEvent() to avoid
* interfering with fork() followed immediately by execve() (we cannot
* execve() when more than one thread is present).
*/
notifierThreadRunning = 0;
}
notifierCount++;
UNLOCK_NOTIFIER_INIT;
return tsdPtr;
}
/*
|
| ︙ | ︙ | |||
653 654 655 656 657 658 659 |
pthread_attr_setstacksize(&attr, 60 * 1024);
result = pthread_create(¬ifierThread, &attr,
(void * (*)(void *))(void *)NotifierThreadProc, NULL);
pthread_attr_destroy(&attr);
if (result) {
Tcl_Panic("StartNotifierThread: unable to start notifier thread");
}
| | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 |
pthread_attr_setstacksize(&attr, 60 * 1024);
result = pthread_create(¬ifierThread, &attr,
(void * (*)(void *))(void *)NotifierThreadProc, NULL);
pthread_attr_destroy(&attr);
if (result) {
Tcl_Panic("StartNotifierThread: unable to start notifier thread");
}
notifierThreadRunning = 1;
/*
* Restore original signal mask.
*/
pthread_sigmask(SIG_SETMASK, ¬ifierSigMask, NULL);
}
|
| ︙ | ︙ | |||
719 720 721 722 723 724 725 |
if (notifierThreadRunning) {
int result = pthread_join(notifierThread, NULL);
if (result) {
Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier "
"thread");
}
| | | | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 |
if (notifierThreadRunning) {
int result = pthread_join(notifierThread, NULL);
if (result) {
Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier "
"thread");
}
notifierThreadRunning = 0;
/*
* If async marks are outstanding, perform actions now.
*/
if (asyncPending) {
asyncPending = 0;
TclAsyncMarkFromNotifier();
}
}
close(receivePipe);
triggerPipe = -1;
}
|
| ︙ | ︙ | |||
814 815 816 817 818 819 820 | * Replaces any previous timer. * *---------------------------------------------------------------------- */ void TclpSetTimer( | | | > | > > | > | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 |
* Replaces any previous timer.
*
*----------------------------------------------------------------------
*/
void
TclpSetTimer(
const Tcl_Time *timePtr) /* Timeout value, may be NULL. */
{
ThreadSpecificData *tsdPtr;
CFRunLoopTimerRef runLoopTimer;
CFTimeInterval waitTime;
tsdPtr = TCL_TSD_INIT(&dataKey);
runLoopTimer = tsdPtr->runLoopTimer;
if (!runLoopTimer) {
return;
}
if (timePtr) {
Tcl_Time vTime = *timePtr;
if (vTime.sec != 0 || vTime.usec != 0) {
TclScaleTime(&vTime);
waitTime = vTime.sec + 1.0e-6 * vTime.usec;
} else {
waitTime = 0;
}
} else {
waitTime = CF_TIMEINTERVAL_FOREVER;
}
tsdPtr->waitTime = waitTime;
CFRunLoopTimerSetNextFireDate(runLoopTimer,
CFAbsoluteTimeGetCurrent() + waitTime);
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
884 885 886 887 888 889 890 |
void
TclpServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
| | | 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 |
void
TclpServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (mode == TCL_SERVICE_ALL && !tsdPtr->runLoopTimer) {
if (!tsdPtr->runLoop) {
Tcl_Panic("Tcl_ServiceModeHook: Notifier not initialized");
}
tsdPtr->runLoopTimer = CFRunLoopTimerCreate(NULL,
CFAbsoluteTimeGetCurrent() + CF_TIMEINTERVAL_FOREVER,
CF_TIMEINTERVAL_FOREVER, 0, 0, TimerWakeUp, NULL);
if (tsdPtr->runLoopTimer) {
|
| ︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 | * None. * *---------------------------------------------------------------------- */ int TclpWaitForEvent( | | < | | | | > | > > > > > | > > > | | | | | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
* None.
*
*----------------------------------------------------------------------
*/
int
TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
int result, polling, runLoopRunning;
CFTimeInterval waitTime;
SInt32 runLoopStatus;
ThreadSpecificData *tsdPtr;
result = -1;
polling = 0;
waitTime = CF_TIMEINTERVAL_FOREVER;
tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->runLoop) {
Tcl_Panic("Tcl_WaitForEvent: Notifier not initialized");
}
/*
* A NULL timePtr means wait forever.
*/
if (timePtr) {
Tcl_Time vTime = *timePtr;
/*
* TIP #233 (Virtualized Time). Is virtual time in effect? And do we
* actually have something to scale? If yes to both then we call the
* handler to do this scaling.
*/
if (vTime.sec != 0 || vTime.usec != 0) {
TclScaleTime(&vTime);
waitTime = vTime.sec + 1.0e-6 * vTime.usec;
} else {
/*
* The max block time was set to 0.
*
* If we set the waitTime to 0, then the call to CFRunLoopInMode
* may return without processing all of its sources. The Apple
* documentation says that if the waitTime is 0 "only one pass is
* made through the run loop before returning; if multiple sources
* or timers are ready to fire immediately, only one (possibly two
* if one is a version 0 source) will be fired, regardless of the
* value of returnAfterSourceHandled." This can cause some chanio
* tests to fail. So we use a small positive waitTime unless
* there is another RunLoop running.
*/
polling = 1;
waitTime = tsdPtr->runLoopRunning ? 0 : 0.0001;
}
}
StartNotifierThread();
LOCK_NOTIFIER_TSD;
tsdPtr->polling = polling;
UNLOCK_NOTIFIER_TSD;
tsdPtr->runLoopSourcePerformed = 0;
/*
* If the Tcl runloop is already running (e.g. if Tcl_WaitForEvent was
* called recursively) start a new runloop in a custom runloop mode
* containing only the source for the notifier thread. Otherwise wakeups
* from other sources added to the common runloop mode might get lost or
* 3rd party event handlers might get called when they do not expect to
* be.
*/
runLoopRunning = tsdPtr->runLoopRunning;
tsdPtr->runLoopRunning = 1;
runLoopStatus = CFRunLoopRunInMode(
runLoopRunning ? tclEventsOnlyRunLoopMode : kCFRunLoopDefaultMode,
waitTime, TRUE);
tsdPtr->runLoopRunning = runLoopRunning;
LOCK_NOTIFIER_TSD;
tsdPtr->polling = 0;
UNLOCK_NOTIFIER_TSD;
switch (runLoopStatus) {
case kCFRunLoopRunFinished:
Tcl_Panic("Tcl_WaitForEvent: CFRunLoop finished");
break;
case kCFRunLoopRunTimedOut:
QueueFileEvents(tsdPtr);
|
| ︙ | ︙ | |||
1294 1295 1296 1297 1298 1299 1300 |
FD_COPY(&tsdPtr->readyMasks.readable, &readyMasks.readable);
FD_COPY(&tsdPtr->readyMasks.writable, &readyMasks.writable);
FD_COPY(&tsdPtr->readyMasks.exceptional, &readyMasks.exceptional);
FD_ZERO(&tsdPtr->readyMasks.readable);
FD_ZERO(&tsdPtr->readyMasks.writable);
FD_ZERO(&tsdPtr->readyMasks.exceptional);
UNLOCK_NOTIFIER_TSD;
| | | 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 |
FD_COPY(&tsdPtr->readyMasks.readable, &readyMasks.readable);
FD_COPY(&tsdPtr->readyMasks.writable, &readyMasks.writable);
FD_COPY(&tsdPtr->readyMasks.exceptional, &readyMasks.exceptional);
FD_ZERO(&tsdPtr->readyMasks.readable);
FD_ZERO(&tsdPtr->readyMasks.writable);
FD_ZERO(&tsdPtr->readyMasks.exceptional);
UNLOCK_NOTIFIER_TSD;
tsdPtr->runLoopSourcePerformed = 1;
for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
filePtr = filePtr->nextPtr) {
int mask = 0;
if (FD_ISSET(filePtr->fd, &readyMasks.readable)) {
mask |= TCL_READABLE;
|
| ︙ | ︙ | |||
1401 1402 1403 1404 1405 1406 1407 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | | | | | | | < | | | > > > > | | > | | | 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
OnOffWaitingList(
ThreadSpecificData *tsdPtr,
int onList,
int signalNotifier)
{
int changeWaitingList;
changeWaitingList = (!onList ^ !tsdPtr->onList);
if (changeWaitingList) {
if (onList) {
tsdPtr->nextPtr = waitingListPtr;
if (waitingListPtr) {
waitingListPtr->prevPtr = tsdPtr;
}
tsdPtr->prevPtr = NULL;
waitingListPtr = tsdPtr;
tsdPtr->onList = 1;
} else {
if (tsdPtr->prevPtr) {
tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
} else {
waitingListPtr = tsdPtr->nextPtr;
}
if (tsdPtr->nextPtr) {
tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
}
tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
tsdPtr->onList = 0;
}
if (signalNotifier) {
write(triggerPipe, "", 1);
}
}
return changeWaitingList;
}
/*
*----------------------------------------------------------------------
*
* Tcl_Sleep --
*
* Delay execution for the specified number of milliseconds.
*
* Results:
* None.
*
* Side effects:
* Time passes.
*
*----------------------------------------------------------------------
*/
void
Tcl_Sleep(
int ms) /* Number of milliseconds to sleep. */
{
Tcl_Time vdelay;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (ms <= 0) {
return;
}
/*
* TIP #233: Scale from virtual time to real-time.
*/
vdelay.sec = ms / 1000;
vdelay.usec = (ms % 1000) * 1000;
TclScaleTime(&vdelay);
if (tsdPtr->runLoop) {
CFTimeInterval waitTime;
CFRunLoopTimerRef runLoopTimer = tsdPtr->runLoopTimer;
CFAbsoluteTime nextTimerFire = 0, waitEnd, now;
SInt32 runLoopStatus;
waitTime = vdelay.sec + 1.0e-6 * vdelay.usec;
now = CFAbsoluteTimeGetCurrent();
waitEnd = now + waitTime;
if (runLoopTimer) {
nextTimerFire = CFRunLoopTimerGetNextFireDate(runLoopTimer);
if (nextTimerFire < waitEnd) {
CFRunLoopTimerSetNextFireDate(runLoopTimer, now +
CF_TIMEINTERVAL_FOREVER);
} else {
runLoopTimer = NULL;
}
}
tsdPtr->sleeping = 1;
do {
runLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
waitTime, FALSE);
switch (runLoopStatus) {
case kCFRunLoopRunFinished:
Tcl_Panic("Tcl_Sleep: CFRunLoop finished");
break;
case kCFRunLoopRunStopped:
waitTime = waitEnd - CFAbsoluteTimeGetCurrent();
break;
case kCFRunLoopRunTimedOut:
waitTime = 0;
break;
}
} while (waitTime > 0);
tsdPtr->sleeping = 0;
if (runLoopTimer) {
CFRunLoopTimerSetNextFireDate(runLoopTimer, nextTimerFire);
}
} else {
struct timespec waitTime;
waitTime.tv_sec = vdelay.sec;
|
| ︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 |
* TCL_EXCEPTION. */
int timeout) /* Maximum amount of time to wait for one of
* the conditions in mask to occur, in
* milliseconds. A value of 0 means don't wait
* at all, and a value of -1 means wait
* forever. */
{
| | | 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 |
* TCL_EXCEPTION. */
int timeout) /* Maximum amount of time to wait for one of
* the conditions in mask to occur, in
* milliseconds. A value of 0 means don't wait
* at all, and a value of -1 means wait
* forever. */
{
Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
struct timeval blockTime, *timeoutPtr;
int numFound, result = 0;
fd_set readableMask;
fd_set writableMask;
fd_set exceptionalMask;
#define SET_BITS(var, bits) ((var) |= (bits))
|
| ︙ | ︙ | |||
1582 1583 1584 1585 1586 1587 1588 |
/*
* If there is a non-zero finite timeout, compute the time when we give
* up.
*/
if (timeout > 0) {
| | > > > > | > | 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 |
/*
* If there is a non-zero finite timeout, compute the time when we give
* up.
*/
if (timeout > 0) {
Tcl_GetTime(&now);
abortTime.sec = now.sec + timeout/1000;
abortTime.usec = now.usec + (timeout%1000)*1000;
if (abortTime.usec >= 1000000) {
abortTime.usec -= 1000000;
abortTime.sec += 1;
}
timeoutPtr = &blockTime;
} else if (timeout == 0) {
timeoutPtr = &blockTime;
blockTime.tv_sec = 0;
blockTime.tv_usec = 0;
} else {
timeoutPtr = NULL;
|
| ︙ | ︙ | |||
1608 1609 1610 1611 1612 1613 1614 |
/*
* Loop in a mini-event loop of our own, waiting for either the file to
* become ready or a timeout to occur.
*/
while (1) {
if (timeout > 0) {
| | > > | | > | | 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 |
/*
* Loop in a mini-event loop of our own, waiting for either the file to
* become ready or a timeout to occur.
*/
while (1) {
if (timeout > 0) {
blockTime.tv_sec = abortTime.sec - now.sec;
blockTime.tv_usec = abortTime.usec - now.usec;
if (blockTime.tv_usec < 0) {
blockTime.tv_sec -= 1;
blockTime.tv_usec += 1000000;
}
if (blockTime.tv_sec < 0) {
blockTime.tv_sec = 0;
blockTime.tv_usec = 0;
}
}
/*
* Setup the select masks for the fd.
|
| ︙ | ︙ | |||
1663 1664 1665 1666 1667 1668 1669 | continue; } /* * The select returned early, so we need to recompute the timeout. */ | | | > | 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 |
continue;
}
/*
* The select returned early, so we need to recompute the timeout.
*/
Tcl_GetTime(&now);
if ((abortTime.sec < now.sec)
|| (abortTime.sec==now.sec && abortTime.usec<=now.usec)) {
break;
}
}
return result;
}
/*
|
| ︙ | ︙ | |||
1689 1690 1691 1692 1693 1694 1695 | * Side effetcs: * The trigger pipe is written when called from the notifier * thread. * *---------------------------------------------------------------------- */ | < > | | | | | | | | 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 |
* Side effetcs:
* The trigger pipe is written when called from the notifier
* thread.
*
*----------------------------------------------------------------------
*/
int
TclAsyncNotifier(
int sigNumber, /* Signal number. */
TCL_UNUSED(Tcl_ThreadId), /* Target thread. */
TCL_UNUSED(void *), /* Notifier data. */
int *flagPtr, /* Flag to mark. */
int value) /* Value of mark. */
{
#if TCL_THREADS
/*
* WARNING:
* This code most likely runs in a signal handler. Thus,
* only few async-signal-safe system calls are allowed,
* e.g. pthread_self(), sem_post(), write().
*/
if (pthread_equal(pthread_self(), (pthread_t) notifierThread)) {
if (notifierThreadRunning) {
*flagPtr = value;
if (!asyncPending) {
asyncPending = 1;
write(triggerPipe, "S", 1);
}
return 1;
}
return 0;
}
/*
* Re-send the signal to the notifier thread.
*/
pthread_kill((pthread_t) notifierThread, sigNumber);
#endif
return 0;
}
/*
*----------------------------------------------------------------------
*
* NotifierThreadProc --
*
|
| ︙ | ︙ | |||
1756 1757 1758 1759 1760 1761 1762 |
static TCL_NORETURN void
NotifierThreadProc(
TCL_UNUSED(void *))
{
ThreadSpecificData *tsdPtr;
fd_set readableMask, writableMask, exceptionalMask;
| | < | 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 |
static TCL_NORETURN void
NotifierThreadProc(
TCL_UNUSED(void *))
{
ThreadSpecificData *tsdPtr;
fd_set readableMask, writableMask, exceptionalMask;
int i, ret, numFdBits = 0, polling;
struct timeval poll = {0., 0.}, *timePtr;
char buf[2];
/*
* Look for file events and report them to interested threads.
*/
|
| ︙ | ︙ | |||
1816 1817 1818 1819 1820 1821 1822 | /* * Signals are unblocked only during select(). */ pthread_sigmask(SIG_SETMASK, ¬ifierSigMask, NULL); ret = select(numFdBits, &readableMask, &writableMask, &exceptionalMask, | | | | | 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 |
/*
* Signals are unblocked only during select().
*/
pthread_sigmask(SIG_SETMASK, ¬ifierSigMask, NULL);
ret = select(numFdBits, &readableMask, &writableMask, &exceptionalMask,
timePtr);
pthread_sigmask(SIG_BLOCK, &allSigMask, NULL);
if (ret == -1) {
/*
* In case a signal was caught during select(),
* perform work on async handlers now.
*/
if (errno == EINTR && asyncPending) {
asyncPending = 0;
TclAsyncMarkFromNotifier();
}
/*
* Try again immediately on an error.
*/
continue;
}
/*
* Alert any threads that are waiting on a ready file descriptor.
*/
LOCK_NOTIFIER;
for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
int found = 0;
SelectMasks readyMasks, checkMasks;
LOCK_NOTIFIER_TSD;
FD_COPY(&tsdPtr->checkMasks.readable, &checkMasks.readable);
FD_COPY(&tsdPtr->checkMasks.writable, &checkMasks.writable);
FD_COPY(&tsdPtr->checkMasks.exceptional, &checkMasks.exceptional);
UNLOCK_NOTIFIER_TSD;
|
| ︙ | ︙ | |||
1889 1890 1891 1892 1893 1894 1895 | LOCK_NOTIFIER_TSD; FD_COPY(&readyMasks.readable, &tsdPtr->readyMasks.readable); FD_COPY(&readyMasks.writable, &tsdPtr->readyMasks.writable); FD_COPY(&readyMasks.exceptional, &tsdPtr->readyMasks.exceptional); UNLOCK_NOTIFIER_TSD; | | | 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 |
LOCK_NOTIFIER_TSD;
FD_COPY(&readyMasks.readable, &tsdPtr->readyMasks.readable);
FD_COPY(&readyMasks.writable, &tsdPtr->readyMasks.writable);
FD_COPY(&readyMasks.exceptional,
&tsdPtr->readyMasks.exceptional);
UNLOCK_NOTIFIER_TSD;
tsdPtr->polled = 0;
if (tsdPtr->runLoop) {
CFRunLoopSourceSignal(tsdPtr->runLoopSource);
CFRunLoopWakeUp(tsdPtr->runLoop);
}
}
}
UNLOCK_NOTIFIER;
|
| ︙ | ︙ | |||
1918 1919 1920 1921 1922 1923 1924 |
* pipe so we need to shut down the notifier thread.
*/
break;
}
if (asyncPending) {
| | | 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 |
* pipe so we need to shut down the notifier thread.
*/
break;
}
if (asyncPending) {
asyncPending = 0;
TclAsyncMarkFromNotifier();
}
}
}
pthread_exit(0);
}
|
| ︙ | ︙ | |||
2016 2017 2018 2019 2020 2021 2022 |
tsdPtr->tsdLock = OS_UNFAIR_LOCK_INIT;
#else
UNLOCK_NOTIFIER_TSD;
UNLOCK_NOTIFIER;
UNLOCK_NOTIFIER_INIT;
#endif
| | | | 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 |
tsdPtr->tsdLock = OS_UNFAIR_LOCK_INIT;
#else
UNLOCK_NOTIFIER_TSD;
UNLOCK_NOTIFIER;
UNLOCK_NOTIFIER_INIT;
#endif
asyncPending = 0;
if (tsdPtr->runLoop) {
tsdPtr->runLoop = NULL;
tsdPtr->runLoopSource = NULL;
tsdPtr->runLoopTimer = NULL;
}
if (notifierCount > 0) {
notifierCount = 1;
notifierThreadRunning = 0;
/*
* Restart the notifier thread for signal handling.
*/
StartNotifierThread();
}
|
| ︙ | ︙ |
Changes to tests-perf/chan.perf.tcl.
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/tclsh # ------------------------------------------------------------------------ # # chan.perf.tcl -- # # This file provides performance tests for comparison of tcl-speed # of channel subsystem. # # ------------------------------------------------------------------------ # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/usr/bin/tclsh
# ------------------------------------------------------------------------
#
# chan.perf.tcl --
#
# This file provides performance tests for comparison of tcl-speed
# of channel subsystem.
#
# ------------------------------------------------------------------------
#
# Copyright (c) 2024 Serg G. Brester (aka sebres)
#
# See the file "license.terms" for information on usage and redistribution
# of this file.
#
if {![namespace exists ::tclTestPerf]} {
source [file join [file dirname [info script]] test-performance.tcl]
|
| ︙ | ︙ |
Changes to tests-perf/file.perf.tcl.
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/tclsh # ------------------------------------------------------------------------ # # file.perf.tcl -- # # This file provides performance tests for comparison of tcl-speed # of file commands and subsystem. # # ------------------------------------------------------------------------ # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/usr/bin/tclsh
# ------------------------------------------------------------------------
#
# file.perf.tcl --
#
# This file provides performance tests for comparison of tcl-speed
# of file commands and subsystem.
#
# ------------------------------------------------------------------------
#
# Copyright (c) 2024 Serg G. Brester (aka sebres)
#
# See the file "license.terms" for information on usage and redistribution
# of this file.
#
if {![namespace exists ::tclTestPerf]} {
source -encoding utf-8 [file join [file dirname [info script]] test-performance.tcl]
|
| ︙ | ︙ |
Changes to tests-perf/list.perf.tcl.
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/tclsh # ------------------------------------------------------------------------ # # list.perf.tcl -- # # This file provides performance tests for comparison of tcl-speed # of list facilities. # # ------------------------------------------------------------------------ # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/usr/bin/tclsh
# ------------------------------------------------------------------------
#
# list.perf.tcl --
#
# This file provides performance tests for comparison of tcl-speed
# of list facilities.
#
# ------------------------------------------------------------------------
#
# Copyright (c) 2024 Serg G. Brester (aka sebres)
#
# See the file "license.terms" for information on usage and redistribution
# of this file.
#
if {![namespace exists ::tclTestPerf]} {
source [file join [file dirname [info script]] test-performance.tcl]
|
| ︙ | ︙ |
Changes to tests/aaa_exit.test.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 |
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
| < < < < | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
foreach {fin_on_exit testname} {0 {normal, quick exit} 1 {full-finalized exit}} {
test exit-1.[expr {$fin_on_exit+1}] $testname -setup {
set tout [expr {1000 + [::tcl::pkgconfig get mem_debug] * 5000}]
set tout [after $tout [list set done "Exit hangs (timeout) !!!"]]
set f {}
} -body {
set f [open [list | [interpreter] << "set ::env(TCL_FINALIZE_ON_EXIT) $fin_on_exit; exit"] r]
fileevent $f readable [namespace code {after cancel $tout; set done OK}]
vwait done
|
| ︙ | ︙ |
Changes to tests/abstractlist.test.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
::tcltest::loadTestedCommands
package require -exact tcl::test [info patchlevel]
}
testConstraint testevalex [llength [info commands testevalex]]
testConstraint testobj [llength [info commands testobj]]
testConstraint lstring [llength [info commands lstring]]
| | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
::tcltest::loadTestedCommands
package require -exact tcl::test [info patchlevel]
}
testConstraint testevalex [llength [info commands testevalex]]
testConstraint testobj [llength [info commands testobj]]
testConstraint lstring [llength [info commands lstring]]
testConstraint lgen [llength [info commands lgegenn]]
set abstractlisttestvars [info var *]
proc value-cmp {vara varb} {
upvar $vara a
upvar $varb b
set ta [tcl::unsupported::representation $a]
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 |
lappend il [llength $l]
set start 0
set words [lmap i $il {
set w [join [lrange $l $start $i-1] {} ]
set start [expr {$i+1}]
set w
}]
| | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
lappend il [llength $l]
set start 0
set words [lmap i $il {
set w [join [lrange $l $start $i-1] {} ]
set start [expr {$i+1}]
set w
}]
set l-isa3 [testobj objtype $l]; # lrange defaults to list behavior
list ${l-isa} $il ${l-isa2} ${l-isa3} $words
} {lstring {2 6 10 15 20 25 30 34 40 44 48 55 62 66 74 77 80 85} lstring list {If you can keep your head when all about you Are losing theirs and blaming it on you,}}
test abstractlist-3.4 {no shimmer foreach} {testobj lstring} {
set l [lstring -not SLICE $str]
set l-isa [testobj objtype $l]
set word {}
set words {}
foreach c $l {
|
| ︙ | ︙ | |||
303 304 305 306 307 308 309 |
set i-isa2 [testobj objtype $i]
lappend res $p ${p-isa} $i ${i-isa2}
} {lstring {I f { } y o u { } c a n { } t r u s t { } y o u r s e l f { } w h e n { } a l l { } w o m e n { } d o u b t { } y o u , { } B u t { } m a k e { } a l l o w a n c e { } f o r { } t h e i r { } d o u b t i n g , { } t o o .} lstring l none {I f { } y o u { } c a n { } t r u s t { } y o u r s e f { } w h e n { } a l l { } w o m e n { } d o u b t { } y o u , { } B u t { } m a k e { } a l l o w a n c e { } f o r { } t h e i r { } d o u b t i n g , { } t o o .} lstring}
test abstractlist-3.8 {shimmer lassign} {testobj lstring} {
set l [lstring -not SLICE Inconceivable]
set l-isa [testobj objtype $l]
| | | | 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
set i-isa2 [testobj objtype $i]
lappend res $p ${p-isa} $i ${i-isa2}
} {lstring {I f { } y o u { } c a n { } t r u s t { } y o u r s e l f { } w h e n { } a l l { } w o m e n { } d o u b t { } y o u , { } B u t { } m a k e { } a l l o w a n c e { } f o r { } t h e i r { } d o u b t i n g , { } t o o .} lstring l none {I f { } y o u { } c a n { } t r u s t { } y o u r s e f { } w h e n { } a l l { } w o m e n { } d o u b t { } y o u , { } B u t { } m a k e { } a l l o w a n c e { } f o r { } t h e i r { } d o u b t i n g , { } t o o .} lstring}
test abstractlist-3.8 {shimmer lassign} {testobj lstring} {
set l [lstring -not SLICE Inconceivable]
set l-isa [testobj objtype $l]
set l2 [lassign $l i n c] ;# must be using lrange internally
set l-isa2 [testobj objtype $l]
set l2-isa [testobj objtype $l2]
list $l ${l-isa} $l2 ${l-isa2} ${l2-isa}
} {{I n c o n c e i v a b l e} lstring {o n c e i v a b l e} list list}
test abstractlist-3.9 {no shimmer lremove} {testobj lstring} {
set l [lstring -not SLICE Inconceivable]
set l-isa [testobj objtype $l]
set l2 [lremove $l 0 1]
set l-isa2 [testobj objtype $l]
set l2-isa [testobj objtype $l2]
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 |
#
# Test fix for bug in TEBC for STR CONCAT, and LIST INDEX
# instructions.
# This example abstract list (lgen) causes a rescursive call in TEBC,
# stack management was not included for these instructions in TEBC.
#
test abstractlist-lgen-bug {bug in str concat and list operations} -constraints lgen -setup {
| > | | | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 |
#
# Test fix for bug in TEBC for STR CONCAT, and LIST INDEX
# instructions.
# This example abstract list (lgen) causes a rescursive call in TEBC,
# stack management was not included for these instructions in TEBC.
#
test abstractlist-lgen-bug {bug in str concat and list operations} -constraints lgen -setup {
set lgenfile [makeFile {
# Test TIP 192 - Lazy Lists
set res {}
set cntr 0
# Fatal error here when [source]'d -- It is a refcounting problem...
lappend res Index*2:[lgen 1 expr 2* ]:--
set x [lseq 17]
set y [lgen 17 apply {{index} {expr {$index * 6}}}] ;# expr * 6
|
| ︙ | ︙ | |||
572 573 574 575 576 577 578 |
lappend res Good-Bye!
set res
} source.file]
} -body {
set tcl_traceExec 0
set tcl_traceCompile 0
set f $lgenfile
| > | > | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 |
lappend res Good-Bye!
set res
} source.file]
} -body {
set tcl_traceExec 0
set tcl_traceCompile 0
set f $lgenfile
#set script [format "puts ====-%s-====\nsource %s\nputs ====-done-====\n" $f $f]
set script [format "source %s" $f]
#puts stderr "eval $script"
eval $script
} -cleanup {
removeFile source.file
unset res
} -result {Index*2:0:-- {0 -> 0} {1 -> 6} {2 -> 12} {3 -> 18} {4 -> 24} {5 -> 30} {6 -> 36} {7 -> 42} {8 -> 48} {9 -> 54} {10 -> 60} {11 -> 66} {12 -> 72} {13 -> 78} {14 -> 84} {15 -> 90} {16 -> 96} my_expr(3):3 {7 8 9 10 11 12 13 14 15 16 17 18 19 20 21} {s2:Index+7: {7 8 9 10 11 12 13 14 15 16 17 18 19 20 21} :--} {foo:Index-8: {-8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6} :--} 9len=15 9(3)=10 {bar:Index+7: {7 8 9 10 11 12 13 14 15 16 17 18 19 20 21} :--} {Index+7:7 8 9 10 11 12 13 14 15 16 17 18 19 20 21:--} {Index+7:7 8 9 10 11 12 13 14 15 16 17 18 19 20 21:--} {fib:0 1 1 2 3} {First 20 fibbinacci:0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181} {First 20 fibbinacci from x :0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181} Good-Bye!}
test abstractlist-lgen-bug2 {bug in foreach} -constraints lgen -body {
|
| ︙ | ︙ |
Changes to tests/apply.test.
| ︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
test apply-3.2 {non-existing namespace} -body {
namespace eval ::NONEXIST::FOR::SURE {}
set lambda [list x {set x 1} ::NONEXIST::FOR::SURE]
apply $lambda x
namespace delete ::NONEXIST
apply $lambda x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}
test apply-3.3 {non-existing namespace} -body {
apply [list x {set x 1} NONEXIST::FOR::SURE] x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}
test apply-3.4 {non-existing namespace} -body {
namespace eval ::NONEXIST::FOR::SURE {}
set lambda [list x {set x 1} NONEXIST::FOR::SURE]
apply $lambda x
| > > > > > > > > > > > > > | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
test apply-3.2 {non-existing namespace} -body {
namespace eval ::NONEXIST::FOR::SURE {}
set lambda [list x {set x 1} ::NONEXIST::FOR::SURE]
apply $lambda x
namespace delete ::NONEXIST
apply $lambda x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}
test apply-3.2.2 {non-existing namespace (recreated between apply-calls)} -body {
set res {}
namespace eval ::NONEXIST::FOR::SURE {}
set lambda {{step} {variable x; lappend x $step} ::NONEXIST::FOR::SURE}
lappend res [catch { apply $lambda A} x] $x
namespace delete ::NONEXIST
lappend res [catch { apply $lambda B} x] $x
namespace eval ::NONEXIST::FOR::SURE {}
lappend res [catch { apply $lambda C} x] $x
set res
} -cleanup {
namespace delete ::NONEXIST
} -result {0 A 1 {namespace "::NONEXIST::FOR::SURE" not found} 0 C}
test apply-3.3 {non-existing namespace} -body {
apply [list x {set x 1} NONEXIST::FOR::SURE] x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}
test apply-3.4 {non-existing namespace} -body {
namespace eval ::NONEXIST::FOR::SURE {}
set lambda [list x {set x 1} NONEXIST::FOR::SURE]
apply $lambda x
|
| ︙ | ︙ | |||
305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
set end [getbytes]
}
set leakedBytes [expr {$end - $tmp}]
} -cleanup {
rename getbytes {}
unset -nocomplain end i x tmp leakedBytes
} -result 0
# Tests for specific bugs
test apply-10.1 {Test for precompiled bytecode body} -constraints {
applylambda
} -body {
testapplylambda
} -result 42
| > > > > > > > > > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
set end [getbytes]
}
set leakedBytes [expr {$end - $tmp}]
} -cleanup {
rename getbytes {}
unset -nocomplain end i x tmp leakedBytes
} -result 0
test apply-9.4 {lambda representation may shimmer during invocation} -setup {
set ::t {apply {n {
expr {[llength [lindex $::t 1 1 1]] + $n}
}} _}
} -body {
{*}[lset ::t end 123]
} -cleanup {
unset -nocomplain ::t
} -result {131}
# Tests for specific bugs
test apply-10.1 {Test for precompiled bytecode body} -constraints {
applylambda
} -body {
testapplylambda
} -result 42
|
| ︙ | ︙ |
Changes to tests/assemble.test.
| ︙ | ︙ | |||
1187 1188 1189 1190 1191 1192 1193 |
test assemble-10.7 {expr - noncompilable} {
-body {
list [catch {assemble {expr $x}} result] $result $::errorCode
}
-result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}}
}
| | | | 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 |
test assemble-10.7 {expr - noncompilable} {
-body {
list [catch {assemble {expr $x}} result] $result $::errorCode
}
-result {1 {assembly code may not contain substitutions} {TCL ASSEM NOSUBST}}
}
# assemble-11 - ASSEM_LVT4 (exist, existArray, dictAppend, dictLappend,
# nsupvar, variable, upvar)
test assemble-11.1 {exist - wrong # args} {
-body {
assemble {exist}
}
-returnCodes error
-match glob
|
| ︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 |
}
x
}
-result 123
-cleanup {namespace delete q; rename x {}}
}
| | | 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 |
}
x
}
-result 123
-cleanup {namespace delete q; rename x {}}
}
# assemble-12 - ASSEM_LVT1 (incr and incrArray)
test assemble-12.1 {incr - wrong # args} {
-body {
assemble {incr}
}
-returnCodes error
-match glob
|
| ︙ | ︙ | |||
1344 1345 1346 1347 1348 1349 1350 |
assemble {push b; push 3; incrArray a}
}
x
}
-result 8
-cleanup {rename x {}}
}
| > > > > > > | > > > > > > | | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 |
assemble {push b; push 3; incrArray a}
}
x
}
-result 8
-cleanup {rename x {}}
}
test assemble-12.6 {incr, stupid stack restriction} {
-body {
proc x {} "
[fillTables]
set y 5
assemble {push 3; incr y}
"
list [catch {x} result] $result $errorCode
}
-result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}}
-cleanup {unset result; rename x {}}
}
# assemble-13 -- ASSEM_LVT1_SINT1 - incrImm and incrArrayImm
test assemble-13.1 {incrImm - wrong # args} {
-body {
assemble {incrImm x}
}
-returnCodes error
-match glob
|
| ︙ | ︙ | |||
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 |
set a(b) 5
assemble {push b; incrArrayImm a 3}
}
x
}
-result 8
-cleanup {rename x {}}
}
# assemble-14 -- ASSEM_SINT1 (incrArrayStkImm and incrStkImm)
test assemble-14.1 {incrStkImm - wrong # args} {
-body {
assemble {incrStkImm}
| > > > > > > > > > > > > | 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 |
set a(b) 5
assemble {push b; incrArrayImm a 3}
}
x
}
-result 8
-cleanup {rename x {}}
}
test assemble-13.9 {incrImm, stupid stack restriction} {
-body {
proc x {} "
[fillTables]
set y 5
assemble {incrImm y 3}
"
list [catch {x} result] $result $errorCode
}
-result {1 {operand does not fit in one byte} {TCL ASSEM 1BYTE}}
-cleanup {unset result; rename x {}}
}
# assemble-14 -- ASSEM_SINT1 (incrArrayStkImm and incrStkImm)
test assemble-14.1 {incrStkImm - wrong # args} {
-body {
assemble {incrStkImm}
|
| ︙ | ︙ | |||
2343 2344 2345 2346 2347 2348 2349 |
x
}
-returnCodes error
-result {can't unset "a(b)": no such variable}
-cleanup {rename x {}}
}
| | | 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 |
x
}
-returnCodes error
-result {can't unset "a(b)": no such variable}
-cleanup {rename x {}}
}
# assemble-24 -- ASSEM_BOOL_LVT4 (unset; unsetArray)
test assemble-24.1 {unset - wrong # args} {
-body {
assemble {unset one}
}
-returnCodes error
-match glob
|
| ︙ | ︙ | |||
2872 2873 2874 2875 2876 2877 2878 |
list 2
}
} result] $result $::errorCode [split $::errorInfo \n]
}
x
}
-match glob
| | | 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 |
list 2
}
} result] $result $::errorCode [split $::errorInfo \n]
}
x
}
-match glob
-result {1 {"loadScalar1" instruction may not appear in a context where an exception has been caught and not disposed of.} {TCL ASSEM BADTHROW} {{"loadScalar1" instruction may not appear in a context where an exception has been caught and not disposed of.} { in assembly code between lines 10 and 15}*}}
-cleanup {rename x {}}
}
test assemble-30.5 {unclosed catch} {
-body {
proc x {} {
assemble {
beginCatch @error
|
| ︙ | ︙ | |||
3021 3022 3023 3024 3025 3026 3027 |
mult
pop
expon
}
} result] $result $::errorInfo
}
-result {1 {stack underflow} {stack underflow
| | | 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 |
mult
pop
expon
}
} result] $result $::errorInfo
}
-result {1 {stack underflow} {stack underflow
in assembly code between lines 1 and end of assembly code*}}
-match glob
-returnCodes ok
}
test assemble-40.2 {unbalanced stack} {*}{
-body {
list \
[catch {
|
| ︙ | ︙ |
Changes to tests/binary.test.
| ︙ | ︙ | |||
652 653 654 655 656 657 658 |
} \x00
test binary-17.2 {Tcl_BinaryObjCmd: format} {
binary format @5a2 "ab"
} \x00\x00\x00\x00\x00\x61\x62
test binary-17.3 {Tcl_BinaryObjCmd: format} {
binary format {a* @0 a2 @* a*} "foobar" "ab" "blat"
} abobarblat
| < < < | 652 653 654 655 656 657 658 659 660 661 662 663 664 665 |
} \x00
test binary-17.2 {Tcl_BinaryObjCmd: format} {
binary format @5a2 "ab"
} \x00\x00\x00\x00\x00\x61\x62
test binary-17.3 {Tcl_BinaryObjCmd: format} {
binary format {a* @0 a2 @* a*} "foobar" "ab" "blat"
} abobarblat
test binary-18.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body {
binary format u0a3 abc abd
} -result {bad field specifier "u"}
test binary-19.1 {Tcl_BinaryObjCmd: errors} -returnCodes error -body {
binary s
|
| ︙ | ︙ |
Changes to tests/chanio.test.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
| < < < < > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
testConstraint noappverifier [expr {
[llength [info commands testappverifierpresent]] == 0
|| ![testappverifierpresent]}]
testConstraint notInCIenv [expr {![info exists ::env(CI)]}]
namespace eval ::tcl::test::io {
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
|
| ︙ | ︙ | |||
2639 2640 2641 2642 2643 2644 2645 |
chan close $f
after 100
set f [open $path(test3) r]
chan read $f
} -cleanup {
chan close $f
} -result "Line 1\nLine 2\n"
| | | 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 |
chan close $f
after 100
set f [open $path(test3) r]
chan read $f
} -cleanup {
chan close $f
} -result "Line 1\nLine 2\n"
test chan-io-29.26 {Tcl_Flush, Tcl_Write on bidirectional pipelines} -constraints {stdio unixExecs notInCIenv} -body {
set f [open "|[list cat -u]" r+]
chan puts $f "Line1"
chan flush $f
chan gets $f
} -cleanup {
chan close $f
} -result {Line1}
|
| ︙ | ︙ | |||
7836 7837 7838 7839 7840 7841 7842 |
}
test chan-io-73.1 {channel Tcl_Obj SetChannelFromAny} -body {
# Test for Bug 1847044 - don't spoil type unless we have a valid channel
chan close [lreplace [list a] 0 end]
} -returnCodes error -match glob -result *
| < < < < < < < < < < < < < < < < < < < < < | 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 |
}
test chan-io-73.1 {channel Tcl_Obj SetChannelFromAny} -body {
# Test for Bug 1847044 - don't spoil type unless we have a valid channel
chan close [lreplace [list a] 0 end]
} -returnCodes error -match glob -result *
# ### ### ### ######### ######### #########
# cleanup
foreach file [list fooBar longfile script output test1 pipe my_script \
test2 test3 cat kyrillic.txt utf8-fcopy.txt utf8-rp.txt] {
removeFile $file
}
cleanupTests
}
namespace delete ::tcl::test::io
|
Changes to tests/clock.test.
| ︙ | ︙ | |||
38585 38586 38587 38588 38589 38590 38591 |
"2018-06-30 23:59:60" "invalid time"
} {
# check with free and format scan:
_check_scan res $d UTC "%Y-%m-%d %H:%M:%S" $i
}
join $res \n; # must be empty
} -result {}
| < < < < < < < < < < < < < < < < < < < < < < < | 38585 38586 38587 38588 38589 38590 38591 38592 38593 38594 38595 38596 38597 38598 |
"2018-06-30 23:59:60" "invalid time"
} {
# check with free and format scan:
_check_scan res $d UTC "%Y-%m-%d %H:%M:%S" $i
}
join $res \n; # must be empty
} -result {}
# cleanup
::tcl::clock::ClearCaches
rename test {}
namespace import -force ::tcltest::*
# adjust expected skipped (valid_off is an artificial constraint):
|
| ︙ | ︙ |
Changes to tests/cmdInfo.test.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 |
testConstraint testcmdinfo [llength [info commands testcmdinfo]]
testConstraint testcmdtoken [llength [info commands testcmdtoken]]
test cmdinfo-1.1 {command procedure and clientData} {testcmdinfo} {
testcmdinfo create x1
testcmdinfo get x1
| | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
testConstraint testcmdinfo [llength [info commands testcmdinfo]]
testConstraint testcmdtoken [llength [info commands testcmdtoken]]
test cmdinfo-1.1 {command procedure and clientData} {testcmdinfo} {
testcmdinfo create x1
testcmdinfo get x1
} {CmdProc1 original CmdDelProc1 original :: stringProc}
test cmdinfo-1.2 {command procedure and clientData} {testcmdinfo} {
testcmdinfo create x1
x1
} {CmdProc1 original}
test cmdinfo-1.3 {command procedure and clientData} {testcmdinfo} {
testcmdinfo create x1
testcmdinfo modify x1
|
| ︙ | ︙ |
Changes to tests/coroutine.test.
| ︙ | ︙ | |||
821 822 823 824 825 826 827 |
# c1. After the fix, that doesn't happen, so if c1 still exists call it
# one final time to allow it to finish and clean up
rename c1 {}
}
return [list $done0 $done1]
} -result {failure failure}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 821 822 823 824 825 826 827 828 829 830 831 832 833 834 |
# c1. After the fix, that doesn't happen, so if c1 still exists call it
# one final time to allow it to finish and clean up
rename c1 {}
}
return [list $done0 $done1]
} -result {failure failure}
test coroutine-8.1.1 {coro inject, ticket 42202ba1e5ff566e} -body {
interp create child
child eval {
coroutine demo apply {{} { while {1} yield }}
demo
coroinject demo set ::result inject-executed
}
|
| ︙ | ︙ |
Changes to tests/dict.test.
| ︙ | ︙ | |||
1661 1662 1663 1664 1665 1666 1667 |
} 1,2
test dict-22.23 {dict with: compiled} {
set ::d {p {q {a 1 b 2}}}
apply {{} {
dict with ::d p q {
}
return $a,$b
| < < < < < < < < < < < < < < < < < < < | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 |
} 1,2
test dict-22.23 {dict with: compiled} {
set ::d {p {q {a 1 b 2}}}
apply {{} {
dict with ::d p q {
}
return $a,$b
}}
} 1,2
proc linenumber {} {
dict get [info frame -1] line
}
test dict-23.1 {dict compilation crash: Bug 3487626} {
|
| ︙ | ︙ |
Changes to tests/encoding.test.
| ︙ | ︙ | |||
1182 1183 1184 1185 1186 1187 1188 |
string equal [encoding system] \
[expr {
[tcltests::windowsbuildnumber] > 18362 ?
"utf-8" : [tcltests::windowscodepage]
}]
} -constraints win -result 1
| < < < < < < < < < < | 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 |
string equal [encoding system] \
[expr {
[tcltests::windowsbuildnumber] > 18362 ?
"utf-8" : [tcltests::windowscodepage]
}]
} -constraints win -result 1
test encoding-bug-6a3e2cb0f0-1 {Bug [6a3e2cb0f0] - invalid bytes in escape encodings} -body {
encoding convertfrom -profile tcl8 iso2022-jp x\x1B\x7Aaby
} -result x\uFFFDy
test encoding-bug-6a3e2cb0f0-2 {Bug [6a3e2cb0f0] - invalid bytes in escape encodings} -body {
encoding convertfrom -profile strict iso2022-jp x\x1B\x7Aaby
} -returnCodes error -result {unexpected byte sequence starting at index 1: '\x1B'}
test encoding-bug-6a3e2cb0f0-3 {Bug [6a3e2cb0f0] - invalid bytes in escape encodings} -body {
|
| ︙ | ︙ |
Changes to tests/error.test.
| ︙ | ︙ | |||
1191 1192 1193 1194 1195 1196 1197 |
}
} 0
test error-21.9 {Bug cee90e4e88} {
# Just don't panic.
apply {{} {try {} on ok {} - on return {} {}}}
} {}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 |
}
} 0
test error-21.9 {Bug cee90e4e88} {
# Just don't panic.
apply {{} {try {} on ok {} - on return {} {}}}
} {}
# negative case try tests - bad "trap" handler
# what is the effect if we attempt to trap an errorcode that is not a list?
# nested try
# catch inside try
# no tests for bad varslist?
# -errorcode but code!=1 doesn't trap
|
| ︙ | ︙ |
Changes to tests/exec.test.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
namespace import -force ::tcltest::*
}
source [file join [file dirname [info script]] tcltests.tcl]
# Some skips when running in a macOS CI environment
testConstraint noosxCI [expr {![info exists ::env(MAC_CI)]}]
testConstraint testhandlecount [expr {[llength [info commands testhandlecount]] != 0}]
unset -nocomplain path
# Utilities that are like Bourne shell stalwarts, but cross-platform.
set path(echo) [makeFile {
| > > > > > > > > > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
namespace import -force ::tcltest::*
}
source [file join [file dirname [info script]] tcltests.tcl]
# Some skips when running in a macOS CI environment
testConstraint noosxCI [expr {![info exists ::env(MAC_CI)]}]
# Need a App Exec Alias for testing exec of reparse points,
# according to MS, winget can only be used on servers with an installed desktop interface,
# no idea how to check it in GHA programmatically, so simply disable it (todo: rewrite with better check later)
if {[testConstraint win] && ![info exists ::env(CI)] &&
[info exists ::env(LOCALAPPDATA)]} {
set wingetPath [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]
if {[file exists $wingetPath]} {
# Ensure it is on the PATH
testConstraint haveWinget 1
}
}
testConstraint testhandlecount [expr {[llength [info commands testhandlecount]] != 0}]
unset -nocomplain path
# Utilities that are like Bourne shell stalwarts, but cross-platform.
set path(echo) [makeFile {
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 |
}
close $f
} -body {
exec [interpreter] $path(err)
} -returnCodes error -result {out
err}
| < < < < | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
}
close $f
} -body {
exec [interpreter] $path(err)
} -returnCodes error -result {out
err}
# Errors in executing the Tcl command, as opposed to errors in the processes
# that are invoked.
test exec-10.1 {errors in exec invocation} -constraints {exec} -body {
exec
} -returnCodes error -result {wrong # args: should be "exec ?-option ...? arg ?arg ...?"}
test exec-10.2 {errors in exec invocation} -constraints {exec} -body {
|
| ︙ | ︙ | |||
747 748 749 750 751 752 753 |
file size $tmpfile
} -cleanup {
removeFile $tmpfile
} -result 26
# Tests to ensure batch files and .CMD (Bug 9ece99d58b)
# can be executed on Windows
| | | | | | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 |
file size $tmpfile
} -cleanup {
removeFile $tmpfile
} -result 26
# Tests to ensure batch files and .CMD (Bug 9ece99d58b)
# can be executed on Windows
test exec-20.0 {exec .bat file} -constraints {win} -body {
set log [makeFile {} exec20.log]
exec [makeFile "echo %1> $log" exec20.bat] "Testing exec-20.0"
viewFile $log
} -result "\"Testing exec-20.0\""
test exec-20.1 {exec .CMD file} -constraints {win} -body {
set log [makeFile {} exec201.log]
exec [makeFile "echo %1> $log" exec201.CMD] "Testing exec-20.1"
viewFile $log
} -result "\"Testing exec-20.1\""
# Test with encoding mismatches (Bug 0f1ddc0df7fb7)
test exec-21.1 {exec encoding mismatch on stdout} -setup {
set path(script) [makeFile {
fconfigure stdout -translation binary
|
| ︙ | ︙ | |||
795 796 797 798 799 800 801 |
set enc [expr {[encoding system] eq "utf-8" ? "iso2022-jp" : "utf-8"}]
exec -encoding $enc -- [interpreter] $path(echobin) [binary encode hex [encoding convertto $enc \u4e4e\u68d9]]
} -result \u4e4e\u68d9
test exec-22.1 {exec -encoding invalid encoding} -body {
exec -encoding nosuchencoding -- [interpreter] $path(echobin) abc
} -result {unknown encoding "nosuchencoding"} -returnCodes error
| < < < | < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < | < < | | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 |
set enc [expr {[encoding system] eq "utf-8" ? "iso2022-jp" : "utf-8"}]
exec -encoding $enc -- [interpreter] $path(echobin) [binary encode hex [encoding convertto $enc \u4e4e\u68d9]]
} -result \u4e4e\u68d9
test exec-22.1 {exec -encoding invalid encoding} -body {
exec -encoding nosuchencoding -- [interpreter] $path(echobin) abc
} -result {unknown encoding "nosuchencoding"} -returnCodes error
test exec-bug-4f0b5767ac {exec App Execution Alias} -setup {
# Ensure winget is on the PATH
set savedEnv $::env(PATH)
append env(PATH) ";" [file nativename [file dirname $wingetPath]]
} -cleanup {
set ::env(PATH) $savedEnv
unset -nocomplain savedEnv
} -constraints haveWinget -body {
exec winget --info
} -result "*Windows*" -match glob
foreach cmdBuiltin {
assoc call cd cls color copy date del dir echo
erase exit ftype for if md mkdir mklink move path
pause prompt rd ren rename rmdir set start time
title type ver vol
} {
test auto_execok-$cmdBuiltin-1.0 "auto_execok $cmdBuiltin" \
-constraints win \
-body {
string equal [auto_execok $cmdBuiltin] \
"[file normalize $::env(COMSPEC)] /c $cmdBuiltin"
} -result 1
}
unset cmdBuiltin
# ----------------------------------------------------------------------
# cleanup
foreach file {gorp.file gorp.file2 echo echo2 echobin cat wc sh sh2 sleep exit err} {
removeFile $file
}
unset -nocomplain path tmp wingetPath
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
# End:
|
Changes to tests/fCmd.test.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
cd [temporaryDirectory]
testConstraint testsetplatform [llength [info commands testsetplatform]]
testConstraint testchmod [llength [info commands testchmod]]
testConstraint winLessThan10 0
# Don't know how to determine this constraint correctly
testConstraint notNetworkFilesystem 0
testConstraint notInCIenv [expr {![info exists ::env(CI)] || !$::env(CI)}]
# File permissions broken on wsl without some "exotic" wsl configuration
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
set tmpspace /tmp;# default value
| > > > > > > > > > > > > > > > > > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
cd [temporaryDirectory]
testConstraint testsetplatform [llength [info commands testsetplatform]]
testConstraint testchmod [llength [info commands testchmod]]
testConstraint winLessThan10 0
# Don't know how to determine this constraint correctly
testConstraint notNetworkFilesystem 0
testConstraint reg 0
if {[testConstraint win]} {
if {[catch {
# Is the registry extension already static to this shell?
try {
load {} Registry
set ::reglib {}
} on error {} {
# try the location given to use on the commandline to tcltest
::tcltest::loadTestedCommands
load $::reglib Registry
}
testConstraint reg 1
} regError]} {
catch {package require registry; testConstraint reg 1}
}
}
testConstraint notInCIenv [expr {![info exists ::env(CI)] || !$::env(CI)}]
# File permissions broken on wsl without some "exotic" wsl configuration
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
set tmpspace /tmp;# default value
|
| ︙ | ︙ | |||
109 110 111 112 113 114 115 |
} home]} {
set home [string trim $home]
if {$home ne ""} {
# Expect exact match (except case), no glob * added
return [string tolower $home]
}
}
| | | | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
} home]} {
set home [string trim $home]
if {$home ne ""} {
# Expect exact match (except case), no glob * added
return [string tolower $home]
}
}
} elseif {[testConstraint reg]} {
# Windows with registry extension loaded
if {![catch {
set sid [exec {*}[auto_execok powershell] -Command "(Get-LocalUser -Name '$user')\[0\].sid.Value"]
set sid [string trim $sid]
# Get path from the Windows registry
set home [registry get "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\$sid" ProfileImagePath]
set home [string trim [string tolower $home]]
} result]} {
if {$home ne ""} {
# file join for \ -> /
return [file join [string tolower $home]]
}
}
|
| ︙ | ︙ | |||
2669 2670 2671 2672 2673 2674 2675 |
test fCmd-29.1 {weird memory corruption fault} -body {
open [file join ~a_totally_bogus_user_id/foo bar]
} -returnCodes error -match glob -result *
test fCmd-30.1 {file writable on 'My Documents'} -setup {
# Get the localized version of the folder name by looking in the registry.
| | | | 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 |
test fCmd-29.1 {weird memory corruption fault} -body {
open [file join ~a_totally_bogus_user_id/foo bar]
} -returnCodes error -match glob -result *
test fCmd-30.1 {file writable on 'My Documents'} -setup {
# Get the localized version of the folder name by looking in the registry.
set mydocsname [registry get {HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders} Personal]
} -constraints {win reg} -body {
file writable $mydocsname
} -result 1
test fCmd-30.2 {file readable on 'NTUSER.DAT'} -constraints {win notWine} -body {
expr {[info exists env(USERPROFILE)]
&& [file exists $env(USERPROFILE)/NTUSER.DAT]
&& [file readable $env(USERPROFILE)/NTUSER.DAT]}
} -result 1
|
| ︙ | ︙ |
Changes to tests/fileName.test.
| ︙ | ︙ | |||
1658 1659 1660 1661 1662 1663 1664 |
} -body {
glob -nocomplain -directory [file home] -join * fileName-20.10
} -cleanup {
cd $savewd
removeDirectory isolate
removeFile fileName-20.10 $s
removeDirectory sub [file home]
| | | 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 |
} -body {
glob -nocomplain -directory [file home] -join * fileName-20.10
} -cleanup {
cd $savewd
removeDirectory isolate
removeFile fileName-20.10 $s
removeDirectory sub [file home]
} -result [file home]/sub/fileName-20.10
test fileName-20.11 {glob dir with undecodable file names} -setup {
# Specifically use /tmp as on WSL [temporaryDirectory]
# on NTFS prevents creation of arbitrary byte sequences in names.
set prevDir [pwd]
set testDir /tmp/tcltest/fileName-20.11
file delete -force $testDir; # Clear it
file mkdir $testDir
|
| ︙ | ︙ |
Changes to tests/fileSystem.test.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
catch {
| | < | | > < < | < < < < < < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
catch {
file delete -force link.file
file delete -force dir.link
file delete -force [file join dir.dir linkinside.file]
}
# notWSL constraint is true when running under native Windows or
# native Unix.
testConstraint notWsl \
[expr {
$::tcl_platform(platform) eq "windows"
|| [llength [array names ::env *WSL*]] == 0
}]
testConstraint loaddll 0
catch {
::tcltest::loadTestedCommands
package require -exact tcl::test [info patchlevel]
set ::ddever [package require dde]
set ::ddelib [info loaded {} Dde]
set ::regver [package require registry]
set ::reglib [info loaded {} Registry]
testConstraint loaddll [expr {$::ddelib ne "" && $::reglib ne ""}]
}
# Test for commands defined in tcl::test package
testConstraint testfilesystem [llength [info commands ::testfilesystem]]
testConstraint testsetplatform [llength [info commands ::testsetplatform]]
testConstraint testsimplefilesystem [llength [info commands ::testsimplefilesystem]]
# Some things fail under all Continuous Integration systems for subtle reasons
# such as CI often running with elevated privileges in a container.
testConstraint notInCIenv [expr {![info exists ::env(CI)]}]
testConstraint notOSX [expr {$::tcl_platform(os) ne "Darwin"}]
cd [tcltest::temporaryDirectory]
makeFile "test file" gorp.file
makeDirectory dir.dir
makeDirectory [file join dir.dir dirinside.dir]
makeFile "test file in directory" [file join dir.dir inside.file]
testConstraint unusedDrive 0
testConstraint moreThanOneDrive 0
apply {{} {
# The variables 'drive' and 'drives' will be used below.
variable drive {} drives {}
if {[testConstraint win]} {
|
| ︙ | ︙ | |||
99 100 101 102 103 104 105 |
return "ok"
}
return "not equal: $one $two"
}
testConstraint hasLinks [expr {![catch {
file link link.file gorp.file
| < < < < < < < < < < < < < < < < < < < < < < < < < < < | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
return "ok"
}
return "not equal: $one $two"
}
testConstraint hasLinks [expr {![catch {
file link link.file gorp.file
cd dir.dir
file link \
[file join linkinside.file] \
[file join inside.file]
cd ..
file link dir.link dir.dir
cd dir.dir
file link [file join dirinside.link] \
[file join dirinside.dir]
cd ..
}]}]
if {[testConstraint testsetplatform]} {
set platform [testgetplatform]
}
# ----------------------------------------------------------------------
test filesystem-1.0 {link normalisation} {hasLinks} {
|
| ︙ | ︙ | |||
369 370 371 372 373 374 375 |
test filesystem-1.37 {file normalisation with '/./'} -body {
set fname "/abc/./def/./ghi/./asda/.././.././asd/x/../../../../....."
file norm $fname
} -match regexp -result {^(?:[^/]|/(?:[^/]|$))+$}
test filesystem-1.38 {file normalisation with volume relative} -setup {
set dir [pwd]
} -constraints {win moreThanOneDrive notInCIenv} -body {
| < | | < < < < < | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
test filesystem-1.37 {file normalisation with '/./'} -body {
set fname "/abc/./def/./ghi/./asda/.././.././asd/x/../../../../....."
file norm $fname
} -match regexp -result {^(?:[^/]|/(?:[^/]|$))+$}
test filesystem-1.38 {file normalisation with volume relative} -setup {
set dir [pwd]
} -constraints {win moreThanOneDrive notInCIenv} -body {
set path "[string range [lindex $drives 0] 0 1]foo"
cd [lindex $drives 1]
file norm $path
} -cleanup {
cd $dir
unset -nocomplain path
} -result "[lindex $drives 0]foo"
test filesystem-1.39 {file normalisation with volume relative} -setup {
set old [pwd]
} -constraints {win} -body {
set drv C:/
cd [lindex [glob -type d -dir $drv *] 0]
file norm [string range $drv 0 1]
} -cleanup {
|
| ︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 |
# ----------------------------------------------------------------------
test filesystem-10.1 {Bug 3414754} {
string match */ [file join [pwd] foo/]
} 0
| | < | | > > > > | | < > | | | < < > | < > > | > > > > | | | | < > | > | < | > > > > > > > > | < | < > | | > | > | | < < < < < < < < < | | < < | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < | < < < | < < < < < < < < | < < < | < < < | < < < | < < < | < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 |
# ----------------------------------------------------------------------
test filesystem-10.1 {Bug 3414754} {
string match */ [file join [pwd] foo/]
} 0
# The filesystem-11.* tests are currently disabled on MacOS.
# See Bug [e6ca0b1b67]
test filesystem-11.1 {
Bug 10890417 - case of tail is correct after normalization
} -constraints {notWsl notOSX} -setup {
makeFile "" mIxEdCaSe.TxT
} -cleanup {
removeFile mIxEdCaSe.TxT
} -body {
lmap file1 [glob [tcltest::temporaryDirectory]/mixedcase.txt \
[tcltest::temporaryDirectory]/MIXEDCASE.TXT \
[tcltest::temporaryDirectory]/mIxEdCaSe.TxT \
] {
file normalize $file1
}
} -result [expr {
$::tcl_platform(platform) eq "windows" ?
[lrepeat 3 [tcltest::temporaryDirectory]/mIxEdCaSe.TxT]
:
[list [tcltest::temporaryDirectory]/mIxEdCaSe.TxT]}]
test filesystem-11.2 {
Bug 10890417 - case of tail is correct after normalization (-directory)
} -constraints {notWsl notOSX} -setup {
makeFile "" mIxEdCaSe.TxT
} -cleanup {
removeFile mIxEdCaSe.TxT
} -body {
lmap file1 [glob -directory [tcltest::temporaryDirectory] \
mixedcase.txt MIXEDCASE.TXT mIxEdCaSe.TxT ] {
file normalize $file1
}
} -result [expr {
$::tcl_platform(platform) eq "windows" ?
[lrepeat 3 [file join [tcltest::temporaryDirectory] mIxEdCaSe.TxT]]
:
[list [file join [tcltest::temporaryDirectory] mIxEdCaSe.TxT]]}]
test filesystem-11.3 {
Bug 10890417 - case of dir is correct after normalization
} -constraints {notWsl notOSX} -setup {
set dir [makeDirectory MiXeDcAsE]
set parent [file dirname $dir]
makeFile "" foo.txt $dir
} -cleanup {
removeFile foo.txt $dir
removeDirectory MiXeDcAsE
unset -nocomplain parent dir
} -body {
lmap file1 [glob $parent/mixedcase/foo.txt \
$parent/MIXEDCASE/foo.txt \
$parent/MiXeDcAsE/foo.txt] {
file tail [file dirname [file normalize $file1]]
}
} -result [expr {
$::tcl_platform(platform) eq "windows" ?
[lrepeat 3 MiXeDcAsE]
:
[list MiXeDcAsE]}]
test filesystem-11.4 {
Bug 10890417 - case of dir is correct after normalization (-directory)
} -constraints {notWsl notOSX} -setup {
set dir [makeDirectory MiXeDcAsE]
set parent [file dirname $dir]
makeFile "" foo.txt $dir
} -cleanup {
removeFile foo.txt $dir
removeDirectory MiXeDcAsE
unset -nocomplain parent dir
} -body {
lmap file1 [concat [glob -dir $parent/mixedcase foo.txt] \
[glob -dir $parent/MIXEDCASE foo.txt] \
[glob -dir $parent/MiXeDcAsE foo.txt]] {
file tail [file dirname [file normalize $file1]]
}
} -result [expr {
$::tcl_platform(platform) eq "windows" ?
[lrepeat 3 MiXeDcAsE]
:
[list MiXeDcAsE]}]
cleanupTests
unset -nocomplain drive drives
}
namespace delete ::tcl::test::fileSystem
return
# Local Variables:
# mode: tcl
# End:
|
Deleted tests/grapheme.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tests/http.test.
| ︙ | ︙ | |||
747 748 749 750 751 752 753 754 755 756 757 758 759 760 |
# with Tcl 8.x (unknown chars become '?'), generating a
# proper exception with Tcl 9.0
http::config -urlencoding "iso8859-1"
http::mapReply "∈"
} -cleanup {
http::config -urlencoding $enc
} -errorCode {TCL ENCODING ILLEGALSEQUENCE 0} -result {unexpected character at index 0: 'U+002208'}
# cleanup
catch {unset url}
catch {unset badurl}
catch {unset port}
catch {unset data}
if {[llength $threadStack]} {
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 |
# with Tcl 8.x (unknown chars become '?'), generating a
# proper exception with Tcl 9.0
http::config -urlencoding "iso8859-1"
http::mapReply "∈"
} -cleanup {
http::config -urlencoding $enc
} -errorCode {TCL ENCODING ILLEGALSEQUENCE 0} -result {unexpected character at index 0: 'U+002208'}
package require tcl::idna 1.0
test http-idna-1.1.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna
} -result {wrong # args: should be "::tcl::idna subcommand ?arg ...?"}
test http-idna-1.2.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna ?
} -result {unknown or ambiguous subcommand "?": must be decode, encode, puny, or version}
test http-idna-1.3.$ThreadLevel {IDNA package: basics} -body {
::tcl::idna version
} -result 1.0.1
test http-idna-1.4.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna version what
} -result {wrong # args: should be "::tcl::idna version"}
test http-idna-1.5.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna puny
} -result {wrong # args: should be "::tcl::idna puny subcommand ?arg ...?"}
test http-idna-1.6.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna puny ?
} -result {unknown or ambiguous subcommand "?": must be decode, or encode}
test http-idna-1.7.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna puny encode
} -result {wrong # args: should be "::tcl::idna puny encode string ?case?"}
test http-idna-1.8.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna puny encode a b c
} -result {wrong # args: should be "::tcl::idna puny encode string ?case?"}
test http-idna-1.9.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna puny decode
} -result {wrong # args: should be "::tcl::idna puny decode string ?case?"}
test http-idna-1.10.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna puny decode a b c
} -result {wrong # args: should be "::tcl::idna puny decode string ?case?"}
test http-idna-1.11.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna decode
} -result {wrong # args: should be "::tcl::idna decode hostname"}
test http-idna-1.12.$ThreadLevel {IDNA package: basics} -returnCodes error -body {
::tcl::idna encode
} -result {wrong # args: should be "::tcl::idna encode hostname"}
test http-idna-2.1.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode abc
} abc-
test http-idna-2.2.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode a€b€c
} abc-k50ab
test http-idna-2.3.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode ABC
} ABC-
test http-idna-2.4.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode A€B€C
} ABC-k50ab
test http-idna-2.5.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode ABC 0
} abc-
test http-idna-2.6.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode A€B€C 0
} abc-k50ab
test http-idna-2.7.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode ABC 1
} ABC-
test http-idna-2.8.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode A€B€C 1
} ABC-k50ab
test http-idna-2.9.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode abc 0
} abc-
test http-idna-2.10.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode a€b€c 0
} abc-k50ab
test http-idna-2.11.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode abc 1
} ABC-
test http-idna-2.12.$ThreadLevel {puny encode: functional test} {
::tcl::idna puny encode a€b€c 1
} ABC-k50ab
test http-idna-2.13.$ThreadLevel {puny encode: edge cases} {
::tcl::idna puny encode ""
} ""
test http-idna-2.14-A.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+0644 u+064A u+0647 u+0645 u+0627 u+0628 u+062A u+0643 u+0644
u+0645 u+0648 u+0634 u+0639 u+0631 u+0628 u+064A u+061F
}]] ""]
} egbpdaj6bu4bxfgehfvwxn
test http-idna-2.14-B.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+4ED6 u+4EEC u+4E3A u+4EC0 u+4E48 u+4E0D u+8BF4 u+4E2D u+6587
}]] ""]
} ihqwcrb4cv8a8dqg056pqjye
test http-idna-2.14-C.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+4ED6 u+5011 u+7232 u+4EC0 u+9EBD u+4E0D u+8AAA u+4E2D u+6587
}]] ""]
} ihqwctvzc91f659drss3x8bo0yb
test http-idna-2.14-D.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+0050 u+0072 u+006F u+010D u+0070 u+0072 u+006F u+0073 u+0074
u+011B u+006E u+0065 u+006D u+006C u+0075 u+0076 u+00ED u+010D
u+0065 u+0073 u+006B u+0079
}]] ""]
} Proprostnemluvesky-uyb24dma41a
test http-idna-2.14-E.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+05DC u+05DE u+05D4 u+05D4 u+05DD u+05E4 u+05E9 u+05D5 u+05D8
u+05DC u+05D0 u+05DE u+05D3 u+05D1 u+05E8 u+05D9 u+05DD u+05E2
u+05D1 u+05E8 u+05D9 u+05EA
}]] ""]
} 4dbcagdahymbxekheh6e0a7fei0b
test http-idna-2.14-F.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+092F u+0939 u+0932 u+094B u+0917 u+0939 u+093F u+0928 u+094D
u+0926 u+0940 u+0915 u+094D u+092F u+094B u+0902 u+0928 u+0939
u+0940 u+0902 u+092C u+094B u+0932 u+0938 u+0915 u+0924 u+0947
u+0939 u+0948 u+0902
}]] ""]
} i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd
test http-idna-2.14-G.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+306A u+305C u+307F u+3093 u+306A u+65E5 u+672C u+8A9E u+3092
u+8A71 u+3057 u+3066 u+304F u+308C u+306A u+3044 u+306E u+304B
}]] ""]
} n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa
test http-idna-2.14-H.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
}]] ""]
} 989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c
test http-idna-2.14-I.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E
u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440
u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A
u+0438
}]] ""]
} b1abfaaepdrnnbgefbadotcwatmq2g4l
test http-idna-2.14-J.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+0050 u+006F u+0072 u+0071 u+0075 u+00E9 u+006E u+006F u+0070
u+0075 u+0065 u+0064 u+0065 u+006E u+0073 u+0069 u+006D u+0070
u+006C u+0065 u+006D u+0065 u+006E u+0074 u+0065 u+0068 u+0061
u+0062 u+006C u+0061 u+0072 u+0065 u+006E u+0045 u+0073 u+0070
u+0061 u+00F1 u+006F u+006C
}]] ""]
} PorqunopuedensimplementehablarenEspaol-fmd56a
test http-idna-2.14-K.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+0054 u+1EA1 u+0069 u+0073 u+0061 u+006F u+0068 u+1ECD u+006B
u+0068 u+00F4 u+006E u+0067 u+0074 u+0068 u+1EC3 u+0063 u+0068
u+1EC9 u+006E u+00F3 u+0069 u+0074 u+0069 u+1EBF u+006E u+0067
u+0056 u+0069 u+1EC7 u+0074
}]] ""]
} TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g
test http-idna-2.14-L.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+0033 u+5E74 u+0042 u+7D44 u+91D1 u+516B u+5148 u+751F
}]] ""]
} 3B-ww4c5e180e575a65lsy2b
test http-idna-2.14-M.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+5B89 u+5BA4 u+5948 u+7F8E u+6075 u+002D u+0077 u+0069 u+0074
u+0068 u+002D u+0053 u+0055 u+0050 u+0045 u+0052 u+002D u+004D
u+004F u+004E u+004B u+0045 u+0059 u+0053
}]] ""]
} -with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n
test http-idna-2.14-N.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+0048 u+0065 u+006C u+006C u+006F u+002D u+0041 u+006E u+006F
u+0074 u+0068 u+0065 u+0072 u+002D u+0057 u+0061 u+0079 u+002D
u+305D u+308C u+305E u+308C u+306E u+5834 u+6240
}]] ""]
} Hello-Another-Way--fc4qua05auwb3674vfr0b
test http-idna-2.14-O.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+3072 u+3068 u+3064 u+5C4B u+6839 u+306E u+4E0B u+0032
}]] ""]
} 2-u9tlzr9756bt3uc0v
test http-idna-2.14-P.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+004D u+0061 u+006A u+0069 u+3067 u+004B u+006F u+0069 u+3059
u+308B u+0035 u+79D2 u+524D
}]] ""]
} MajiKoi5-783gue6qz075azm5e
test http-idna-2.14-Q.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+30D1 u+30D5 u+30A3 u+30FC u+0064 u+0065 u+30EB u+30F3 u+30D0
}]] ""]
} de-jg4avhby1noc0d
test http-idna-2.14-R.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode [join [subst [string map {u+ \\u} {
u+305D u+306E u+30B9 u+30D4 u+30FC u+30C9 u+3067
}]] ""]
} d9juau41awczczp
test http-idna-2.14-S.$ThreadLevel {puny encode: examples from RFC 3492} {
::tcl::idna puny encode {-> $1.00 <-}
} {-> $1.00 <--}
test http-idna-3.1.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode abc-
} abc
test http-idna-3.2.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode abc-k50ab
} a€b€c
test http-idna-3.3.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode ABC-
} ABC
test http-idna-3.4.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode ABC-k50ab
} A€B€C
test http-idna-3.5.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode ABC-K50AB
} A€B€C
test http-idna-3.6.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode abc-K50AB
} a€b€c
test http-idna-3.7.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode ABC- 0
} abc
test http-idna-3.8.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode ABC-K50AB 0
} a€b€c
test http-idna-3.9.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode ABC- 1
} ABC
test http-idna-3.10.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode ABC-K50AB 1
} A€B€C
test http-idna-3.11.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode abc- 0
} abc
test http-idna-3.12.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode abc-k50ab 0
} a€b€c
test http-idna-3.13.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode abc- 1
} ABC
test http-idna-3.14.$ThreadLevel {puny decode: functional test} {
::tcl::idna puny decode abc-k50ab 1
} A€B€C
test http-idna-3.15.$ThreadLevel {puny decode: edge cases and errors} {
# Is this case actually correct?
binary encode hex [encoding convertto utf-8 [::tcl::idna puny decode abc]]
} c282c281c280
test http-idna-3.16.$ThreadLevel {puny decode: edge cases and errors} -returnCodes error -body {
::tcl::idna puny decode abc!
} -result {bad decode character "!"}
test http-idna-3.17.$ThreadLevel {puny decode: edge cases and errors} {
catch {::tcl::idna puny decode abc!} -> opt
dict get $opt -errorcode
} {PUNYCODE BAD_INPUT CHAR}
test http-idna-3.18.$ThreadLevel {puny decode: edge cases and errors} {
::tcl::idna puny decode ""
} {}
# A helper so we don't get lots of crap in failures
proc hexify s {lmap c [split $s ""] {format u+%04X [scan $c %c]}}
test http-idna-3.19-A.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode egbpdaj6bu4bxfgehfvwxn]
} [list {*}{
u+0644 u+064A u+0647 u+0645 u+0627 u+0628 u+062A u+0643 u+0644
u+0645 u+0648 u+0634 u+0639 u+0631 u+0628 u+064A u+061F
}]
test http-idna-3.19-B.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode ihqwcrb4cv8a8dqg056pqjye]
} {u+4ED6 u+4EEC u+4E3A u+4EC0 u+4E48 u+4E0D u+8BF4 u+4E2D u+6587}
test http-idna-3.19-C.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode ihqwctvzc91f659drss3x8bo0yb]
} {u+4ED6 u+5011 u+7232 u+4EC0 u+9EBD u+4E0D u+8AAA u+4E2D u+6587}
test http-idna-3.19-D.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode Proprostnemluvesky-uyb24dma41a]
} [list {*}{
u+0050 u+0072 u+006F u+010D u+0070 u+0072 u+006F u+0073 u+0074
u+011B u+006E u+0065 u+006D u+006C u+0075 u+0076 u+00ED u+010D
u+0065 u+0073 u+006B u+0079
}]
test http-idna-3.19-E.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode 4dbcagdahymbxekheh6e0a7fei0b]
} [list {*}{
u+05DC u+05DE u+05D4 u+05D4 u+05DD u+05E4 u+05E9 u+05D5 u+05D8
u+05DC u+05D0 u+05DE u+05D3 u+05D1 u+05E8 u+05D9 u+05DD u+05E2
u+05D1 u+05E8 u+05D9 u+05EA
}]
test http-idna-3.19-F.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode \
i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd]
} [list {*}{
u+092F u+0939 u+0932 u+094B u+0917 u+0939 u+093F u+0928 u+094D
u+0926 u+0940 u+0915 u+094D u+092F u+094B u+0902 u+0928 u+0939
u+0940 u+0902 u+092C u+094B u+0932 u+0938 u+0915 u+0924 u+0947
u+0939 u+0948 u+0902
}]
test http-idna-3.19-G.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa]
} [list {*}{
u+306A u+305C u+307F u+3093 u+306A u+65E5 u+672C u+8A9E u+3092
u+8A71 u+3057 u+3066 u+304F u+308C u+306A u+3044 u+306E u+304B
}]
test http-idna-3.19-H.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode \
989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c]
} [list {*}{
u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
}]
test http-idna-3.19-I.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode b1abfaaepdrnnbgefbadotcwatmq2g4l]
} [list {*}{
u+043F u+043E u+0447 u+0435 u+043C u+0443 u+0436 u+0435 u+043E
u+043D u+0438 u+043D u+0435 u+0433 u+043E u+0432 u+043E u+0440
u+044F u+0442 u+043F u+043E u+0440 u+0443 u+0441 u+0441 u+043A
u+0438
}]
test http-idna-3.19-J.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode \
PorqunopuedensimplementehablarenEspaol-fmd56a]
} [list {*}{
u+0050 u+006F u+0072 u+0071 u+0075 u+00E9 u+006E u+006F u+0070
u+0075 u+0065 u+0064 u+0065 u+006E u+0073 u+0069 u+006D u+0070
u+006C u+0065 u+006D u+0065 u+006E u+0074 u+0065 u+0068 u+0061
u+0062 u+006C u+0061 u+0072 u+0065 u+006E u+0045 u+0073 u+0070
u+0061 u+00F1 u+006F u+006C
}]
test http-idna-3.19-K.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode \
TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g]
} [list {*}{
u+0054 u+1EA1 u+0069 u+0073 u+0061 u+006F u+0068 u+1ECD u+006B
u+0068 u+00F4 u+006E u+0067 u+0074 u+0068 u+1EC3 u+0063 u+0068
u+1EC9 u+006E u+00F3 u+0069 u+0074 u+0069 u+1EBF u+006E u+0067
u+0056 u+0069 u+1EC7 u+0074
}]
test http-idna-3.19-L.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode 3B-ww4c5e180e575a65lsy2b]
} {u+0033 u+5E74 u+0042 u+7D44 u+91D1 u+516B u+5148 u+751F}
test http-idna-3.19-M.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode -with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n]
} [list {*}{
u+5B89 u+5BA4 u+5948 u+7F8E u+6075 u+002D u+0077 u+0069 u+0074
u+0068 u+002D u+0053 u+0055 u+0050 u+0045 u+0052 u+002D u+004D
u+004F u+004E u+004B u+0045 u+0059 u+0053
}]
test http-idna-3.19-N.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode Hello-Another-Way--fc4qua05auwb3674vfr0b]
} [list {*}{
u+0048 u+0065 u+006C u+006C u+006F u+002D u+0041 u+006E u+006F
u+0074 u+0068 u+0065 u+0072 u+002D u+0057 u+0061 u+0079 u+002D
u+305D u+308C u+305E u+308C u+306E u+5834 u+6240
}]
test http-idna-3.19-O.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode 2-u9tlzr9756bt3uc0v]
} {u+3072 u+3068 u+3064 u+5C4B u+6839 u+306E u+4E0B u+0032}
test http-idna-3.19-P.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode MajiKoi5-783gue6qz075azm5e]
} [list {*}{
u+004D u+0061 u+006A u+0069 u+3067 u+004B u+006F u+0069 u+3059
u+308B u+0035 u+79D2 u+524D
}]
test http-idna-3.19-Q.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode de-jg4avhby1noc0d]
} {u+30D1 u+30D5 u+30A3 u+30FC u+0064 u+0065 u+30EB u+30F3 u+30D0}
test http-idna-3.19-R.$ThreadLevel {puny decode: examples from RFC 3492} {
hexify [::tcl::idna puny decode d9juau41awczczp]
} {u+305D u+306E u+30B9 u+30D4 u+30FC u+30C9 u+3067}
test http-idna-3.19-S.$ThreadLevel {puny decode: examples from RFC 3492} {
::tcl::idna puny decode {-> $1.00 <--}
} {-> $1.00 <-}
rename hexify ""
test http-idna-4.1.$ThreadLevel {IDNA encoding} {
::tcl::idna encode abc.def
} abc.def
test http-idna-4.2.$ThreadLevel {IDNA encoding} {
::tcl::idna encode a€b€c.def
} xn--abc-k50ab.def
test http-idna-4.3.$ThreadLevel {IDNA encoding} {
::tcl::idna encode def.a€b€c
} def.xn--abc-k50ab
test http-idna-4.4.$ThreadLevel {IDNA encoding} {
::tcl::idna encode ABC.DEF
} ABC.DEF
test http-idna-4.5.$ThreadLevel {IDNA encoding} {
::tcl::idna encode A€B€C.def
} xn--ABC-k50ab.def
test http-idna-4.6.$ThreadLevel {IDNA encoding: invalid edge case} {
# Should this be an error?
::tcl::idna encode abc..def
} abc..def
test http-idna-4.7.$ThreadLevel {IDNA encoding: invalid char} -returnCodes error -body {
::tcl::idna encode abc.$.def
} -result {bad character "$" in DNS name}
test http-idna-4.7.1.$ThreadLevel {IDNA encoding: invalid char} {
catch {::tcl::idna encode abc.$.def} -> opt
dict get $opt -errorcode
} {IDNA INVALID_NAME_CHARACTER {$}}
test http-idna-4.8.$ThreadLevel {IDNA encoding: empty} {
::tcl::idna encode ""
} {}
set overlong www.[join [subst [string map {u+ \\u} {
u+C138 u+ACC4 u+C758 u+BAA8 u+B4E0 u+C0AC u+B78C u+B4E4 u+C774
u+D55C u+AD6D u+C5B4 u+B97C u+C774 u+D574 u+D55C u+B2E4 u+BA74
u+C5BC u+B9C8 u+B098 u+C88B u+C744 u+AE4C
}]] ""].com
test http-idna-4.9.$ThreadLevel {IDNA encoding: max lengths from RFC 5890} -body {
::tcl::idna encode $overlong
} -returnCodes error -result "hostname part too long"
test http-idna-4.9.1.$ThreadLevel {IDNA encoding: max lengths from RFC 5890} {
catch {::tcl::idna encode $overlong} -> opt
dict get $opt -errorcode
} {IDNA OVERLONG_PART xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c}
unset overlong
test http-idna-4.10.$ThreadLevel {IDNA encoding: edge cases} {
::tcl::idna encode passé.example.com
} xn--pass-epa.example.com
test http-idna-5.1.$ThreadLevel {IDNA decoding} {
::tcl::idna decode abc.def
} abc.def
test http-idna-5.2.$ThreadLevel {IDNA decoding} {
# Invalid entry that's just a wrapper
::tcl::idna decode xn--abc-.def
} abc.def
test http-idna-5.3.$ThreadLevel {IDNA decoding} {
# Invalid entry that's just a wrapper
::tcl::idna decode xn--abc-.xn--def-
} abc.def
test http-idna-5.4.$ThreadLevel {IDNA decoding} {
# Invalid entry that's just a wrapper
::tcl::idna decode XN--abc-.XN--def-
} abc.def
test http-idna-5.5.$ThreadLevel {IDNA decoding: error cases} -returnCodes error -body {
::tcl::idna decode xn--$$$.example.com
} -result {bad decode character "$"}
test http-idna-5.5.1.$ThreadLevel {IDNA decoding: error cases} {
catch {::tcl::idna decode xn--$$$.example.com} -> opt
dict get $opt -errorcode
} {PUNYCODE BAD_INPUT CHAR}
test http-idna-5.6.$ThreadLevel {IDNA decoding: error cases} -returnCodes error -body {
::tcl::idna decode xn--a-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.def
} -result {exceeded input data}
test http-idna-5.6.1.$ThreadLevel {IDNA decoding: error cases} {
catch {::tcl::idna decode xn--a-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.def} -> opt
dict get $opt -errorcode
} {PUNYCODE BAD_INPUT LENGTH}
# cleanup
catch {unset url}
catch {unset badurl}
catch {unset port}
catch {unset data}
if {[llength $threadStack]} {
|
| ︙ | ︙ |
Changes to tests/httpcookie.test.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
package require tcltest 2.5
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
testConstraint notMacCI [expr {![info exists ::env(MAC_CI)]}]
| | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package require tcltest 2.5
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
testConstraint notMacCI [expr {![info exists ::env(MAC_CI)]}]
testConstraint sqlite3 [expr {[testConstraint notMacCI] && ![catch {
package require sqlite3
}]}]
testConstraint cookiejar [expr {[testConstraint sqlite3] && ![catch {
package require cookiejar
}]}]
set COOKIEJAR_VERSION 0.2.0
|
| ︙ | ︙ |
Changes to tests/icuUcmTests.tcl.
1 2 3 4 | # This file is automatically generated by ucm2tests.tcl. # Edits will be overwritten on next generation. # | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 |
# This file is automatically generated by ucm2tests.tcl.
# Edits will be overwritten on next generation.
#
# Tests comparing Tcl encodings to ICU.
# This file is NOT standalone. It should be sourced into a test script.
proc ucmConvertfromMismatches {enc map} {
set mismatches {}
foreach {unihex hex} $map {
set unihex [string range 00000000$unihex end-7 end]; # Make 8 digits
set unich [subst "\\U$unihex"]
if {[encoding convertfrom -profile strict $enc [binary decode hex $hex]] ne $unich} {
|
| ︙ | ︙ |
Deleted tests/idna.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tests/info.test.
| ︙ | ︙ | |||
651 652 653 654 655 656 657 |
catch {namespace delete x}
} -body {
namespace eval x info vars foo
} -cleanup {
namespace delete x
} -result {}
| | | | | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
catch {namespace delete x}
} -body {
namespace eval x info vars foo
} -cleanup {
namespace delete x
} -result {}
set functions {abs acos asin atan atan2 bool ceil cos cosh double entier exp floor fmod hypot int isfinite isinf isnan isnormal isqrt issubnormal isunordered log log10 max min pow rand round sin sinh sqrt srand tan tanh wide}
# Check whether the extra testing functions are defined...
if {!([catch {expr {T1()}} msg] && ($msg eq {invalid command name "tcl::mathfunc::T1"}))} {
set functions "T1 T2 T3 $functions" ;# A lazy way of prepending!
}
test info-20.1 {info functions option} {info functions sin} sin
test info-20.2 {info functions option} {lsort [info functions]} $functions
test info-20.3 {info functions option} {
lsort [info functions a*]
} {abs acos asin atan atan2}
test info-20.4 {info functions option} {
lsort [info functions *tan*]
} {atan atan2 tan tanh}
test info-20.5 {info functions option} -returnCodes error -body {
info functions raise an error
} -result {wrong # args: should be "info functions ?pattern?"}
unset functions msg
test info-21.1 {miscellaneous error conditions} -returnCodes error -body {
info
|
| ︙ | ︙ | |||
731 732 733 734 735 736 737 |
incr level -1
}
return $res
}
test info-22.0 {info frame, levels} {!singleTestInterp} {
info frame
| | | | | | | | | | | 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
incr level -1
}
return $res
}
test info-22.0 {info frame, levels} {!singleTestInterp} {
info frame
} 7
test info-22.1 {info frame, bad level relative} {!singleTestInterp} {
# catch is another level!, i.e. we have 8, not 7
catch {info frame -8} msg
set msg
} {bad level "-8"}
test info-22.2 {info frame, bad level absolute} {!singleTestInterp} {
# catch is another level!, i.e. we have 8, not 7
catch {info frame 9} msg
set msg
} {bad level "9"}
test info-22.3 {info frame, current, relative} -match glob -body {
info frame 0
} -result {type source line 750 file */info.test cmd {info frame 0} proc ::tcltest::RunTest}
test info-22.4 {info frame, current, relative, nested} -match glob -body {
set res [info frame 0]
} -result {type source line 753 file */info.test cmd {info frame 0} proc ::tcltest::RunTest} -cleanup {unset res}
test info-22.5 {info frame, current, absolute} -constraints {!singleTestInterp} -match glob -body {
reduce [info frame 7]
} -result {type source line 756 file info.test cmd {info frame 7} proc ::tcltest::RunTest}
test info-22.6 {info frame, global, relative} {!singleTestInterp} {
reduce [info frame -6]
} {type source line 758 file info.test cmd test\ info-22.6\ \{info\ frame,\ global,\ relative\}\ \{!singleTestInter level 0}
test info-22.7 {info frame, global, absolute} {!singleTestInterp} {
reduce [info frame 1]
} {type source line 761 file info.test cmd test\ info-22.7\ \{info\ frame,\ global,\ absolute\}\ \{!singleTestInter level 0}
test info-22.8 {info frame, basic trace} -match glob -body {
join [lrange [etrace] 0 2] \n
} -result {* {type source line 730 file info.test cmd {info frame $level} proc ::etrace level 0}
|
| ︙ | ︙ | |||
2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 |
demo
} -cleanup {
unset -nocomplain body
rename demo {}
rename probe {}
} -result 3
test info-41.0 {Bug 0de6c1d79c crash} -setup {
interp create child
child hide info
} -body {
list [child invokehidden info frame] \
[child invokehidden info frame 0] \
[child invokehidden info frame 1] \
| > > > > > > > > > > > > > | 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 |
demo
} -cleanup {
unset -nocomplain body
rename demo {}
rename probe {}
} -result 3
test info-39.3 {Bug [e533296a92d89044]: no segfault, nested lambda invocation doesn't remove info from stack} -setup {
set ::res {}
proc probe {s} {
lappend ::res [dict filter [info frame -1] key {[cl]*m*d*}]
catch {apply {{s} {eval $s}} $s}
}
} -body {
probe {catch {probe {error X}}; probe {}}
set ::res
} -cleanup {
unset -nocomplain ::res
} -result {{cmd {probe {catch {probe {error X}}; probe {}}}} {cmd {probe {error X}} lambda {{s} {eval $s}}} {cmd {probe {}} lambda {{s} {eval $s}}}}
test info-41.0 {Bug 0de6c1d79c crash} -setup {
interp create child
child hide info
} -body {
list [child invokehidden info frame] \
[child invokehidden info frame 0] \
[child invokehidden info frame 1] \
|
| ︙ | ︙ |
Changes to tests/init.test.
| ︙ | ︙ | |||
235 236 237 238 239 240 241 |
list $code $foo $bar $code2 $foo2 $bar2
} -cleanup {
unset ::auto_index(::xxx)
} -match glob -result {2 xxx {-errorcode NONE -code 1 -level 1} 2 xxx {-code 1 -level 1 -errorcode NONE}}
cleanupTests
} ;# End of [interp eval $testInterp]
| < < < < < < < < < < < < < | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
list $code $foo $bar $code2 $foo2 $bar2
} -cleanup {
unset ::auto_index(::xxx)
} -match glob -result {2 xxx {-errorcode NONE -code 1 -level 1} 2 xxx {-code 1 -level 1 -errorcode NONE}}
cleanupTests
} ;# End of [interp eval $testInterp]
# cleanup
interp delete $testInterp
::tcltest::cleanupTests
return
# Local Variables:
|
| ︙ | ︙ |
Changes to tests/interp.test.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 |
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
| < | < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testinterpdelete [llength [info commands testinterpdelete]]
set hidden_cmds [list {*}{
cd encoding exec exit fconfigure file glob load open pwd socket source
tcl:encoding:dirs tcl:encoding:system
tcl:file:atime tcl:file:attributes tcl:file:copy tcl:file:delete
tcl:file:dirname tcl:file:executable tcl:file:exists tcl:file:extension
tcl:file:home tcl:file:isdirectory tcl:file:isfile tcl:file:link
tcl:file:lstat tcl:file:mkdir tcl:file:mtime tcl:file:nativename
tcl:file:normalize tcl:file:owned tcl:file:readable tcl:file:readlink
|
| ︙ | ︙ | |||
65 66 67 68 69 70 71 |
# Part 0: Check out options for interp command
test interp-1.1 {options for interp command} -returnCodes error -body {
interp
} -result {wrong # args: should be "interp cmd ?arg ...?"}
test interp-1.2 {options for interp command} -returnCodes error -body {
interp frobox
| | | | | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# Part 0: Check out options for interp command
test interp-1.1 {options for interp command} -returnCodes error -body {
interp
} -result {wrong # args: should be "interp cmd ?arg ...?"}
test interp-1.2 {options for interp command} -returnCodes error -body {
interp frobox
} -result {bad option "frobox": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.3 {options for interp command} {
interp delete
} ""
test interp-1.4 {options for interp command} -returnCodes error -body {
interp delete foo bar
} -result {could not find interpreter "foo"}
test interp-1.5 {options for interp command} -returnCodes error -body {
interp exists foo bar
} -result {wrong # args: should be "interp exists ?path?"}
#
# test interp-0.6 was removed
#
test interp-1.6 {options for interp command} -returnCodes error -body {
interp children foo bar zop
} -result {wrong # args: should be "interp children ?path?"}
test interp-1.7 {options for interp command} -returnCodes error -body {
interp hello
} -result {bad option "hello": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.8 {options for interp command} -returnCodes error -body {
interp -froboz
} -result {bad option "-froboz": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.9 {options for interp command} -returnCodes error -body {
interp -froboz -safe
} -result {bad option "-froboz": must be alias, aliases, bgerror, cancel, children, create, debug, delete, eval, exists, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, recursionlimit, share, target, or transfer}
test interp-1.10 {options for interp command} -returnCodes error -body {
interp target
} -result {wrong # args: should be "interp target path alias"}
test interp-1.11 {options for interp child command} -returnCodes error -setup {
interp create child
} -body {
child gorp
} -cleanup {
interp delete child
} -result {bad option "gorp": must be alias, aliases, bgerror, debug, eval, expose, hide, hidden, issafe, invokehidden, limit, marktrusted, or recursionlimit}
# Part 1: Basic interpreter creation tests:
test interp-2.1 {basic interpreter creation} {
interp create a
} a
test interp-2.2 {basic interpreter creation} {
catch {interp create}
|
| ︙ | ︙ | |||
3754 3755 3756 3757 3758 3759 3760 |
interp debug {} -frames
} -returnCodes error -result {bad debug option "-frames": must be -frame}
test interp-38.8 {interp debug basic setup} -body {
interp debug {} -frame 0 bogus
} -returnCodes {
error
} -result {wrong # args: should be "interp debug path ?-frame ?bool??"}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 |
interp debug {} -frames
} -returnCodes error -result {bad debug option "-frames": must be -frame}
test interp-38.8 {interp debug basic setup} -body {
interp debug {} -frame 0 bogus
} -returnCodes {
error
} -result {wrong # args: should be "interp debug path ?-frame ?bool??"}
# cleanup
unset -nocomplain hidden_cmds
foreach i [interp children] {
interp delete $i
}
rename _ms_limit_args {}
|
| ︙ | ︙ |
Changes to tests/io.test.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
testConstraint testbytestring [llength [info commands testbytestring]]
testConstraint testchannel [llength [info commands testchannel]]
testConstraint testfevent [llength [info commands testfevent]]
testConstraint testchannelevent [llength [info commands testchannelevent]]
testConstraint testmainthread [llength [info commands testmainthread]]
testConstraint testobj [llength [info commands testobj]]
testConstraint testservicemode [llength [info commands testservicemode]]
# Some things fail under Windows in Continuous Integration systems for subtle
# reasons such as CI often running with elevated privileges in a container.
testConstraint notWinCI [expr {
$::tcl_platform(platform) ne "windows" || ![info exists ::env(CI)]}]
testConstraint notOSX [expr {$::tcl_platform(os) ne "Darwin"}]
# File permissions broken on wsl without some "exotic" wsl configuration
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
| > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
testConstraint testbytestring [llength [info commands testbytestring]]
testConstraint testchannel [llength [info commands testchannel]]
testConstraint testfevent [llength [info commands testfevent]]
testConstraint testchannelevent [llength [info commands testchannelevent]]
testConstraint testmainthread [llength [info commands testmainthread]]
testConstraint testobj [llength [info commands testobj]]
testConstraint testservicemode [llength [info commands testservicemode]]
testConstraint notInCIenv [expr {![info exists ::env(CI)]}]
# Some things fail under Windows in Continuous Integration systems for subtle
# reasons such as CI often running with elevated privileges in a container.
testConstraint notWinCI [expr {
$::tcl_platform(platform) ne "windows" || ![info exists ::env(CI)]}]
testConstraint notOSX [expr {$::tcl_platform(os) ne "Darwin"}]
# File permissions broken on wsl without some "exotic" wsl configuration
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
|
| ︙ | ︙ | |||
2928 2929 2930 2931 2932 2933 2934 |
close $f
after 100
set f [open $path(test3) r]
set x [read $f]
close $f
set x
} "Line 1\nLine 2\n"
| | | 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 |
close $f
after 100
set f [open $path(test3) r]
set x [read $f]
close $f
set x
} "Line 1\nLine 2\n"
test io-29.26 {Tcl_Flush, Tcl_Write on bidirectional pipelines} {stdio unixExecs notInCIenv} {
set f [open "|[list cat -u]" r+]
puts $f "Line1"
flush $f
set x [gets $f]
close $f
set x
} {Line1}
|
| ︙ | ︙ |
Deleted tests/lfilter.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tests/listObj.test.
| ︙ | ︙ | |||
236 237 238 239 240 241 242 |
uplevel 1 $script
set tmp $end
set end [lindex [split [memory info] \n] 3 3]
}
expr {$end - $tmp}
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
uplevel 1 $script
set tmp $end
set end [lindex [split [memory info] \n] 3 3]
}
expr {$end - $tmp}
}
test listobj-12.1 {Tcl_ListObjIndex memory leaks for native lists} -constraints {
testobj memory
} -body {
list [listobjmemcheck {
testobj set 1 [lrepeat 1000 x]
set errorMessage [testlistobj indexmemcheck 1]
testobj freeallvars
}] $errorMessage
} -result {0 {}}
test listobj-12.2 {Tcl_ListObjIndex memory leaks for native lists with spans} -constraints {
testobj memory
} -body {
list [listobjmemcheck {
testobj set 1 [testlistrep new 1000 100 100]
set errorMessage [testlistobj indexmemcheck 1]
testobj freeallvars
}] $errorMessage
} -result {0 {}}
test listobj-12.3 {Tcl_ListObjIndex memory leaks for lseq} -constraints {
testobj memory
} -body {
list [listobjmemcheck {
testobj set 1 [lseq 1000]
set errorMessage [testlistobj indexmemcheck 1]
testobj freeallvars
}] $errorMessage
} -result {0 {}}
test listobj-13.1 {Tcl_ListObjGetElements memory leaks for native lists} -constraints {
testobj memory
} -body {
list [listobjmemcheck {
testobj set 1 [lrepeat 1000 x]
set errorMessage [testlistobj getelementsmemcheck 1]
testobj freeallvars
}] $errorMessage
} -result {0 {}}
test listobj-13.2 {Tcl_ListObjElements memory leaks for native lists with spans} -constraints {
testobj memory
} -body {
list [listobjmemcheck {
testobj set 1 [testlistrep new 1000 100 100]
set errorMessage [testlistobj getelementsmemcheck 1]
testobj freeallvars
}] $errorMessage
} -result {0 {}}
test listobj-13.3 {Tcl_ListObjElements memory leaks for lseq} -constraints {
testobj memory
} -body {
list [listobjmemcheck {
testobj set 1 [lseq 1000]
set errorMessage [testlistobj getelementsmemcheck 1]
testobj freeallvars
}] $errorMessage
} -result {0 {}}
# Tests for Tcl_ListObjIndex as sematics are different from lindex for
# out of bounds indices. Out of bounds should return a null pointer and
# not empty string.
test listobj-14.1 {Tcl_ListObjIndex out-of-bounds index for native lists} -constraints {
testobj
} -setup {
testobj set 1 [list a b c]
} -cleanup {
testobj freeallvars
} -body {
list [testlistobj index 1 -1] [testlistobj index 1 3]
} -result {null null}
test listobj-14.2 {Tcl_ListObjIndex out-of-bounds index for native lists with spans} -constraints {
testobj
} -setup {
testobj set 1 [testlistrep new 1000 100 100]
} -cleanup {
testobj freeallvars
} -body {
list [testlistobj index 1 -1] [testlistobj index 1 1000]
} -result {null null}
test listobj-14.3 {Tcl_ListObjIndex out-of-bounds index for lseq} -constraints {bug_30e4e9102f testobj} -setup {
testobj set 1 [lseq 3]
} -cleanup {
testobj freeallvars
} -body {
list [testlistobj index 1 -1] [testlistobj index 1 3]
} -result {null null}
# cleanup
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
|
| ︙ | ︙ |
Changes to tests/listRep.test.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testlistrep [llength [info commands testlistrep]]
proc describe {l args} {dict get [testlistrep describe $l] {*}$args}
proc irange {first last} {
| < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testlistrep [llength [info commands testlistrep]]
proc describe {l args} {dict get [testlistrep describe $l] {*}$args}
proc irange {first last} {
set l {}
while {$first <= $last} {
lappend l $first
incr first
}
return $l
}
|
| ︙ | ︙ |
Deleted tests/listTypes.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tests/load.test.
| ︙ | ︙ | |||
132 133 134 135 136 137 138 |
test load-5.1 {file name not specified and no static package: pick default} -setup {
catch {interp delete x}
interp create x
} -constraints [list $dll $loaded] -body {
load -global [file join $testDir tcl9pkga$ext] Pkga
load {} Pkga x
| < < | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
test load-5.1 {file name not specified and no static package: pick default} -setup {
catch {interp delete x}
interp create x
} -constraints [list $dll $loaded] -body {
load -global [file join $testDir tcl9pkga$ext] Pkga
load {} Pkga x
info loaded x
} -cleanup {
interp delete x
} -result [list [list [file join $testDir tcl9pkga$ext] Pkga]]
test load-6.1 {errors loading file} [list $dll $loaded] {
catch {load foo foo}
} {1}
|
| ︙ | ︙ |
Changes to tests/lpop.test.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 |
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
unset -nocomplain no; # following tests expecting var "no" does not exists
| | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | | | < | | | | < < < < < < < < < < < < < < < < < < < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
unset -nocomplain no; # following tests expecting var "no" does not exists
test lpop-1.1 {error conditions} -returnCodes error -body {
lpop no
} -result {can't read "no": no such variable}
test lpop-1.2 {error conditions} -returnCodes error -body {
lpop no 0
} -result {can't read "no": no such variable}
test lpop-1.3 {error conditions} -returnCodes error -body {
set l "x {}x"
lpop l
} -result {list element in braces followed by "x" instead of space}
test lpop-1.4 {error conditions} -returnCodes error -body {
set l "x y"
lpop l -1
} -result {index "-1" out of range}
test lpop-1.4b {error conditions (also check SF on empty list variable, bug [234d6c811d])} -body {
set l "x y"
list [lpop l] [lpop l] [catch {lpop l} v] $v [catch {lpop l 0} v] $v $l
} -result {y x 1 {index "end" out of range} 1 {index "0" out of range} {}}
test lpop-1.5 {error conditions} -returnCodes error -body {
set l "x y z"
lpop l 3
} -result {index "3" out of range} ;#-errorCode {TCL OPERATION LPOP BADINDEX}
test lpop-1.6 {error conditions} -returnCodes error -body {
set l "x y"
lpop l end+1
} -result {index "end+1" out of range}
test lpop-1.7 {error conditions} -returnCodes error -body {
set l "x y"
lpop l {}
} -match glob -result {bad index *}
test lpop-1.8 {error conditions} -returnCodes error -body {
set l "x y"
lpop l 0 0 0 0 1
} -result {index "1" out of range}
test lpop-1.9 {error conditions} -returnCodes error -body {
set l "x y"
lpop l {1 0}
} -match glob -result {bad index *}
test lpop-2.1 {basic functionality} -body {
set l "x y z"
list [lpop l 0] $l
} -result {x {y z}}
test lpop-2.2 {basic functionality} -body {
set l "x y z"
list [lpop l 1] $l
} -result {y {x z}}
test lpop-2.3 {basic functionality} -body {
set l "x y z"
list [lpop l] $l
} -result {z {x y}}
test lpop-2.4 {basic functionality} -body {
set l "x y z"
set l2 $l
list [lpop l] $l $l2
} -result {z {x y} {x y z}}
test lpop-3.1 {nested} -body {
set l "x y"
set l2 $l
list [lpop l 0 0 0 0] $l $l2
} -result {x {{{{}}} y} {x y}}
test lpop-3.2 {nested} -body {
set l "{x y} {a b}"
list [lpop l 0 1] $l
} -result {y {x {a b}}}
test lpop-3.3 {nested} -body {
set l "{x y} {a b}"
list [lpop l 1 0] $l
} -result {a {{x y} b}}
test lpop-99.1 {performance} -constraints perf -body {
set l [lrepeat 10000 x]
set l2 $l
set t1 [time {
while {[llength $l] >= 2} {
lpop l end
|
| ︙ | ︙ | |||
214 215 216 217 218 219 220 |
while {[llength $l] >= 2} {
lpop l 1
}
}]
regexp {\d+} $t1 ms1
regexp {\d+} $t2 ms2
set ratio [expr {double($ms2)/$ms1}]
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
while {[llength $l] >= 2} {
lpop l 1
}
}]
regexp {\d+} $t1 ms1
regexp {\d+} $t2 ms2
set ratio [expr {double($ms2)/$ms1}]
expr {$ratio > 10 ? $ratio : 10}
} -result {10}
# cleanup
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
# End:
|
Changes to tests/lrange.test.
| ︙ | ︙ | |||
182 183 184 185 186 187 188 |
set ll1 [list $tcl_version 2 3 4]
# With string rep
string length $ll1
set rep1 [tcl::unsupported::representation $ll1]
# Get pure object, unshared
set ll2 [lrange $ll1[set ll1 {}] 0 end]
set rep2 [tcl::unsupported::representation $ll2]
| > > | | > > | | | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
set ll1 [list $tcl_version 2 3 4]
# With string rep
string length $ll1
set rep1 [tcl::unsupported::representation $ll1]
# Get pure object, unshared
set ll2 [lrange $ll1[set ll1 {}] 0 end]
set rep2 [tcl::unsupported::representation $ll2]
regexp {object pointer at (\S+)} $rep1 -> obj1
regexp {object pointer at (\S+)} $rep2 -> obj2
list $rep1 $rep2 [string equal $obj1 $obj2]
# Internal optimisations should keep the same object
} -match glob -result {*value is *refcount of 2,*, string rep*value is*refcount of 2,* no string rep* 1}
test lrange-4.4 {lrange pure promise} -body {
set ll1 [list $tcl_version 2 3 4]
# With string rep
string length $ll1
set rep1 [tcl::unsupported::representation $ll1]
# Get pure object, unshared, not compiled
set ll2 [[string cat l range] $ll1[set ll1 {}] 0 end]
set rep2 [tcl::unsupported::representation $ll2]
regexp {object pointer at (\S+)} $rep1 -> obj1
regexp {object pointer at (\S+)} $rep2 -> obj2
list $rep1 $rep2 [string equal $obj1 $obj2]
# Internal optimisations should keep the same object
} -match glob -result {*value is *refcount of 2,*, string rep*value is*refcount of 2,* no string rep* 1}
# Testing for compiled vs non-compiled behaviour, and shared vs non-shared.
# Far too many variations to check with spelt-out tests.
# Note that this *just* checks whether the different versions are the same
# not whether any of them is correct.
apply {{} {
set lss {{} {a} {a b c} {a b c d}}
|
| ︙ | ︙ |
Changes to tests/lseq.test.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 |
}
testConstraint arithSeriesDouble 1
testConstraint arithSeriesShimmer 1
testConstraint arithSeriesShimmerOk 1
testConstraint has64BitLengths [expr {$tcl_platform(pointerSize) == 8}]
testConstraint has32BitLengths [expr {$tcl_platform(pointerSize) == 4}]
| < < < < < < < < < < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
}
testConstraint arithSeriesDouble 1
testConstraint arithSeriesShimmer 1
testConstraint arithSeriesShimmerOk 1
testConstraint has64BitLengths [expr {$tcl_platform(pointerSize) == 8}]
testConstraint has32BitLengths [expr {$tcl_platform(pointerSize) == 4}]
testConstraint TIP746 0 ;# Obsolete expr behavior in lseq on numeric arguments
proc memusage {} {
set fd [open /proc/[pid]/statm]
set line [gets $fd]
if {[llength $line] != 7} {
error "Unexpected /proc/pid/statm format"
}
close $fd
return [lindex $line 5]
}
testConstraint hasMemUsage [expr {![catch {memusage}]}]
# Arg errors
test lseq-1.1 {error cases} -body {
lseq
} \
-returnCodes 1 \
-result {wrong # args: should be "lseq n ??op? n ??by? n??"}
|
| ︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 |
trace add variable var1 write [list ::apply [list args {
error {this is an error}
} [namespace current]]]
list [catch {set var1 [lindex [lreplace [lseq 1 2] 1 1 hello] 0]} cres] $cres
} -cleanup {unset var1 cres} -result {1 {can't set "var1": this is an error}}
test lseq-bug-54329e39c7 {does not cause memory bloat} -constraints {
| | < < > < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < | | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
trace add variable var1 write [list ::apply [list args {
error {this is an error}
} [namespace current]]]
list [catch {set var1 [lindex [lreplace [lseq 1 2] 1 1 hello] 0]} cres] $cres
} -cleanup {unset var1 cres} -result {1 {can't set "var1": this is an error}}
test lseq-bug-54329e39c7 {does not cause memory bloat} -constraints {
hasMemUsage
} -body {
set l [lseq 1000000]
proc p l {foreach x $l {}}
set premem [memusage]
p $l
set postmem [memusage]
expr {[tcl::build-info purify] || ($postmem - $premem < 10) ? 1 : ($postmem - $premem)}
} -result 1
test lseq-bug-578b7e273c03-1 {Arithmetic Series Objects get wrong precision when end value is not specified} -body {
set bl [expr {2.8 in [lseq 0 count 100 by .1]}]
lappend bl [expr {2.8 in [lseq 0 count 200 by .1]}]
lappend bl [expr {0.28 in [lseq 0 count 100 by .01]}]
lappend bl [expr {0.28 in [lseq 0 count 200 by .01]}]
lappend bl [expr {0.286 in [lseq 0 count 100 by .011]}]
lappend bl [expr {0.286 in [lseq 0 count 200 by .011]}]
} -result {1 1 1 1 1 1}
test lseq-bug-578b7e273c03-2 {Arithmetic Series Objects get wrong precision when end value is not specified} -body {
set ll [llength [lseq 0 count 100 by .1]]
lappend ll [llength [lseq 0 count 200 by .1]]
lappend ll [llength [lseq 0 count 100 by .01]]
lappend ll [llength [lseq 0 count 200 by .01]]
lappend ll [llength [lseq 0 count 100 by .011]]
lappend ll [llength [lseq 0 count 200 by .011]]
} -result {100 200 100 200 100 200}
test lseq-bug-f4a4bd7f1070-1 {} -body {
set result {}
lappend result [catch {lseq 3.1} msg]
lappend result $msg
lappend result [catch {lseq 5 count 3.0} msg]
lappend result $msg
lappend result [lseq 3]
lappend result [lseq 3.0]
|
| ︙ | ︙ |
Changes to tests/main.test.
| ︙ | ︙ | |||
230 231 232 233 234 235 236 |
exec [interpreter] script -appinitprocdeleteinterp >& result
set f [open result]
read $f
} -cleanup {
close $f
file delete result
removeFile script
| | | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
exec [interpreter] script -appinitprocdeleteinterp >& result
set f [open result]
read $f
} -cleanup {
close $f
file delete result
removeFile script
} -result "application-specific initialization failed: \n"
test Tcl_Main-2.4 {
Tcl_Main: appInitProc deletes interp
} -constraints {
exec tcl::test
} -body {
exec [interpreter] << {puts "In script"} \
-appinitprocdeleteinterp >& result
set f [open result]
read $f
} -cleanup {
close $f
file delete result
} -result "application-specific initialization failed: \n"
test Tcl_Main-2.5 {
Tcl_Main: appInitProc closes stderr
} -constraints {
exec tcl::test
} -body {
exec [interpreter] << {puts "In script"} \
|
| ︙ | ︙ |
Deleted tests/mathfunc.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tests/mutex.test.
1 2 3 4 5 6 | # Commands covered: (test)mutex # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Commands covered: (test)mutex
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands. Sourcing this file into Tcl runs the tests and
# generates output for errors. No output means no errors were found.
#
# Copyright (c) 2025 Ashok P. Nadkarni
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
|
| ︙ | ︙ |
Changes to tests/nre.test.
| ︙ | ︙ | |||
31 32 33 34 35 36 37 |
# [testnrelevels] returns a 6-list with: C-stack depth, iPtr->numlevels,
# cmdFrame level, callFrame level, tosPtr and callback depth
#
variable last [testnrelevels]
proc depthDiff {} {
variable last
set depth [testnrelevels]
| > | > > | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# [testnrelevels] returns a 6-list with: C-stack depth, iPtr->numlevels,
# cmdFrame level, callFrame level, tosPtr and callback depth
#
variable last [testnrelevels]
proc depthDiff {} {
variable last
set depth [testnrelevels]
set res {}
foreach t $depth l $last {
lappend res [expr {$t-$l}]
}
set last $depth
return $res
}
proc setabs {} {
variable abs [- [lindex [testnrelevels] 0]]
}
|
| ︙ | ︙ | |||
211 212 213 214 215 216 217 |
testnrelevels
} -result {{0 2 2 0} 0}
test nre-6.2 {[uplevel] is not recursive} -setup {
setabs
proc a i [makebody {uplevel 1 "set x $i; a $i"}]
} -body {
a 0
| < < < < < < < < < < | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
testnrelevels
} -result {{0 2 2 0} 0}
test nre-6.2 {[uplevel] is not recursive} -setup {
setabs
proc a i [makebody {uplevel 1 "set x $i; a $i"}]
} -body {
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 0} 0}
test nre-7.1 {[catch] is not recursive} -setup {
|
| ︙ | ︙ |
Changes to tests/oo.test.
| ︙ | ︙ | |||
2790 2791 2792 2793 2794 2795 2796 |
set obj [cls new]
set id [info object creationid $obj]
rename $obj gorp
set id2 [info object creationid gorp]
list $id $id2
} -cleanup {
cls destroy
| < | 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 |
set obj [cls new]
set id [info object creationid $obj]
rename $obj gorp
set id2 [info object creationid gorp]
list $id $id2
} -cleanup {
cls destroy
} -result {^(\d+) \1$} -match regexp
test oo-16.17 {OO: object introspection: creationid #500} -body {
info object creationid nosuchobject
} -returnCodes error -result {nosuchobject does not refer to an object}
test oo-16.18 {OO: object introspection: creationid #500} -body {
info object creationid
} -returnCodes error -result {wrong # args: should be "info object creationid objName"}
|
| ︙ | ︙ |
Changes to tests/ooUtil.test.
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
unexport find
}
set t [Table new]
$t find 1 2 3
} -returnCodes error -cleanup {
parent destroy
} -match glob -result {unknown method "find": must be *}
| | | 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
unexport find
}
set t [Table new]
$t find 1 2 3
} -returnCodes error -cleanup {
parent destroy
} -match glob -result {unknown method "find": must be *}
test ooUtil-1.7 {} -setup {
oo::class create parent
} -body {
oo::class create Foo {
superclass parent
classmethod bar {} {
puts "This is in the class; self is [self]"
my meee
|
| ︙ | ︙ |
Changes to tests/package.test.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
set auto_path ""
testConstraint testpreferstable [llength [info commands testpreferstable]]
testConstraint isStaticBuild [expr {
[string first static [tcl::build-info]] >= 0
}]
test package-1.1 {pkg::create gives error on insufficient args} -body {
::pkg::create
} -returnCodes error -match glob -result {wrong # args: should be "*"}
test package-1.2 {pkg::create gives error on bad args} -body {
::pkg::create -foo bar -bar baz -baz boo
} -returnCodes error -match glob -result {unknown option "bar": *}
test package-1.3 {pkg::create gives error on no value given} -body {
| > | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
set auto_path ""
testConstraint testpreferstable [llength [info commands testpreferstable]]
testConstraint isStaticBuild [expr {
[string first static [tcl::build-info]] >= 0
}]
test package-1.1 {pkg::create gives error on insufficient args} -body {
::pkg::create
} -returnCodes error -match glob -result {wrong # args: should be "*"}
test package-1.2 {pkg::create gives error on bad args} -body {
::pkg::create -foo bar -bar baz -baz boo
} -returnCodes error -match glob -result {unknown option "bar": *}
test package-1.3 {pkg::create gives error on no value given} -body {
|
| ︙ | ︙ | |||
1388 1389 1390 1391 1392 1393 1394 |
Bug 4f06d7ca08 - package require static package in secondary interp
} -constraints {win isStaticBuild} -setup {
set ip [interp create]
} -cleanup {
interp delete $ip
unset -nocomplain ip
} -body {
| | | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 |
Bug 4f06d7ca08 - package require static package in secondary interp
} -constraints {win isStaticBuild} -setup {
set ip [interp create]
} -cleanup {
interp delete $ip
unset -nocomplain ip
} -body {
$ip eval {package require registry}
} -result {\d+.\d+.\d+} -match regexp
rename prefer {}
set auto_path $oldPath
package unknown $oldPkgUnknown
|
| ︙ | ︙ |
Changes to tests/reg.test.
| ︙ | ︙ | |||
1191 1192 1193 1194 1195 1196 1197 |
test reg-33.21 {constraint fixes} {
regexp {(^(?!aa)(?!bb)(?!cc))+} {cc x}
} 0
test reg-33.22 {constraint fixes} {
regexp {(^(?!aa)(?!bb)(?!cc))+} {dd x}
} 1
| | | | | | | | | 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 |
test reg-33.21 {constraint fixes} {
regexp {(^(?!aa)(?!bb)(?!cc))+} {cc x}
} 0
test reg-33.22 {constraint fixes} {
regexp {(^(?!aa)(?!bb)(?!cc))+} {dd x}
} 1
test reg-33.23 {} {
regexp {abcd(\m)+xyz} x
} 0
test reg-33.24 {} {
regexp {abcd(\m)+xyz} a
} 0
test reg-33.25 {} {
regexp {^abcd*(((((^(a c(e?d)a+|)+|)+|)+|)+|a)+|)} x
} 0
test reg-33.26 {} {
regexp {a^(^)bcd*xy(((((($a+|)+|)+|)+$|)+|)+|)^$} x
} 0
test reg-33.27 {} {
regexp {xyz(\Y\Y)+} x
} 0
test reg-33.28 {} {
regexp {x|(?:\M)+} x
} 1
test reg-33.29 {} {
# This is near the limits of the RE engine
regexp [string repeat x*y*z* 480] x
} 1
test reg-33.30 {Bug 1080042} {
regexp {(\Y)+} foo
} 1
|
| ︙ | ︙ |
Changes to tests/registry.test.
|
| | | | | > < | > > | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | > | | | | > | | | | | | > > > > > > > > > < < < < < < < < < < | | < | | | | < | > | | | < | | | | < | | < | > | | | < | | | | < | > | | | < | | | | < | | < | > | | < < | | < | > | | | < | | < | | > | | < | | | | < | > | | | < | | | | < | > | | | < | | | | < | > | | | < | | | | < | > | | > > | | | > | | > | | > | | | < | | | < < | | < < | | < < | | < | | > | < < | | < | | > | < < | | < < < < | > | > | | < | > | | < < | | < | > | | < < | | < | > | | < < | < < < < < < < < | < | | > | > > | > | > | | < | > | | < < | | < | > | | < < | | < < < < < < < < < | | > > > > > > > | | < | | | < < | | < < | | < < | | < | > | | < < | | < | > | | < < | | < | > | | < < | | < | > | | < < | | < | | > | < < | | < | | > | < < | | > > | < < | < < | | < | | > | < < | | < | > | | < < | | < | > | | < < | | < | | > | < < | | < | | > | < < | | < | | > | < < | | < | | > | < < | | < | > | | < < | | < | > | | < < | | < | > | | < < | | < | > | | < < | | < | > | | | | > < | | | < | | | > | | | < < | | < | > | > < | | | < | | | > | | | < | | | > | | | > | | | | | > < | | | | | | | | | | | | | | | | | | > | < | | > | | | > | | | | < < | | > | | | | | < < | | > > | | | | | | | | | | | | < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
# registry.test --
#
# This file contains a collection of tests for the registry command.
# Sourcing this file into Tcl runs the tests and generates output for
# errors. No output means no errors were found.
#
# In order for these tests to run, the registry package must be on the
# auto_path or the registry package must have been loaded already.
#
# Copyright © 1997 Sun Microsystems, Inc. All rights reserved.
# Copyright © 1998-1999 Scriptics Corporation.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
testConstraint reg 0
if {[testConstraint win]} {
if {![catch {
::tcltest::loadTestedCommands
set ::regver [package require registry 1.3.7]
}]} {
testConstraint reg 1
}
}
testConstraint notWine [expr {![info exists ::env(CI_USING_WINE)]}]
# determine the current locale
testConstraint english [expr {
[llength [info commands testlocale]]
&& [string match "English*" [testlocale all ""]]
}]
test registry-1.0 {check if we are testing the right dll} {win reg} {
set ::regver
} {1.3.7}
test registry-1.1 {argument parsing for registry command} {win reg} {
list [catch {registry} msg] $msg
} {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}}
test registry-1.1a {argument parsing for registry command} {win reg} {
list [catch {registry -32bit} msg] $msg
} {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}}
test registry-1.1b {argument parsing for registry command} {win reg} {
list [catch {registry -64bit} msg] $msg
} {1 {wrong # args: should be "registry ?-32bit|-64bit? option ?arg ...?"}}
test registry-1.2 {argument parsing for registry command} {win reg} {
list [catch {registry foo} msg] $msg
} {1 {bad option "foo": must be broadcast, delete, get, keys, set, type, or values}}
test registry-1.2a {argument parsing for registry command} {win reg} {
list [catch {registry -33bit foo} msg] $msg
} {1 {bad mode "-33bit": must be -32bit or -64bit}}
test registry-1.3 {argument parsing for registry command} {win reg} {
list [catch {registry d} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}
test registry-1.3a {argument parsing for registry command} {win reg} {
list [catch {registry -32bit d} msg] $msg
} {1 {wrong # args: should be "registry -32bit delete keyName ?valueName?"}}
test registry-1.3b {argument parsing for registry command} {win reg} {
list [catch {registry -64bit d} msg] $msg
} {1 {wrong # args: should be "registry -64bit delete keyName ?valueName?"}}
test registry-1.4 {argument parsing for registry command} {win reg} {
list [catch {registry delete} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}
test registry-1.5 {argument parsing for registry command} {win reg} {
list [catch {registry delete foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry delete keyName ?valueName?"}}
test registry-1.6 {argument parsing for registry command} {win reg} {
list [catch {registry g} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.6a {argument parsing for registry command} {win reg} {
list [catch {registry -32bit g} msg] $msg
} {1 {wrong # args: should be "registry -32bit get keyName valueName"}}
test registry-1.6b {argument parsing for registry command} {win reg} {
list [catch {registry -64bit g} msg] $msg
} {1 {wrong # args: should be "registry -64bit get keyName valueName"}}
test registry-1.7 {argument parsing for registry command} {win reg} {
list [catch {registry get} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.8 {argument parsing for registry command} {win reg} {
list [catch {registry get foo} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.9 {argument parsing for registry command} {win reg} {
list [catch {registry get foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry get keyName valueName"}}
test registry-1.10 {argument parsing for registry command} {win reg} {
list [catch {registry k} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}
test registry-1.10a {argument parsing for registry command} {win reg} {
list [catch {registry -32bit k} msg] $msg
} {1 {wrong # args: should be "registry -32bit keys keyName ?pattern?"}}
test registry-1.10b {argument parsing for registry command} {win reg} {
list [catch {registry -64bit k} msg] $msg
} {1 {wrong # args: should be "registry -64bit keys keyName ?pattern?"}}
test registry-1.11 {argument parsing for registry command} {win reg} {
list [catch {registry keys} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}
test registry-1.12 {argument parsing for registry command} {win reg} {
list [catch {registry keys foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry keys keyName ?pattern?"}}
test registry-1.13 {argument parsing for registry command} {win reg} {
list [catch {registry s} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.13a {argument parsing for registry command} {win reg} {
list [catch {registry -32bit s} msg] $msg
} {1 {wrong # args: should be "registry -32bit set keyName ?valueName data ?type??"}}
test registry-1.13b {argument parsing for registry command} {win reg} {
list [catch {registry -64bit s} msg] $msg
} {1 {wrong # args: should be "registry -64bit set keyName ?valueName data ?type??"}}
test registry-1.14 {argument parsing for registry command} {win reg} {
list [catch {registry set} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.15 {argument parsing for registry command} {win reg} {
list [catch {registry set foo bar} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.16 {argument parsing for registry command} {win reg} {
list [catch {registry set foo bar baz blat gorp} msg] $msg
} {1 {wrong # args: should be "registry set keyName ?valueName data ?type??"}}
test registry-1.17 {argument parsing for registry command} {win reg} {
list [catch {registry t} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.17a {argument parsing for registry command} {win reg} {
list [catch {registry -32bit t} msg] $msg
} {1 {wrong # args: should be "registry -32bit type keyName valueName"}}
test registry-1.17b {argument parsing for registry command} {win reg} {
list [catch {registry -64bit t} msg] $msg
} {1 {wrong # args: should be "registry -64bit type keyName valueName"}}
test registry-1.18 {argument parsing for registry command} {win reg} {
list [catch {registry type} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.19 {argument parsing for registry command} {win reg} {
list [catch {registry type foo} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.20 {argument parsing for registry command} {win reg} {
list [catch {registry type foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry type keyName valueName"}}
test registry-1.21 {argument parsing for registry command} {win reg} {
list [catch {registry v} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}
test registry-1.21a {argument parsing for registry command} {win reg} {
list [catch {registry -32bit v} msg] $msg
} {1 {wrong # args: should be "registry -32bit values keyName ?pattern?"}}
test registry-1.21b {argument parsing for registry command} {win reg} {
list [catch {registry -64bit v} msg] $msg
} {1 {wrong # args: should be "registry -64bit values keyName ?pattern?"}}
test registry-1.22 {argument parsing for registry command} {win reg} {
list [catch {registry values} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}
test registry-1.23 {argument parsing for registry command} {win reg} {
list [catch {registry values foo bar baz} msg] $msg
} {1 {wrong # args: should be "registry values keyName ?pattern?"}}
test registry-2.1 {DeleteKey: bad key} {win reg} {
list [catch {registry delete foo} msg] $msg
} {1 {bad root name "foo": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}}
test registry-2.2 {DeleteKey: bad key} {win reg} {
list [catch {registry delete HKEY_CLASSES_ROOT} msg] $msg
} {1 {bad key: cannot delete root keys}}
test registry-2.3 {DeleteKey: bad key} {win reg} {
list [catch {registry delete HKEY_CLASSES_ROOT\\} msg] $msg
} {1 {bad key: cannot delete root keys}}
test registry-2.4 {DeleteKey: subkey at root level} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar
registry delete HKEY_CURRENT_USER\\TclFoobar
registry keys HKEY_CURRENT_USER TclFoobar
} {}
test registry-2.5 {DeleteKey: subkey below root level} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar\\test
registry delete HKEY_CURRENT_USER\\TclFoobar\\test
set result [registry keys HKEY_CURRENT_USER TclFoobar\\test]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {}
test registry-2.6 {DeleteKey: recursive delete} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar\\test1
registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
registry delete HKEY_CURRENT_USER\\TclFoobar
set result [registry keys HKEY_CURRENT_USER TclFoobar]
set result
} {}
test registry-2.7 {DeleteKey: trailing backslashes} {win reg english} {
registry set HKEY_CURRENT_USER\\TclFoobar\\baz
list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar\\} msg] $msg
} {1 {unable to delete key: The configuration registry key is invalid.}}
test registry-2.8 {DeleteKey: failure} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry delete HKEY_CURRENT_USER\\TclFoobar
} {}
test registry-2.9 {DeleteKey: unicode} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\a
registry set HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar\\b
registry delete HKEY_CURRENT_USER\\TclFoobar\\test\u00c7bar
set result [registry keys HKEY_CURRENT_USER\\TclFoobar]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {}
test registry-3.1 {DeleteValue} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz test1 blort
registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blat
registry delete HKEY_CURRENT_USER\\TclFoobar\\baz test1
set result [registry values HKEY_CURRENT_USER\\TclFoobar\\baz]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} test2
test registry-3.2 {DeleteValue: bad key} {win reg english} {
registry delete HKEY_CURRENT_USER\\TclFoobar
list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar test} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-3.3 {DeleteValue: bad value} {win reg english} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz test2 blort
set result [list [catch {registry delete HKEY_CURRENT_USER\\TclFoobar test1} msg] $msg]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {1 {unable to delete value "test1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}}
test registry-3.4 {DeleteValue: Unicode} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1 blort
registry set HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz test2 blat
registry delete HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz \u00c7test1
set result [registry values HKEY_CURRENT_USER\\TclFoobar\\\u00c7baz]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} test2
test registry-4.1 {GetKeyNames: bad key} {win reg english} {
registry delete HKEY_CURRENT_USER\\TclFoobar
list [catch {registry keys HKEY_CURRENT_USER\\TclFoobar} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-4.2 {GetKeyNames} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz
set result [registry keys HKEY_CURRENT_USER\\TclFoobar]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {baz}
test registry-4.3 {GetKeyNames: remote key} {win reg nonPortable english} {
set hostname [info hostname]
registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar\\baz
set result [registry keys \\\\gaspode\\HKEY_CURRENT_USER\\TclFoobar]
registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
set result
} {baz}
test registry-4.4 {GetKeyNames: empty key} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar
set result [registry keys HKEY_CURRENT_USER\\TclFoobar]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {}
test registry-4.5 {GetKeyNames: patterns} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz
registry set HKEY_CURRENT_USER\\TclFoobar\\blat
registry set HKEY_CURRENT_USER\\TclFoobar\\foo
set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {baz blat}
test registry-4.6 {GetKeyNames: names with spaces} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz\ bar
registry set HKEY_CURRENT_USER\\TclFoobar\\blat
registry set HKEY_CURRENT_USER\\TclFoobar\\foo
set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {{baz bar} blat}
test registry-4.7 {GetKeyNames: Unicode} {win reg english} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u00c7bar
registry set HKEY_CURRENT_USER\\TclFoobar\\blat
registry set HKEY_CURRENT_USER\\TclFoobar\\foo
set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} "baz\u00c7bar blat"
test registry-4.8 {GetKeyNames: Unicode} {win reg} {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz\u30b7bar
registry set HKEY_CURRENT_USER\\TclFoobar\\blat
registry set HKEY_CURRENT_USER\\TclFoobar\\foo
set result [lsort [registry keys HKEY_CURRENT_USER\\TclFoobar b*]]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} "baz\u30b7bar blat"
test registry-4.9 {GetKeyNames: very long key [Bug 1682211]} {*}{
-constraints {win reg}
-setup {
registry set HKEY_CURRENT_USER\\TclFoobar\\a
registry set HKEY_CURRENT_USER\\TclFoobar\\b[string repeat x 254]
registry set HKEY_CURRENT_USER\\TclFoobar\\c
}
-body {
lsort [registry keys HKEY_CURRENT_USER\\TclFoobar]
}
-cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
}} \
-result [list a b[string repeat x 254] c]
test registry-5.1 {GetType} {win reg english} {
registry delete HKEY_CURRENT_USER\\TclFoobar
list [catch {registry type HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-5.2 {GetType} {win reg english} {
registry set HKEY_CURRENT_USER\\TclFoobar
list [catch {registry type HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg
} {1 {unable to get type of value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}}
test registry-5.3 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} none
test registry-5.4 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} sz
test registry-5.5 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} sz
test registry-5.6 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} expand_sz
test registry-5.7 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} binary
test registry-5.8 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} dword
test registry-5.9 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 dword_big_endian
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} dword_big_endian
test registry-5.10 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} link
test registry-5.11 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} multi_sz
test registry-5.12 {GetType} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} resource_list
test registry-5.13 {GetType: unknown types} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24
set result [registry type HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 24
test registry-5.14 {GetType: Unicode} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar va\u00c7l1 1 24
set result [registry type HKEY_CURRENT_USER\\TclFoobar va\u00c7l1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 24
test registry-6.1 {GetValue} {win reg english} {
registry delete HKEY_CURRENT_USER\\TclFoobar
list [catch {registry get HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-6.2 {GetValue} {win reg english} {
registry set HKEY_CURRENT_USER\\TclFoobar
list [catch {registry get HKEY_CURRENT_USER\\TclFoobar val1} msg] $msg
} {1 {unable to get value "val1" from key "HKEY_CURRENT_USER\TclFoobar": The system cannot find the file specified.}}
test registry-6.3 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar none
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} foobar
test registry-6.4 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} foobar
test registry-6.5 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} foobar
test registry-6.6 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar expand_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} foobar
test registry-6.7 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 binary
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 1
test registry-6.8 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 32
test registry-6.9 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 0x20 dword_big_endian
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 32
test registry-6.10 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 link
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 1
test registry-6.11 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 foobar multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} foobar
test registry-6.12 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo\ bar baz} multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {{foo bar} baz}
test registry-6.13 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 {} multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} {}
test registry-6.14 {GetValue: truncation of multivalues with null elements} \
{win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 {a {} b} multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} a
test registry-6.15 {GetValue} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 resource_list
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 1
test registry-6.16 {GetValue: unknown types} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 1 24
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} 1
test registry-6.17 {GetValue: Unicode value names} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val\u00c71 foobar multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val\u00c71]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} foobar
test registry-6.18 {GetValue: values with Unicode strings} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u30b7r baz} multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} "foo ba\u30b7r baz"
test registry-6.19 {GetValue: values with Unicode strings} {win reg english} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u00c7r baz} multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} "foo ba\u00c7r baz"
test registry-6.20 {GetValue: values with Unicode strings with embedded nulls} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u0000r baz} multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} "foo ba r baz"
test registry-6.21 {GetValue: very long value names and values} {win reg} {
registry set HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383] [string repeat x 16383] multi_sz
set result [registry get HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383]]
registry delete HKEY_CURRENT_USER\\TclFoobar
set result
} [string repeat x 16383]
test registry-7.1 {GetValueNames: bad key} -constraints {win reg english} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
registry values HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error -result {unable to open key: The system cannot find the file specified.}
test registry-7.2 {GetValueNames} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar baz foobar
} -body {
registry values HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -result baz
test registry-7.3 {GetValueNames} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1
registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
registry set HKEY_CURRENT_USER\\TclFoobar {} foobar3
} -body {
lsort [registry values HKEY_CURRENT_USER\\TclFoobar]
} -cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {{} baz blat}
test registry-7.4 {GetValueNames: remote key} -constraints {win reg nonPortable english} -body {
set hostname [info hostname]
registry set \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar baz blat
set result [registry values \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar]
registry delete \\\\$hostname\\HKEY_CURRENT_USER\\TclFoobar
set result
} -result baz
test registry-7.5 {GetValueNames: empty key} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar
} -body {
registry values HKEY_CURRENT_USER\\TclFoobar
} -cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}
test registry-7.6 {GetValueNames: patterns} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar baz foobar1
registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3
} -body {
lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {baz blat}
test registry-7.7 {GetValueNames: names with spaces} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar baz\ bar foobar1
registry set HKEY_CURRENT_USER\\TclFoobar blat foobar2
registry set HKEY_CURRENT_USER\\TclFoobar foo foobar3
} -body {
lsort [registry values HKEY_CURRENT_USER\\TclFoobar b*]
} -cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {{baz bar} blat}
test registry-8.1 {OpenSubKey} -constraints {win reg nonPortable english} \
-body {
# This test will only succeed if the current user does not have
# registry access on the specified machine.
registry keys {\\mom\HKEY_LOCAL_MACHINE}
} -returnCodes error -result "unable to open key: Access is denied."
test registry-8.2 {OpenSubKey} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar
} -body {
registry keys HKEY_CURRENT_USER TclFoobar
} -cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {TclFoobar}
test registry-8.3 {OpenSubKey} -constraints {win reg english} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
registry keys HKEY_CURRENT_USER\\TclFoobar
} -returnCodes error \
-result "unable to open key: The system cannot find the file specified."
test registry-9.1 {ParseKeyName: bad keys} -constraints {win reg} -body {
registry values \\
} -returnCodes error -result "bad key \"\\\": must start with a valid root"
test registry-9.2 {ParseKeyName: bad keys} -constraints {win reg} -body {
registry values \\foobar
} -returnCodes error -result {bad key "\foobar": must start with a valid root}
test registry-9.3 {ParseKeyName: bad keys} -constraints {win reg} -body {
registry values \\\\
} -returnCodes error -result {bad root name "": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}
test registry-9.4 {ParseKeyName: bad keys} -constraints {win reg} -body {
registry values \\\\\\
} -returnCodes error -result {bad root name "": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}
test registry-9.5 {ParseKeyName: bad keys} -constraints {win reg english} -body {
registry values \\\\\\HKEY_CLASSES_ROOT
} -returnCodes error -result {unable to open key: The network address is invalid.}
test registry-9.6 {ParseKeyName: bad keys} -constraints {win reg} -body {
registry values \\\\gaspode
} -returnCodes error -result {bad root name "": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}
test registry-9.7 {ParseKeyName: bad keys} -constraints {win reg} -body {
registry values foobar
} -returnCodes error -result {bad root name "foobar": must be HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, or HKEY_DYN_DATA}
test registry-9.8 {ParseKeyName: null keys} -constraints {win reg} -body {
registry delete HKEY_CLASSES_ROOT\\
} -returnCodes error -result {bad key: cannot delete root keys}
test registry-9.9 {ParseKeyName: null keys} \
-constraints {win reg english} \
-body {registry keys HKEY_CLASSES_ROOT\\TclFoobar\\baz} \
-returnCodes error \
-result {unable to open key: The system cannot find the file specified.}
test registry-10.1 {RecursiveDeleteKey} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
registry set HKEY_CURRENT_USER\\TclFoobar\\test1
registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
registry delete HKEY_CURRENT_USER\\TclFoobar
set result [registry keys HKEY_CURRENT_USER TclFoobar]
set result
} -result {}
test registry-10.2 {RecursiveDeleteKey} -constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
registry set HKEY_CURRENT_USER\\TclFoobar\\test1
registry set HKEY_CURRENT_USER\\TclFoobar\\test2\\test3
} -body {
registry delete HKEY_CURRENT_USER\\TclFoobar\\test2\\test4
} -cleanup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -result {}
test registry-11.1 {SetValue: recursive creation} \
-constraints {win reg} -setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar
set result [registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat]
} -result {foobar}
test registry-11.2 {SetValue: modification} -constraints {win reg} \
-setup {
registry delete HKEY_CURRENT_USER\\TclFoobar
} -body {
registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat foobar
registry set HKEY_CURRENT_USER\\TclFoobar\\baz blat frob
set result [registry get HKEY_CURRENT_USER\\TclFoobar\\baz blat]
} -result {frob}
test registry-11.3 {SetValue: failure} \
-constraints {win reg nonPortable english} \
-body {
# This test will only succeed if the current user does not have
# registry access on the specified machine.
registry set {\\mom\HKEY_CURRENT_USER\TclFoobar} bar foobar
} -returnCodes error -result {unable to open key: Access is denied.}
test registry-12.1 {BroadcastValue} -constraints {win reg} -body {
registry broadcast
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout milliseconds?\""
test registry-12.2 {BroadcastValue} -constraints {win reg} -body {
registry broadcast "" -time
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout milliseconds?\""
test registry-12.3 {BroadcastValue} -constraints {win reg} -body {
registry broadcast "" - 500
} -returnCodes error -result "wrong # args: should be \"registry broadcast keyName ?-timeout milliseconds?\""
test registry-12.4 {BroadcastValue} -constraints {win reg notWine} -body {
registry broadcast {Environment}
} -result {1 0}
test registry-12.5 {BroadcastValue} -constraints {win reg notWine} -body {
registry b {}
} -result {1 0}
# cleanup
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
|
| ︙ | ︙ |
Changes to tests/safe.test.
| ︙ | ︙ | |||
1592 1593 1594 1595 1596 1597 1598 |
safe::interpDelete $i
} -result {permission denied}
test safe-13.2 {mimic the valid glob call by ::tcl::tm::UnknownHandler [Bug 2964715]} -setup {
set i [safe::interpCreate]
buildEnvironment deleteme.tm
} -body {
::safe::interpAddToAccessPath $i $testdir2
| | | | | | 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 |
safe::interpDelete $i
} -result {permission denied}
test safe-13.2 {mimic the valid glob call by ::tcl::tm::UnknownHandler [Bug 2964715]} -setup {
set i [safe::interpCreate]
buildEnvironment deleteme.tm
} -body {
::safe::interpAddToAccessPath $i $testdir2
set result [$i eval glob -nocomplain -directory $testdir2 *.tm]
if {$result eq [list $testfile]} {
return "glob match"
} else {
return "no match: $result"
}
} -cleanup {
safe::interpDelete $i
removeDirectory $testdir
} -result {glob match}
test safe-13.3 {cf 13.2 but test glob failure when -directory is outside access path [Bug 2964715]} -setup {
set i [safe::interpCreate]
buildEnvironment deleteme.tm
} -body {
$i eval glob -directory $testdir2 *.tm
} -returnCodes error -cleanup {
safe::interpDelete $i
removeDirectory $testdir
} -result {permission denied}
test safe-13.4 {another valid glob call [Bug 2964715]} -setup {
set i [safe::interpCreate]
buildEnvironment deleteme.tm
} -body {
::safe::interpAddToAccessPath $i $testdir
::safe::interpAddToAccessPath $i $testdir2
set result [$i eval \
glob -nocomplain -directory $testdir [file join deletemetoo *.tm]]
if {$result eq [list $testfile]} {
return "glob match"
} else {
return "no match: $result"
}
} -cleanup {
safe::interpDelete $i
|
| ︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 |
removeDirectory $testdir
} -result {}
test safe-13.9 {as 13.8 but test glob failure when -directory is outside access path [Bug 2964715]} -setup {
set i [safe::interpCreate]
buildEnvironment notIndex.tcl
} -body {
::safe::interpAddToAccessPath $i $testdir2
| | | | | 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 |
removeDirectory $testdir
} -result {}
test safe-13.9 {as 13.8 but test glob failure when -directory is outside access path [Bug 2964715]} -setup {
set i [safe::interpCreate]
buildEnvironment notIndex.tcl
} -body {
::safe::interpAddToAccessPath $i $testdir2
set result [$i eval \
glob -directory $testdir -join -nocomplain * notIndex.tcl]
if {$result eq [list $testfile]} {
return {glob match}
} else {
return "no match: $result"
}
} -cleanup {
safe::interpDelete $i
removeDirectory $testdir
} -result {no match: }
test safe-13.10 {as 13.8 but test silent failure when result is outside access_path [Bug 2964715]} -setup {
set i [safe::interpCreate]
buildEnvironment notIndex.tcl
} -body {
::safe::interpAddToAccessPath $i $testdir
$i eval glob -directory $testdir -join -nocomplain * notIndex.tcl
} -cleanup {
safe::interpDelete $i
removeDirectory $testdir
} -result {}
rename buildEnvironment {}
rename buildEnvironment2 {}
|
| ︙ | ︙ |
Changes to tests/socket.test.
| ︙ | ︙ | |||
363 364 365 366 367 368 369 |
test socket_$af-1.20 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
socket -reuseport
} -returnCodes error -result {no argument given for -reuseport option}
set path(script) [makeFile {} script]
test socket_$af-2.1 {tcp connection} -constraints [list socket supported_$af stdio] -setup {
| | | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
test socket_$af-1.20 {arg parsing for socket command} -constraints [list socket supported_$af] -body {
socket -reuseport
} -returnCodes error -result {no argument given for -reuseport option}
set path(script) [makeFile {} script]
test socket_$af-2.1 {tcp connection} -constraints [list socket supported_$af stdio] -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f {
set timer [after 10000 "set x timed_out"]
set f [socket -server accept 0]
proc accept {file addr port} {
global x
set x done
|
| ︙ | ︙ | |||
395 396 397 398 399 400 401 |
close $sock
lappend x [gets $f]
} -cleanup {
close $f
} -result {ready done {}}
test socket_$af-2.2 {tcp connection with client port specified} -setup {
set port [randport]
| | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
close $sock
lappend x [gets $f]
} -cleanup {
close $f
} -result {ready done {}}
test socket_$af-2.2 {tcp connection with client port specified} -setup {
set port [randport]
file delete $path(script)
set f [open $path(script) w]
puts $f {
set timer [after 10000 "set x timeout"]
set f [socket -server accept 0]
proc accept {file addr port} {
global x
puts "[gets $file] $port"
|
| ︙ | ︙ | |||
429 430 431 432 433 434 435 |
close $sock
return $x
} -cleanup {
catch {close [socket $localhost $listen]}
close $f
} -result {ready 1}
test socket_$af-2.3 {tcp connection with client interface specified} -setup {
| | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 |
close $sock
return $x
} -cleanup {
catch {close [socket $localhost $listen]}
close $f
} -result {ready 1}
test socket_$af-2.3 {tcp connection with client interface specified} -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f {
set timer [after 2000 "set x done"]
set f [socket -server accept 0]
proc accept {file addr port} {
global x
puts "[gets $file] $addr"
|
| ︙ | ︙ | |||
462 463 464 465 466 467 468 |
lappend x [gets $f]
close $sock
return $x
} -cleanup {
close $f
} -result [list ready [list hello $localhost]]
test socket_$af-2.4 {tcp connection with server interface specified} -setup {
| | | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
lappend x [gets $f]
close $sock
return $x
} -cleanup {
close $f
} -result [list ready [list hello $localhost]]
test socket_$af-2.4 {tcp connection with server interface specified} -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f [list set localhost $localhost]
puts $f {
set timer [after 2000 "set x done"]
set f [socket -server accept -myaddr $localhost 0]
proc accept {file addr port} {
global x
|
| ︙ | ︙ | |||
496 497 498 499 500 501 502 |
lappend x [gets $f]
close $sock
return $x
} -cleanup {
close $f
} -result {ready hello}
test socket_$af-2.5 {tcp connection with redundant server port} -setup {
| | | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
lappend x [gets $f]
close $sock
return $x
} -cleanup {
close $f
} -result {ready hello}
test socket_$af-2.5 {tcp connection with redundant server port} -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f {
set timer [after 10000 "set x timeout"]
set f [socket -server accept 0]
proc accept {file addr port} {
global x
puts "[gets $file]"
|
| ︙ | ︙ | |||
539 540 541 542 543 544 545 |
set status broken
}
close $sock
}
set status
} -result ok
test socket_$af-2.7 {echo server, one line} -constraints [list socket supported_$af stdio] -setup {
| | | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 |
set status broken
}
close $sock
}
set status
} -result ok
test socket_$af-2.7 {echo server, one line} -constraints [list socket supported_$af stdio] -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f {
set timer [after 10000 "set x timeout"]
set f [socket -server accept 0]
proc accept {s a p} {
fileevent $s readable [list echo $s]
fconfigure $s -translation lf -buffering line
|
| ︙ | ︙ | |||
630 631 632 633 634 635 636 |
} -cleanup {
close $f
removeFile script
} -result {done 50}
set path(script) [makeFile {} script]
test socket_$af-2.9 {socket conflict} -constraints [list socket supported_$af stdio] -body {
set s [socket -server accept 0]
| | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
} -cleanup {
close $f
removeFile script
} -result {done 50}
set path(script) [makeFile {} script]
test socket_$af-2.9 {socket conflict} -constraints [list socket supported_$af stdio] -body {
set s [socket -server accept 0]
file delete $path(script)
set f [open $path(script) w]
puts $f [list set ::tcl::unsupported::socketAF $::tcl::unsupported::socketAF]
puts $f "socket -server accept [lindex [fconfigure $s -sockname] 2]"
close $f
set f [open "|[list [interpreter] $path(script)]" r]
gets $f
after 100
|
| ︙ | ︙ | |||
697 698 699 700 701 702 703 |
lappend result c:[gets $sock]
} -cleanup {
fconfigure $sock -blocking 1
close $s2
close $s
close $sock
} -result {a:one b: c:two}
| | | | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
lappend result c:[gets $sock]
} -cleanup {
fconfigure $sock -blocking 1
close $s2
close $s
close $sock
} -result {a:one b: c:two}
test socket_$af-2.12 {} [list socket stdio supported_$af] {
file delete $path(script)
set f [open $path(script) w]
puts $f {
set server [socket -server accept_client 0]
puts [lindex [chan configure $server -sockname] 2]
proc accept_client { client host port } {
chan configure $client -blocking 0 -buffering line
write_line $client
|
| ︙ | ︙ | |||
737 738 739 740 741 742 743 |
while {![string is integer [set ::done [gets $pipe]]]} {}
}
vwait ::done
close $f
set ::done
} 0
test socket_$af-2.13 {Bug 1758a0b603} {socket stdio notWine} {
| | | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 |
while {![string is integer [set ::done [gets $pipe]]]} {}
}
vwait ::done
close $f
set ::done
} 0
test socket_$af-2.13 {Bug 1758a0b603} {socket stdio notWine} {
file delete $path(script)
set f [open $path(script) w]
puts $f {
set server [socket -server accept 0]
puts [lindex [chan configure $server -sockname] 2]
proc accept { client host port } {
chan configure $client -blocking 0 -buffering line -buffersize 1
puts $client [string repeat . 720000]
|
| ︙ | ︙ | |||
779 780 781 782 783 784 785 |
variable done
vwait [namespace which -variable done]
close $pipe
set done
} write
test socket_$af-3.1 {socket conflict} -constraints [list socket supported_$af stdio] -setup {
| | | | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 |
variable done
vwait [namespace which -variable done]
close $pipe
set done
} write
test socket_$af-3.1 {socket conflict} -constraints [list socket supported_$af stdio] -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f [list set localhost $localhost]
puts $f {
set f [socket -server accept -myaddr $localhost 0]
puts ready
puts [lindex [fconfigure $f -sockname] 2]
gets stdin
close $f
}
close $f
set f [open "|[list [interpreter] $path(script)]" r+]
gets $f
gets $f listen
} -body {
socket -server accept -myaddr $localhost $listen
} -cleanup {
puts $f bye
close $f
} -returnCodes error -result {couldn't open socket: address already in use}
test socket_$af-3.2 {server with several clients} -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f [list set localhost $localhost]
puts $f {
set t1 [after 30000 "set x timed_out"]
set t2 [after 31000 "set x timed_out"]
set t3 [after 32000 "set x timed_out"]
set counter 0
|
| ︙ | ︙ | |||
863 864 865 866 867 868 869 |
close $s3
lappend x [gets $f]
} -cleanup {
close $f
} -result {ready done}
test socket_$af-4.1 {server with several clients} -setup {
| | | 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 |
close $s3
lappend x [gets $f]
} -cleanup {
close $f
} -result {ready done}
test socket_$af-4.1 {server with several clients} -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f [list set localhost $localhost]
puts $f {
set port [gets stdin]
set s [socket $localhost $port]
fconfigure $s -buffering line
for {set i 0} {$i < 100} {incr i} {
|
| ︙ | ︙ | |||
960 961 962 963 964 965 966 |
test socket_$af-6.1 {accept callback error} -constraints [list socket supported_$af stdio] -setup {
proc myHandler {msg options} {
variable x $msg
}
set handler [interp bgerror {}]
interp bgerror {} [namespace which myHandler]
| | | 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 |
test socket_$af-6.1 {accept callback error} -constraints [list socket supported_$af stdio] -setup {
proc myHandler {msg options} {
variable x $msg
}
set handler [interp bgerror {}]
interp bgerror {} [namespace which myHandler]
file delete $path(script)
} -body {
set f [open $path(script) w]
puts $f [list set localhost $localhost]
puts $f {
gets stdin port
socket $localhost $port
}
|
| ︙ | ︙ | |||
1002 1003 1004 1005 1006 1007 1008 |
} -constraints [list socket supported_$af] -body {
fileevent $sock writable dummy
} -cleanup {
close $sock
} -returnCodes 1 -result "channel is not writable"
test socket_$af-7.1 {testing socket specific options} -setup {
| | | 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 |
} -constraints [list socket supported_$af] -body {
fileevent $sock writable dummy
} -cleanup {
close $sock
} -returnCodes 1 -result "channel is not writable"
test socket_$af-7.1 {testing socket specific options} -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f {
set ss [socket -server accept 0]
proc accept args {
global x
set x done
}
|
| ︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 |
lappend l [string compare [lindex $p 0] $localhost]
lappend l [string compare [lindex $p 2] $listen]
lappend l [llength $p]
} -cleanup {
close $f
} -result {0 0 3}
test socket_$af-7.2 {testing socket specific options} -setup {
| | | 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 |
lappend l [string compare [lindex $p 0] $localhost]
lappend l [string compare [lindex $p 2] $listen]
lappend l [llength $p]
} -cleanup {
close $f
} -result {0 0 3}
test socket_$af-7.2 {testing socket specific options} -setup {
file delete $path(script)
set f [open $path(script) w]
puts $f [list set ::tcl::unsupported::socketAF $::tcl::unsupported::socketAF]
puts $f {
set ss [socket -server accept 0]
proc accept args {
global x
set x done
|
| ︙ | ︙ | |||
1660 1661 1662 1663 1664 1665 1666 |
sendCommand {close $l}
} -result 65566
set path(script1) [makeFile {} script1]
set path(script2) [makeFile {} script2]
test socket_$af-12.1 {testing inheritance of server sockets} -setup {
| | | | 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 |
sendCommand {close $l}
} -result 65566
set path(script1) [makeFile {} script1]
set path(script2) [makeFile {} script2]
test socket_$af-12.1 {testing inheritance of server sockets} -setup {
file delete $path(script1)
file delete $path(script2)
# Script1 is just a 10 second delay. If the server socket is inherited, it
# will be held open for 10 seconds
set f [open $path(script1) w]
puts $f {
fileevent stdin readable exit
after 10000 exit
vwait forever
|
| ︙ | ︙ | |||
1702 1703 1704 1705 1706 1707 1708 |
} else {
return {server socket was inherited}
}
} -cleanup {
catch {close $p}
} -result {server socket was not inherited}
test socket_$af-12.2 {testing inheritance of client sockets} -setup {
| | | | 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 |
} else {
return {server socket was inherited}
}
} -cleanup {
catch {close $p}
} -result {server socket was not inherited}
test socket_$af-12.2 {testing inheritance of client sockets} -setup {
file delete $path(script1)
file delete $path(script2)
# Script1 is just a 20 second delay. If the server socket is inherited, it
# will be held open for 20 seconds
set f [open $path(script1) w]
puts $f {
fileevent stdin readable exit
after 20000 exit
vwait forever
|
| ︙ | ︙ | |||
1771 1772 1773 1774 1775 1776 1777 |
} -cleanup {
fconfigure $f -blocking 1
close $f
after cancel $after
close $p
} -result {client socket was not inherited}
test socket_$af-12.3 {testing inheritance of accepted sockets} -setup {
| | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 |
} -cleanup {
fconfigure $f -blocking 1
close $f
after cancel $after
close $p
} -result {client socket was not inherited}
test socket_$af-12.3 {testing inheritance of accepted sockets} -setup {
file delete $path(script1)
file delete $path(script2)
set f [open $path(script1) w]
puts $f {
fileevent stdin readable exit
after 10000 exit
vwait forever
}
close $f
set f [open $path(script2) w]
puts $f [list set tcltest [interpreter]]
puts $f [list set delay $path(script1)]
puts $f [list set localhost $localhost]
puts $f {
set server [socket -server accept -myaddr $localhost 0]
|
| ︙ | ︙ |
Changes to tests/split.test.
| ︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
test split-2.1 {split errors} {
list [catch split msg] $msg $errorCode
} {1 {wrong # args: should be "split string ?splitChars?"} {TCL WRONGARGS}}
test split-2.2 {split errors} {
list [catch {split a b c} msg] $msg $errorCode
} {1 {wrong # args: should be "split string ?splitChars?"} {TCL WRONGARGS}}
# cleanup
catch {rename foo {}}
::tcltest::cleanupTests
return
# Local Variables:
| > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
test split-2.1 {split errors} {
list [catch split msg] $msg $errorCode
} {1 {wrong # args: should be "split string ?splitChars?"} {TCL WRONGARGS}}
test split-2.2 {split errors} {
list [catch {split a b c} msg] $msg $errorCode
} {1 {wrong # args: should be "split string ?splitChars?"} {TCL WRONGARGS}}
# cleanup
catch {rename foo {}}
::tcltest::cleanupTests
return
# Local Variables:
|
| ︙ | ︙ |
Changes to tests/string.test.
| ︙ | ︙ | |||
222 223 224 225 226 227 228 |
test string-2.35.$noComp {string compare, binary neq} {
run {string compare [binary format a100a 0 1] [binary format a100a 0 0]}
} 1
test string-2.36.$noComp {string compare, binary neq unequal length} {
run {string compare [binary format a20a 0 1] [binary format a100a 0 0]}
} 1
test string-2.37.$noComp {string compare, big -length} {
| < | < < < | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
test string-2.35.$noComp {string compare, binary neq} {
run {string compare [binary format a100a 0 1] [binary format a100a 0 0]}
} 1
test string-2.36.$noComp {string compare, binary neq unequal length} {
run {string compare [binary format a20a 0 1] [binary format a100a 0 0]}
} 1
test string-2.37.$noComp {string compare, big -length} {
run {string compare -length 0x100000000 ab abde}
} -1
test string-2.38a.$noComp {string compare empty string against byte array} {
# Bug edb4b065f4
run {string compare "" [binary decode hex 00]}
} -1
test string-2.38b.$noComp {string compare -length empty string against byte array} {
# Bug edb4b065f4
|
| ︙ | ︙ | |||
393 394 395 396 397 398 399 |
test string-3.41.$noComp {string equal, binary neq} {
run {string equal [binary format a100a 0 1] [binary format a100a 0 0]}
} 0
test string-3.42.$noComp {string equal, binary neq inequal length} {
run {string equal [binary format a20a 0 1] [binary format a100a 0 0]}
} 0
test string-3.43.$noComp {string equal, big -length} {
| < | < < < | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
test string-3.41.$noComp {string equal, binary neq} {
run {string equal [binary format a100a 0 1] [binary format a100a 0 0]}
} 0
test string-3.42.$noComp {string equal, binary neq inequal length} {
run {string equal [binary format a20a 0 1] [binary format a100a 0 0]}
} 0
test string-3.43.$noComp {string equal, big -length} {
run {string equal -length 0x100000000 abc def}
} 0
test string-3.44.$noComp {string equal, bigger -length} -body {
run {string equal -length 18446744073709551616 abc def}
} -returnCodes 1 -result {integer value too large to represent}
test string-3.45a.$noComp {string equal empty string against byte array} {
# Bug edb4b065f4
run {string equal "" [binary decode hex 00]}
|
| ︙ | ︙ | |||
1722 1723 1724 1725 1726 1727 1728 |
set val ""
for { set i 0 } { $i < $x } { incr i } {
set val [format "0%s" $val]
}
string replace $val[unset val] 1 1 $y
}} 4 x
} 0x00
| | | | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 |
set val ""
for { set i 0 } { $i < $x } { incr i } {
set val [format "0%s" $val]
}
string replace $val[unset val] 1 1 $y
}} 4 x
} 0x00
test stringComp-14.25.$noComp {} {
string length [string replace [string repeat a\xFE 2] 3 end {}]
} 3
test stringComp-14.26.$noComp {} {
run {string replace abcd 0x10000000000000000-0xffffffffffffffff 2 e}
} aed
test string-15.1.$noComp {string tolower not enough args} {
list [catch {run {string tolower}} msg] $msg
} {1 {wrong # args: should be "string tolower string ?first? ?last?"}}
test string-15.2.$noComp {string tolower bad args} {
|
| ︙ | ︙ |
Changes to tests/stringObj.test.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testobj [llength [info commands testobj]]
| < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testobj [llength [info commands testobj]]
testConstraint testbytestring [llength [info commands testbytestring]]
testConstraint testdstring [llength [info commands testdstring]]
test stringObj-1.1 {string type registration} testobj {
set t [testobj types]
set first [string first "string" $t]
set result [expr {$first >= 0}]
|
| ︙ | ︙ | |||
524 525 526 527 528 529 530 |
teststringobj range 1 [expr {$INT_MAX-1}] [expr {$INT_MAX-1}]
} {}
test stringObj-16.12 {Tcl_GetRange: first = last = SIZE_MAX-1} testobj {
teststringobj set 1 abcde
set i [expr {$SIZE_MAX - 1}]
teststringobj range 1 $i $i
} {}
| < < < < < < < < < < < < < < < < < < < < | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
teststringobj range 1 [expr {$INT_MAX-1}] [expr {$INT_MAX-1}]
} {}
test stringObj-16.12 {Tcl_GetRange: first = last = SIZE_MAX-1} testobj {
teststringobj set 1 abcde
set i [expr {$SIZE_MAX - 1}]
teststringobj range 1 $i $i
} {}
if {[testConstraint testobj]} {
testobj freeallvars
}
# cleanup
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
# End:
|
Changes to tests/subst.test.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 |
::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testbytestring [llength [info commands testbytestring]]
test subst-1.1 {basics} -returnCodes error -body {
subst
| | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testbytestring [llength [info commands testbytestring]]
test subst-1.1 {basics} -returnCodes error -body {
subst
} -result {wrong # args: should be "subst ?-nobackslashes? ?-nocommands? ?-novariables? string"}
test subst-1.2 {basics} -returnCodes error -body {
subst a b c
} -result {bad option "a": must be -nobackslashes, -nocommands, or -novariables}
test subst-2.1 {simple strings} {
subst {}
} {}
test subst-2.2 {simple strings} {
subst a
} a
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
test subst-6.1 {clear the result after command substitution} -body {
catch {unset a}
subst {[concat foo] $a}
} -returnCodes error -result {can't read "a": no such variable}
test subst-7.1 {switches} -returnCodes error -body {
subst foo bar
| | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
test subst-6.1 {clear the result after command substitution} -body {
catch {unset a}
subst {[concat foo] $a}
} -returnCodes error -result {can't read "a": no such variable}
test subst-7.1 {switches} -returnCodes error -body {
subst foo bar
} -result {bad option "foo": must be -nobackslashes, -nocommands, or -novariables}
test subst-7.2 {switches} -returnCodes error -body {
subst -no bar
} -result {ambiguous option "-no": must be -nobackslashes, -nocommands, or -novariables}
test subst-7.3 {switches} -returnCodes error -body {
subst -bogus bar
} -result {bad option "-bogus": must be -nobackslashes, -nocommands, or -novariables}
test subst-7.4 {switches} {
set x 123
subst -nobackslashes {abc $x [expr {1 + 2}] \\\x41}
} {abc 123 3 \\\x41}
test subst-7.5 {switches} {
set x 123
subst -nocommands {abc $x [expr {1 + 2}] \\\x41}
} {abc 123 [expr {1 + 2}] \A}
test subst-7.6 {switches} {
set x 123
subst -novariables {abc $x [expr {1 + 2}] \\\x41}
} {abc $x 3 \A}
test subst-7.7 {switches} {
set x 123
subst -nov -nob -noc {abc $x [expr {1 + 2}] \\\x41}
} {abc $x [expr {1 + 2}] \\\x41}
test subst-8.1 {return in a subst} {
subst {foo [return {x}; bogus code] bar}
} {foo x bar}
test subst-8.2 {return in a subst} {
subst {foo [return x ; bogus code] bar}
} {foo x bar}
test subst-8.3 {return in a subst} {
|
| ︙ | ︙ |
Changes to tests/switch.test.
| ︙ | ︙ | |||
95 96 97 98 99 100 101 |
-* {subst glob}
-glob {subst exact}
default {subst none}
}
} exact
test switch-3.6 {-exact vs. -glob vs. -regexp} -body {
switch -foo a b c
| | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
-* {subst glob}
-glob {subst exact}
default {subst none}
}
} exact
test switch-3.6 {-exact vs. -glob vs. -regexp} -body {
switch -foo a b c
} -returnCodes error -result {bad option "-foo": must be -exact, -glob, -indexvar, -matchvar, -nocase, -regexp, or --}
test switch-3.7 {-exact vs. -glob vs. -regexp with -nocase} {
switch -exact -nocase aaaab {
^a*b$ {subst regexp}
*b {subst glob}
aaaab {subst exact}
default {subst none}
}
|
| ︙ | ︙ | |||
153 154 155 156 157 158 159 |
} -returnCodes error -result {bad option "-glob": -exact option already found}
test switch-3.17 {-exact vs. -glob vs. -regexp} -body {
switch -glob -regexp Foo Foo {set result OK}
} -returnCodes error -result {bad option "-regexp": -glob option already found}
test switch-3.18 {-exact vs. -glob vs. -regexp} -body {
switch -regexp -glob Foo Foo {set result OK}
} -returnCodes error -result {bad option "-glob": -regexp option already found}
| < < < < < < < < < | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
} -returnCodes error -result {bad option "-glob": -exact option already found}
test switch-3.17 {-exact vs. -glob vs. -regexp} -body {
switch -glob -regexp Foo Foo {set result OK}
} -returnCodes error -result {bad option "-regexp": -glob option already found}
test switch-3.18 {-exact vs. -glob vs. -regexp} -body {
switch -regexp -glob Foo Foo {set result OK}
} -returnCodes error -result {bad option "-glob": -regexp option already found}
test switch-4.1 {error in executed command} {
list [catch {switch a a {error "Just a test"} default {subst 1}} msg] \
$msg $::errorInfo
} {1 {Just a test} {Just a test
while executing
"error "Just a test""
|
| ︙ | ︙ | |||
773 774 775 776 777 778 779 |
list [coroutine c coro] [c]
}
-result {ok1 ok2}
-cleanup {
rename coro {}
}
}
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 |
list [coroutine c coro] [c]
}
-result {ok1 ok2}
-cleanup {
rename coro {}
}
}
# cleanup
catch {rename foo {}}
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
# End:
|
Changes to tests/tailcall.test.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 |
}
namespace import testnre::*
}
proc errorcode options {
dict get [dict merge {-errorcode NONE} $options] -errorcode
}
| < < < < < < < < < < < < < < < < < < | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
}
namespace import testnre::*
}
proc errorcode options {
dict get [dict merge {-errorcode NONE} $options] -errorcode
}
test tailcall-0.1 {tailcall is constant space} -constraints testnrelevels -setup {
proc a i {
#
# NOTE: there may be a diff in callback depth with the first call
# ($i==0) due to the fact that the first is from an eval. Successive
# calls should add nothing to any stack depths.
|
| ︙ | ︙ | |||
722 723 724 725 726 727 728 |
tailcall [namespace current] {*}$args
}
namespace delete [namespace current]
p
}
} -returnCodes 1 -result {namespace "::ns" not found}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 |
tailcall [namespace current] {*}$args
}
namespace delete [namespace current]
p
}
} -returnCodes 1 -result {namespace "::ns" not found}
test tailcall-bug-784befb0ba {tailcall crash with 254 args} -body {
proc tccrash args {llength $args}
# Must be EXACTLY 254 for crash
proc p {} [list tailcall tccrash {*}[lrepeat 254 x]]
p
} -result 254
# cleanup
::tcltest::cleanupTests
# Local Variables:
# mode: tcl
# End:
|
Changes to tests/tcltest.test.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
#
# It would be better to have the -body of the tests run the tcltest
# commands in a child interp so the [test] being tested would not
# interfere with the [test] doing the testing.
#
if {"::tcltest" ni [namespace children]} {
| | | | < | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#
# It would be better to have the -body of the tests run the tcltest
# commands in a child interp so the [test] being tested would not
# interfere with the [test] doing the testing.
#
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
# File permissions broken on wsl without some "exotic" wsl configuration
testConstraint notWsl [expr {[llength [array names ::env *WSL*]] == 0}]
namespace eval ::tcltest::test {
namespace import ::tcltest::*
makeFile {
package require tcltest 2.5
namespace import ::tcltest::test
test a-1.0 {test a} {
list 0
} {0}
test b-1.0 {test b} {
list 1
} {0}
test c-1.0 {test c} {knownBug} {
} {}
test d-1.0 {test d} {
error "foo" foo 9
} {}
tcltest::cleanupTests
exit
} test.tcl
cd [temporaryDirectory]
testConstraint exec [llength [info commands exec]]
# test -help
# Child processes because -help [exit]s.
test tcltest-1.1 {tcltest -help} {exec} {
|
| ︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 |
return $msg
} -cleanup {
removeFile test.tcl
} -match glob -result {*
---- errorInfo: body error
*
---- errorInfo(cleanup): cleanup error*}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 |
return $msg
} -cleanup {
removeFile test.tcl
} -match glob -result {*
---- errorInfo: body error
*
---- errorInfo(cleanup): cleanup error*}
cleanupTests
}
namespace delete ::tcltest::test
return
# Local Variables:
# mode: tcl
# End:
|
Changes to tests/tcltests.tcl.
| ︙ | ︙ | |||
22 23 24 25 26 27 28 |
}]
testConstraint fcopy [llength [info commands fcopy]]
testConstraint fileevent [llength [info commands fileevent]]
testConstraint thread [expr {![catch {package require Thread 2.7-}]}]
testConstraint notValgrind [expr {![testConstraint valgrind]}]
namespace eval ::tcltests {
| < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
}]
testConstraint fcopy [llength [info commands fcopy]]
testConstraint fileevent [llength [info commands fileevent]]
testConstraint thread [expr {![catch {package require Thread 2.7-}]}]
testConstraint notValgrind [expr {![testConstraint valgrind]}]
namespace eval ::tcltests {
proc init {} {
if {[namespace which ::tcl::file::tempdir] eq {}} {
interp alias {} [namespace current]::tempdir {} [
namespace current]::tempdir_alternate
} else {
interp alias {} [namespace current]::tempdir {} ::tcl::file::tempdir
|
| ︙ | ︙ | |||
122 123 124 125 126 127 128 |
return [windowsversion]
}
proc windowsbuildnumber {} {
return [lindex [windowsversion] 3]
}
proc windowscodepage {} {
# Note we cannot use result of chcp because that returns OEM code page.
| > | < | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
return [windowsversion]
}
proc windowsbuildnumber {} {
return [lindex [windowsversion] 3]
}
proc windowscodepage {} {
# Note we cannot use result of chcp because that returns OEM code page.
package require registry
set cp [registry get HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage ACP]
if {$cp eq "65001"} {
proc windowscodepage {} "return utf-8"
} else {
proc windowscodepage {} "return cp$cp"
}
return [windowscodepage]
}
}
}
init
package provide tcltests 0.1
}
|
Changes to tests/timer.test.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
test timer-1.1 {Tcl_CreateTimerHandler procedure} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x ""
foreach i {100 200 1000 50 150} {
after $i lappend x $i
}
after 200 set done 1
vwait done
return $x
} -cleanup {
foreach i [after info] {
after cancel $i
}
} -result {50 100 150 200}
test timer-2.1 {Tcl_DeleteTimerHandler procedure} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x ""
foreach i {100 200 1000 50 150} {
after $i lappend x $i
}
after cancel lappend x 150
after cancel lappend x 50
after 200 set done 1
vwait done
return $x
} -result {100 200}
# No tests for Tcl_ServiceTimer or ResetTimer, since it is already tested
# above.
test timer-3.1 {TimerHandlerEventProc procedure: event masks} {
set x start
after 100 { set x fired }
update idletasks
set result $x
after 200
update
lappend result $x
} {start fired}
test timer-3.2 {TimerHandlerEventProc procedure: multiple timers} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
foreach i {200 600 1000} {
after $i lappend x $i
}
after 200
set result ""
set x ""
update
lappend result $x
after 400
update
lappend result $x
after 400
update
lappend result $x
} -result {200 {200 600} {200 600 1000}}
test timer-3.3 {TimerHandlerEventProc procedure: reentrant timer deletion} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x {}
after 100 lappend x 100
set i [after 300 lappend x 300]
after 200 after cancel $i
after 400
update
return $x
} -result 100
test timer-3.4 {TimerHandlerEventProc procedure: all expired timers fire} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x {}
after 100 lappend x a
after 200 lappend x b
after 300 lappend x c
after 300
vwait x
return $x
} -result {a b c}
test timer-3.5 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x {}
after 100 {lappend x a; after 0 lappend x b}
after 100
vwait x
return $x
} -result a
test timer-3.6 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x {}
after 100 {lappend x a; after 100 lappend x b; after 100}
after 100
vwait x
set result $x
vwait x
lappend result $x
} -result {a {a b}}
# No tests for Tcl_DoWhenIdle: it's already tested by other tests
# below.
|
| ︙ | ︙ | |||
476 477 478 479 480 481 482 |
update idletasks
lappend result $x
} -result {2 24 4}
test timer-6.1 {Tcl_AfterCmd procedure, basics} -returnCodes error -body {
after
} -result {wrong # args: should be "after option ?arg ...?"}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < | < < | | < | < | < < < < < < < < < < | < < < < < | < | < < < < < < | < < < < < < < | | < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
update idletasks
lappend result $x
} -result {2 24 4}
test timer-6.1 {Tcl_AfterCmd procedure, basics} -returnCodes error -body {
after
} -result {wrong # args: should be "after option ?arg ...?"}
test timer-6.2 {Tcl_AfterCmd procedure, basics} -returnCodes error -body {
after 2x
} -result {bad argument "2x": must be cancel, idle, info, or an integer}
test timer-6.3 {Tcl_AfterCmd procedure, basics} -returnCodes error -body {
after gorp
} -result {bad argument "gorp": must be cancel, idle, info, or an integer}
test timer-6.4 {Tcl_AfterCmd procedure, ms argument} {
set x before
after 400 {set x after}
after 200
update
set y $x
after 400
update
list $y $x
} {before after}
test timer-6.5 {Tcl_AfterCmd procedure, ms argument} {
set x before
after 400 set x after
after 200
update
set y $x
after 400
update
list $y $x
} {before after}
test timer-6.6 {Tcl_AfterCmd procedure, cancel option} -body {
after cancel
} -returnCodes error -result {wrong # args: should be "after cancel id|command"}
test timer-6.7 {Tcl_AfterCmd procedure, cancel option} {
after cancel after#1
} {}
test timer-6.8 {Tcl_AfterCmd procedure, cancel option} {
after cancel {foo bar}
} {}
test timer-6.9 {Tcl_AfterCmd procedure, cancel option} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x before
set y [after 100 set x after]
after cancel $y
after 200
update
return $x
} -result {before}
test timer-6.10 {Tcl_AfterCmd procedure, cancel option} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x before
after 100 set x after
after cancel {set x after}
after 200
update
return $x
} -result {before}
test timer-6.11 {Tcl_AfterCmd procedure, cancel option} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x before
after 100 set x after
set id [after 300 set x after]
after cancel $id
after 200
update
set y $x
set x cleared
after 200
update
list $y $x
} -result {after cleared}
test timer-6.12 {Tcl_AfterCmd procedure, cancel option} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x first
after idle lappend x second
after idle lappend x third
set i [after idle lappend x fourth]
after cancel {lappend x second}
after cancel $i
update idletasks
return $x
} -result {first third}
test timer-6.13 {Tcl_AfterCmd procedure, cancel option, multiple arguments for command} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x first
after idle lappend x second
after idle lappend x third
set i [after idle lappend x fourth]
after cancel lappend x second
after cancel $i
update idletasks
return $x
} -result {first third}
test timer-6.14 {Tcl_AfterCmd procedure, cancel option, cancel during handler, used to dump core} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set id [
after 100 {
set x done
after cancel $id
}
]
vwait x
} -result {}
test timer-6.15 {Tcl_AfterCmd procedure, cancel option, multiple interps} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
interp create x
x eval {set a before; set b before; after idle {set a a-after};
after idle {set b b-after}}
set result [llength [x eval after info]]
lappend result [llength [after info]]
after cancel {set b b-after}
set a aaa
set b bbb
x eval {after cancel set a a-after}
update idletasks
lappend result $a $b [x eval {list $a $b}]
} -cleanup {
interp delete x
} -result {2 0 aaa bbb {before b-after}}
test timer-6.16 {Tcl_AfterCmd procedure, idle option} -body {
after idle
} -returnCodes error -result {wrong # args: should be "after idle script ?script ...?"}
test timer-6.17 {Tcl_AfterCmd procedure, idle option} {
set x before
after idle {set x after}
set y $x
update idletasks
list $y $x
} {before after}
test timer-6.18 {Tcl_AfterCmd procedure, idle option} {
set x before
after idle set x after
set y $x
update idletasks
list $y $x
} {before after}
set event1 [after idle event 1]
set event2 [after 1000 event 2]
interp create x
set childEvent [x eval {after idle event in child}]
test timer-6.19 {Tcl_AfterCmd, info option} {
lsort [after info]
} [lsort "$event1 $event2"]
test timer-6.20 {Tcl_AfterCmd, info option} -returnCodes error -body {
after info a b
} -result {wrong # args: should be "after info ?id?"}
test timer-6.21 {Tcl_AfterCmd, info option} -returnCodes error -body {
after info $childEvent
} -result "event \"$childEvent\" doesn't exist"
test timer-6.22 {Tcl_AfterCmd, info option} {
list [after info $event1] [after info $event2]
} {{{event 1} idle} {{event 2} timer}}
after cancel $event1
after cancel $event2
interp delete x
test timer-6.23 {Tcl_AfterCmd procedure, no option, script with NUL} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x "hello world"
after 1 "set x ab\x00cd"
after 10
update
string length $x
} -result {5}
test timer-6.24 {Tcl_AfterCmd procedure, no option, script with NUL} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x "hello world"
after 1 set x ab\x00cd
after 10
update
string length $x
} -result {5}
test timer-6.25 {Tcl_AfterCmd procedure, cancel option, script with NUL} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x "hello world"
after 1 set x ab\x00cd
after cancel "set x ab\x00ef"
llength [after info]
} -cleanup {
foreach i [after info] {
after cancel $i
}
} -result {1}
test timer-6.26 {Tcl_AfterCmd procedure, cancel option, script with NUL} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x "hello world"
after 1 set x ab\x00cd
after cancel set x ab\x00ef
llength [after info]
} -cleanup {
foreach i [after info] {
after cancel $i
}
} -result {1}
test timer-6.27 {Tcl_AfterCmd procedure, idle option, script with NUL} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x "hello world"
after idle "set x ab\x00cd"
update
string length $x
} -result {5}
test timer-6.28 {Tcl_AfterCmd procedure, idle option, script with NUL} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x "hello world"
after idle set x ab\x00cd
update
string length $x
} -result {5}
test timer-6.29 {Tcl_AfterCmd procedure, info option, script with NUL} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
set x "hello world"
set id junk
set id [after 10 set x ab\x00cd]
update
string length [lindex [lindex [after info $id] 0] 2]
} -cleanup {
foreach i [after info] {
after cancel $i
}
} -result 5
set event [after idle foo bar]
scan $event after#%d lastId
test timer-7.1 {GetAfterEvent procedure} -returnCodes error -body {
after info xfter#$lastId
} -result "event \"xfter#$lastId\" doesn't exist"
test timer-7.2 {GetAfterEvent procedure} -returnCodes error -body {
after info afterx$lastId
} -result "event \"afterx$lastId\" doesn't exist"
test timer-7.3 {GetAfterEvent procedure} -returnCodes error -body {
after info after#ab
} -result {event "after#ab" doesn't exist}
test timer-7.4 {GetAfterEvent procedure} -returnCodes error -body {
after info after#
} -result {event "after#" doesn't exist}
test timer-7.5 {GetAfterEvent procedure} -returnCodes error -body {
after info after#${lastId}x
} -result "event \"after#${lastId}x\" doesn't exist"
test timer-7.6 {GetAfterEvent procedure} -returnCodes error -body {
after info afterx[expr {$lastId+1}]
} -result "event \"afterx[expr {$lastId+1}]\" doesn't exist"
after cancel $event
test timer-8.1 {AfterProc procedure} {
set x before
proc foo {} {
set x untouched
after 100 {set x after}
after 200
update
return $x
}
list [foo] $x
} {untouched after}
test timer-8.2 {AfterProc procedure} -setup {
variable x empty
proc myHandler {msg options} {
variable x [list $msg [dict get $options -errorinfo]]
}
set handler [interp bgerror {}]
interp bgerror {} [namespace which myHandler]
} -body {
after 100 {error "After error"}
after 200
set y $x
update
list $y $x
} -cleanup {
interp bgerror {} $handler
} -result {empty {{After error} {After error
while executing
"error "After error""
("after" script)}}}
test timer-8.3 {AfterProc procedure, deleting handler from itself} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
proc foo {} {
global x
set x {}
foreach i [after info] {
lappend x [after info $i]
}
after cancel foo
}
after idle foo
after 1000 {error "I shouldn't ever have executed"}
update idletasks
return $x
} -result {{{error "I shouldn't ever have executed"} timer}}
test timer-8.4 {AfterProc procedure, deleting handler from itself} -setup {
foreach i [after info] {
after cancel $i
}
} -body {
proc foo {} {
global x
|
| ︙ | ︙ | |||
1203 1204 1205 1206 1207 1208 1209 |
interp delete x
set x before
after 300
update
return $x
} -result {before after2 after4}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 |
interp delete x
set x before
after 300
update
return $x
} -result {before after2 after4}
test timer-10.1 {Bug 1016167: [after] overwrites imports} -setup {
interp create child
child eval namespace export after
child eval namespace eval foo namespace import ::after
} -body {
child eval foo::after 1
child eval namespace origin foo::after
} -cleanup {
# Bug will cause crash here; would cause failure otherwise
interp delete child
} -result ::after
test timer-11.1 {Bug 1350291: [after] overflowing 32-bit field} -body {
set b ok
set a [after 0x100000001 {set b "after fired early"}]
after 100 set done 1
vwait done
return $b
} -cleanup {
catch {after cancel $a}
} -result ok
test timer-11.2 {Bug 1350293: [after] negative argument} -body {
set l {}
after 100 {lappend l 100; set done 1}
after -1 {lappend l -1}
vwait done
return $l
} -result {-1 100}
# cleanup
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
# End:
|
Deleted tests/ucdUtils.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/unicodeNormalize.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/unicodeProperties.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/unicodeTestVectors/DerivedNormalizationProps.txt.
more than 10,000 changes
Deleted tests/unicodeTestVectors/GraphemeBreakTest-17.0.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/unicodeTestVectors/GraphemeBreakTest.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted tests/unicodeTestVectors/NormalizationTest.txt.
more than 10,000 changes
Deleted tests/unicodeTestVectors/README-tcl.md.
|
| < < |
Deleted tests/unicodeTestVectors/license.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tests/unixInit.test.
| ︙ | ︙ | |||
93 94 95 96 97 98 99 |
set enc [gets $f]
close $f
set enc
} -cleanup {
unset -nocomplain env(LANG)
} -match regexp -result {^(iso8859-15?|utf-8)$}
| | | | | | | < < < | > > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
set enc [gets $f]
close $f
set enc
} -cleanup {
unset -nocomplain env(LANG)
} -match regexp -result {^(iso8859-15?|utf-8)$}
# unixInit-3.2 depends on the *spawned* [interpreter] being able to locate
# tcl_library without setting of TCL_LIBRARY env. This in turn depends on
# Tcl's "library" directory being under the parent or grandparent of the
# executable directory (the initScript search path in tclInterp.c).
# Thus this constraint. On GiuHub CI, the only time this is not true
# is for the XCode builds.
if {[string match [zipfs root]* [info library]] ||
[file isfile [file normalize [file join [info nameofexecutable] .. .. library init.tcl]]] ||
[file isfile [file normalize [file join [info nameofexecutable] .. .. .. library init.tcl]]]
} {
tcltest::testConstraint enableUnixInit32 1
} else {
tcltest::testConstraint enableUnixInit32 0
}
test unixInit-3.2 {TclpSetInitialEncodings} -setup {
catch {set oldlc_all $env(LC_ALL)}
catch {set oldtcl_library $env(TCL_LIBRARY)}
|
| ︙ | ︙ |
Changes to tests/utfext.test.
1 2 3 4 | # This file contains a collection of tests for Tcl_UtfToExternal and # Tcl_UtfToExternal that exercise various combinations of flags, # buffer lengths and fragmentation that cannot be tested by # normal script level commands. There tests are NOT intended to check | | | < < < < < < < < < | | | | | < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# This file contains a collection of tests for Tcl_UtfToExternal and
# Tcl_UtfToExternal that exercise various combinations of flags,
# buffer lengths and fragmentation that cannot be tested by
# normal script level commands. There tests are NOT intended to check
# correct encodings; those are elsewhere.
#
# Copyright (c) 2023 Ashok P. Nadkarni
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
catch [list package require -exact tcl::test [info patchlevel]]
testConstraint testbytestring [llength [info commands testbytestring]]
testConstraint testencoding [llength [info commands testencoding]]
namespace eval utftest {
# Format of table, indexed by encoding. The encodings are not exhaustive
# but one of each kind of encoding transform (algorithmic, table-driven,
# stateful, DBCS, MBCS).
# Each element is list of lists. Nested lists have following fields
# 0 comment (no spaces, might be used to generate id's as well)
# The combination of comment and internal hex (2) should be unique.
# 1 hex representation of internal *modified* utf-8 encoding. This is the
# source string for Tcl_UtfToExternal and expected result for
# Tcl_ExternalToUtf.
# 2 hex representation in specified encoding. This is the source string for
# Tcl_ExternalToUtf and expected result for Tcl_UtfToExternal.
# 3 internal fragmentation index - where to split field 1 for fragmentation
# tests. -1 to skip
# 4 external fragmentation index - where to split field 2 for fragmentation
# tests. -1 to skip
#
# THE HEX DEFINITIONS SHOULD SEPARATE EACH CHARACTER BY WHITESPACE
# (assumed by the charlimit tests)
lappend utfExtMap {*}{
ascii {
{basic {41 42 43} {41 42 43} -1 -1}
}
utf-8 {
{bmp {41 c3a9 42} {41 c3a9 42} 2 2}
{nonbmp-frag-1 {41 f09f9880 42} {41 f09f9880 42} 2 2}
{nonbmp-frag-2 {41 f09f9880 42} {41 f09f9880 42} 3 3}
{nonbmp-frag-3 {41 f09f9880 42} {41 f09f9880 42} 4 4}
{null {41 c080 42} {41 00 42} 2 -1}
}
cesu-8 {
{bmp {41 c3a9 42} {41 c3a9 42} 2 2}
{nonbmp-frag-surr-low {41 f09f9880 42} {41 eda0bd edb880 42} 2 2}
{nonbmp-split-surr {41 f09f9880 42} {41 eda0bd edb880 42} 3 -1}
{nonbmp-frag-surr-high {41 f09f9880 42} {41 eda0bd edb880 42} 4 6}
{null {41 c080 42} {41 00 42} 2 -1}
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
iso2022-jp {
{frag-in-leadescape {58 e4b98e 5a} {58 1b2442 3843 1b2842 5a} 2 2}
{frag-in-char {58 e4b98e 5a} {58 1b2442 3843 1b2842 5a} 2 5}
{frag-in-trailescape {58 e4b98e 5a} {58 1b2442 3843 1b2842 5a} 2 8}
}
}
| < < < < < < < | | < | < < < < < | | | < < < < < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < | < | < | < < < | < < < < | < | < < < | < > > > > > > < < < < < < < < < < < < < | < | < < < < < < < < < < < < < | < < < < < < < | < | | | < < < < < < | | < < | < < < | < < < < < > | | | < < < < < | < < < < < < < < < < < < < | < < < | | < | | < < < | | | < | | < < < < < < < < | < < | < < < < < < | | > > | | | < < < | | | | < > < < > > | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
iso2022-jp {
{frag-in-leadescape {58 e4b98e 5a} {58 1b2442 3843 1b2842 5a} 2 2}
{frag-in-char {58 e4b98e 5a} {58 1b2442 3843 1b2842 5a} 2 5}
{frag-in-trailescape {58 e4b98e 5a} {58 1b2442 3843 1b2842 5a} 2 8}
}
}
# Return a binary string containing nul terminator for encoding
proc hexnuls {enc} {
return [binary encode hex [encoding convertto $enc \x00]]
}
# The C wrapper fills entire destination buffer with FF.
# Anything beyond expected output should have FF's
proc fill {bin buflen} {
return [string range "$bin[string repeat \xFF $buflen]" 0 $buflen-1]
}
proc testutf {direction enc comment hexin hexout args} {
set id $comment-[join $hexin ""]
if {$direction eq "toutf"} {
set cmd Tcl_ExternalToUtf
} else {
set cmd Tcl_UtfToExternal
}
set in [binary decode hex $hexin]
set out [binary decode hex $hexout]
set dstlen 40 ;# Should be enough for all encoding tests
set status ok
set flags [list start end]
set constraints [list testencoding]
set profiles [encoding profiles]
while {[llength $args] > 1} {
set opt [lpop args 0]
switch $opt {
-flags { set flags [lpop args 0] }
-constraints { lappend constraints {*}[lpop args 0] }
-profiles { set profiles [lpop args 0] }
-status { set status [lpop args 0]}
default {
error "Unknown option \"$opt\""
}
}
}
if {[llength $args]} {
error "No value supplied for option [lindex $args 0]."
}
set result [list $status {} [fill $out $dstlen]]
test $cmd-$enc-$id-[join $flags -] "$cmd - $enc - $hexin - $flags" -body \
[list testencoding $cmd $enc $in $flags {} $dstlen] \
-result $result -constraints $constraints
foreach profile $profiles {
set flags2 [linsert $flags end $profile]
test $cmd-$enc-$id-[join $flags2 -] "$cmd - $enc - $hexin - $flags2" -body \
[list testencoding $cmd $enc $in $flags2 {} $dstlen] \
-result $result -constraints $constraints
}
}
proc testfragment {direction enc comment hexin hexout fragindex args} {
if {$fragindex < 0} {
# Single byte encodings so no question of fragmentation
return
}
set id $comment-[join $hexin ""]-fragment
if {$direction eq "toutf"} {
set cmd Tcl_ExternalToUtf
} else {
set cmd Tcl_UtfToExternal
}
set status1 multibyte; # Return status to expect after first call
while {[llength $args] > 1} {
set opt [lpop args 0]
switch $opt {
-status1 { set status1 [lpop args 0]}
default {
error "Unknown option \"$opt\""
}
}
}
set in [binary decode hex $hexin]
set infrag [string range $in 0 $fragindex-1]
set out [binary decode hex $hexout]
set dstlen 40 ;# Should be enough for all encoding tests
test $cmd-$enc-$id-0 "$cmd - $enc - $hexin - frag=$fragindex" -constraints testencoding -body {
set frag1Result [testencoding $cmd $enc [string range $in 0 $fragindex-1] {start} 0 $dstlen frag1Read frag1Written]
lassign $frag1Result frag1Status frag1State frag1Decoded
set frag2Result [testencoding $cmd $enc [string range $in $frag1Read end] {end} $frag1State $dstlen frag2Read frag2Written]
lassign $frag2Result frag2Status frag2State frag2Decoded
set decoded [string cat [string range $frag1Decoded 0 $frag1Written-1] [string range $frag2Decoded 0 $frag2Written-1]]
list $frag1Status [expr {$frag1Read <= $fragindex}] \
$frag2Status [expr {$frag1Read+$frag2Read}] \
[expr {$frag1Written+$frag2Written}] $decoded
} -result [list $status1 1 ok [string length $in] [string length $out] $out]
if {$direction eq "toutf"} {
# Fragmentation but with no more data.
# Only check status. Content output is already checked in above test.
test $cmd-$enc-$id-1 "$cmd - $enc - $hexin - frag=$fragindex - no more data" -constraints testencoding -body {
set frag1Result [testencoding $cmd $enc [string range $in 0 $fragindex-1] {start end} 0 $dstlen frag1Read frag1Written]
lassign $frag1Result frag1Status frag1State frag1Decoded
set frag1Status
} -result syntax
}
}
proc testcharlimit {direction enc comment hexin hexout} {
set id $comment-[join $hexin ""]-charlimit
if {$direction eq "toutf"} {
set cmd Tcl_ExternalToUtf
} else {
set cmd Tcl_UtfToExternal
}
set maxchars [llength $hexout]
set in [binary decode hex $hexin]
set out [binary decode hex $hexout]
set dstlen 40 ;# Should be enough for all encoding tests
for {set nchars 0} {$nchars <= $maxchars} {incr nchars} {
set expected_bytes [binary decode hex [lrange $hexout 0 $nchars-1]]
set expected_nwritten [string length $expected_bytes]
test $cmd-$enc-$id-$nchars "$cmd - $enc - $hexin - nchars $nchars" -constraints testencoding -body {
set charlimit $nchars
lassign [testencoding $cmd $enc $in \
{start end charlimit} 0 $dstlen nread nwritten charlimit] \
status state buf
list $status $nwritten [string range $buf 0 $nwritten-1]
} -result [list [expr {$nchars == $maxchars ? "ok" : "nospace"}] $expected_nwritten $expected_bytes]
}
}
proc testspacelimit {direction enc comment hexin hexout} {
set id $comment-[join $hexin ""]-spacelimit
# Triple the input to avoid pathological short input case where
# whereby nothing is written to output. The test below
# requires $nchars > 0
set hexin $hexin$hexin$hexin
set hexout $hexout$hexout$hexout
set flags [list start end]
set constraints [list testencoding]
set maxchars [llength $hexout]
set in [binary decode hex $hexin]
set out [binary decode hex $hexout]
set dstlen [expr {[string length $out] - 1}]; # Smaller buffer than needed
if {$direction eq "toutf"} {
set cmd Tcl_ExternalToUtf
set str [encoding convertfrom $enc $in]
} else {
set cmd Tcl_UtfToExternal
set str [encoding convertfrom $enc $out]
}
# Note the tests are loose because the some encoding operations will
# stop even there is actually still room in the destination. For example,
# below only one char is written though there is room in the output.
# % testencoding Tcl_ExternalToUtf ascii abc {start end} {} 5 nread nwritten nchars
# nospace {} aÿÿÿ#
# % puts $nread,$nwritten,$nchars
# 1,1,1
#
test $cmd-$enc-$id-[join $flags -] "$cmd - $enc - $hexin - $flags" \
-constraints $constraints \
-body {
lassign [testencoding $cmd $enc $in $flags {} $dstlen nread nwritten nchars] status state buf
list \
$status \
[expr {$nread < [string length $in]}] \
[expr {$nwritten <= $dstlen}] \
[expr {$nchars > 0 && $nchars < [string length $str]}] \
[expr {[string range $out 0 $nwritten-1] eq [string range $buf 0 $nwritten-1]}]
} -result {nospace 1 1 1 1}
}
#
# Basic tests
foreach {enc testcases} $utfExtMap {
foreach testcase $testcases {
lassign $testcase {*}{comment utfhex hex internalfragindex externalfragindex}
# Basic test - TCL_ENCODING_START|TCL_ENCODING_END
# Note by default output should be terminated with \0
set encnuls [hexnuls $enc]
testutf toutf $enc $comment $hex ${utfhex}00
testutf fromutf $enc $comment $utfhex $hex$encnuls
# Test TCL_ENCODING_NO_TERMINATE
testutf toutf $enc $comment $hex $utfhex -flags {start end noterminate}
# noterminate is specific to ExternalToUtf,
# should have no effect in other direction
testutf fromutf $enc $comment $utfhex $hex$encnuls -flags {start end noterminate}
# Fragments
testfragment toutf $enc $comment $hex $utfhex $externalfragindex
testfragment fromutf $enc $comment $utfhex $hex $internalfragindex
# Char limits - note no fromutf as Tcl_UtfToExternal does not support it
testcharlimit toutf $enc $comment $hex $utfhex
# Space limits
testspacelimit toutf $enc $comment $hex $utfhex
testspacelimit fromutf $enc $comment $utfhex $hex
}
}
# Special cases - cesu2 high and low surrogates in separate fragments
# This will (correctly) return "ok", not "multibyte" after first frag
testfragment toutf cesu-8 nonbmp-split-surr \
{41 eda0bd edb880 42} {41 f09f9880 42} 4 -status1 ok
# Bug regression tests
test Tcl_UtfToExternal-bug-183a1adcc0 {buffer overflow} -body {
testencoding Tcl_UtfToExternal utf-16 A {start end} {} 1
} -result [list nospace {} \xFF] -constraints testencoding
test Tcl_ExternalToUtf-bug-5be203d6ca {
truncated prefix in table encoding
} -constraints testencoding -body {
set src \x82\x4F\x82\x50\x82
set result [list [testencoding Tcl_ExternalToUtf shiftjis $src {start tcl8} 0 16 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten]
lappend result {*}[list [testencoding Tcl_ExternalToUtf shiftjis [string range $src $srcRead end] {end tcl8} 0 10 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten]
} -result [list [list multibyte 0 \xEF\xBC\x90\xEF\xBC\x91\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF] 4 6 2 [list ok 0 \xC2\x82\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF] 1 2 1]
test Tcl_ExternalToUtf-bug-7346adc50f-strict-0 {
truncated input in escape encoding (strict)
} -constraints testencoding -body {
set src [binary decode hex 1b2442242a3b6e24]
list {*}[testencoding Tcl_ExternalToUtf iso2022-jp $src {start end strict} 0 16 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten
} -result [list syntax 2 [binary decode hex e3818ae8a9a600ffffffffffffffffff] 7 6 2]
test Tcl_ExternalToUtf-bug-7346adc50f-strict-1 {
truncated input in escape encoding (strict, partial)
} -constraints testencoding -body {
set src [binary decode hex 1b2442242a3b6e24]
list {*}[testencoding Tcl_ExternalToUtf iso2022-jp $src {start strict} 0 16 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten
} -result [list multibyte 2 [binary decode hex e3818ae8a9a600ffffffffffffffffff] 7 6 2]
test Tcl_ExternalToUtf-bug-7346adc50f-replace-0 {
truncated input in escape encoding (replace)
} -constraints testencoding -body {
set src [binary decode hex 1b2442242a3b6e24]
list {*}[testencoding Tcl_ExternalToUtf iso2022-jp $src {start end replace} 0 16 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten
} -result [list ok 2 [binary decode hex e3818ae8a9a6efbfbd00ffffffffffff] 8 9 3]
test Tcl_ExternalToUtf-bug-7346adc50f-replace-1 {
truncated input in escape encoding (replace, partial)
} -constraints testencoding -body {
set src [binary decode hex 1b2442242a3b6e24]
list {*}[testencoding Tcl_ExternalToUtf iso2022-jp $src {start replace} 0 16 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten
} -result [list multibyte 2 [binary decode hex e3818ae8a9a600ffffffffffffffffff] 7 6 2]
test Tcl_ExternalToUtf-bug-7346adc50f-tcl8-0 {
truncated input in escape encoding (tcl8)
} -constraints testencoding -body {
set src [binary decode hex 1b2442242a3b6e24]
list {*}[testencoding Tcl_ExternalToUtf iso2022-jp $src {start end tcl8} 0 16 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten
} -result [list ok 2 [binary decode hex e3818ae8a9a6efbfbd00ffffffffffff] 8 9 3]
test Tcl_ExternalToUtf-bug-7346adc50f-tcl8-1 {
truncated input in escape encoding (tcl8, partial)
} -constraints testencoding -body {
set src [binary decode hex 1b2442242a3b6e24]
list {*}[testencoding Tcl_ExternalToUtf iso2022-jp $src {start tcl8} 0 16 srcRead dstWritten charsWritten] $srcRead $dstWritten $charsWritten
} -result [list multibyte 2 [binary decode hex e3818ae8a9a600ffffffffffffffffff] 7 6 2]
}
namespace delete utftest
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
# End:
|
Changes to tests/winConsole.test.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
package require tcltest 2.5
namespace import -force ::tcltest::*
}
catch {package require twapi} ;# Only to bring window to foreground. Not critical
::tcltest::ConstraintInitializer haveThread { expr {![catch {package require Thread}]} }
tcltest::testConstraint havePowershell [tcl::mathop::ne [auto_execok powershell] ""]
| < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package require tcltest 2.5
namespace import -force ::tcltest::*
}
catch {package require twapi} ;# Only to bring window to foreground. Not critical
::tcltest::ConstraintInitializer haveThread { expr {![catch {package require Thread}]} }
tcltest::testConstraint havePowershell [tcl::mathop::ne [auto_execok powershell] ""]
# Prompt user for a yes/no response
proc yesno {question {default "Y"}} {
set answer ""
# Make sure we are seen but catch because ui and console
# packages may not be available
catch {twapi::set_foreground_window [twapi::get_console_window]}
|
| ︙ | ︙ | |||
428 429 430 431 432 433 434 |
} -body {
thread::send $tid {puts [thread::id]}
yesno "Did you see $tid printed?"
} -result 1
# Bug f10d91c2 - dead console busy loop
# Test script courtesy @JulianNoble
| < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
} -body {
thread::send $tid {puts [thread::id]}
yesno "Did you see $tid printed?"
} -result 1
# Bug f10d91c2 - dead console busy loop
# Test script courtesy @JulianNoble
test console-bug-f10d91c2 {
Test termination of console process with extreme prejudice
} -constraints {win havePowershell} -setup {
set tclScript [tcltest::makeFile {
#stdin fileevent + 1s heartbeat. Optional argv 0: heartbeat file path.
if {[llength $argv]} {
set hbf [lindex $argv 0]
} else {
set hbf [file join [file dirname [info script]] heartbeat.txt]
}
chan configure stdin -blocking 0
chan event stdin readable {
set status [catch {read stdin} data]
puts stderr "readable fired"
flush stderr
if {$status} {
puts stderr "Error: $data - exiting"
exit 0
} else {
if {[chan eof stdin]} {
puts stderr "eof - exiting"
exit 0
}
}
}
proc heartbeat {} {
set f [open $::hbf a]
puts $f "[clock format [clock seconds] -format %H:%M:%S] alive - pid [pid]"
close $f
after 1000 heartbeat
}
heartbeat
puts stderr "armed - pid [pid]"
flush stderr
vwait ::forever
} bug-f10d91.tcl ]
# The powershell driver script
set psProgram {
param([string]$Tclsh = '%TCLINTERP%')
$dir = Join-Path $env:TEMP ("deadconsole_" + (Get-Date -Format HHmmss_fff))
New-Item -ItemType Directory $dir | Out-Null
$err = Join-Path $dir err.txt
$hb = Join-Path $dir heartbeat.txt
# 1. launch the payload under its OWN dedicated CLASSIC conhost (bypasses Windows Terminal)
$con = Start-Process -WindowStyle Hidden -PassThru conhost.exe -ArgumentList `
"$env:SystemRoot\System32\cmd.exe /c `"$Tclsh %TCLSCRIPT% $hb 2> $err`""
# 2. wait for the payload to arm and report its pid
$tclpid = $null
foreach ($i in 1..20) {
Start-Sleep -Milliseconds 500
if ((Test-Path $err) -and ((Get-Content $err -Raw) -match 'armed - pid (\d+)')) {
$tclpid = [int]$Matches[1]; break
}
}
if (-not $tclpid) { throw "payload never armed (see $err)" }
"conhost $($con.Id), tclsh $tclpid armed; baselining..."
$p = Get-Process -Id $tclpid; $c0 = $p.CPU; Start-Sleep 3; $p.Refresh()
"idle baseline: $($p.CPU - $c0) cpu-sec over 3s (expect ~0)"
# 3. force-kill the console server (TerminateProcess - no CTRL_CLOSE_EVENT is generated)
|
| ︙ | ︙ |
Changes to tests/winDde.test.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 |
}
source [file join [file dirname [info script]] tcltests.tcl]
testConstraint dde 0
if {[testConstraint win]} {
if {![catch {
::tcltest::loadTestedCommands
| | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
}
source [file join [file dirname [info script]] tcltests.tcl]
testConstraint dde 0
if {[testConstraint win]} {
if {![catch {
::tcltest::loadTestedCommands
set ::ddever [package require dde 1.4.6]
set ::ddelib [info loaded {} Dde]}]} {
testConstraint dde 1
}
}
testConstraint notWine [expr {![info exists ::env(CI_USING_WINE)]}]
|
| ︙ | ︙ | |||
101 102 103 104 105 106 107 |
gets $f line
return $f
}
# -------------------------------------------------------------------------
test winDde-1.0 {check if we are testing the right dll} {win dde} {
set ::ddever
| | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
gets $f line
return $f
}
# -------------------------------------------------------------------------
test winDde-1.0 {check if we are testing the right dll} {win dde} {
set ::ddever
} {1.4.6}
test winDde-1.1 {Settings the server's topic name} -constraints dde -body {
list [dde servername foobar] [dde servername] [dde servername self]
} -result {foobar foobar self}
test winDde-2.1 {Checking for other services} -constraints dde -body {
expr {[llength [dde services {} {}]] >= 0}
|
| ︙ | ︙ |
Changes to tests/winFCmd.test.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
# If in a CI environment, file system changes are ephemeral anyways so
# always set allowfilesecuritychanges constraint
if {![testConstraint notInCIenv]} {
testConstraint allowfilesecuritychanges 1
}
| < < < < < < < < < < < < < < < < < < < | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# If in a CI environment, file system changes are ephemeral anyways so
# always set allowfilesecuritychanges constraint
if {![testConstraint notInCIenv]} {
testConstraint allowfilesecuritychanges 1
}
proc createfile {file {string a}} {
set f [open $file w]
puts -nonewline $f $string
close $f
return $string
}
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
# an empty string as its value
# SDDL syntax:
# O: owner SID
# G: group SID
# D: DACL - optional control flags, followed by parenthesized ACE list
# S: SACL - ditto
set sddlRe {(?x)
| | | | | | | | | | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# an empty string as its value
# SDDL syntax:
# O: owner SID
# G: group SID
# D: DACL - optional control flags, followed by parenthesized ACE list
# S: SACL - ditto
set sddlRe {(?x)
^
(?: (O:) ( [A-Za-z0-9-]+? ) (?=G:|D:|S:|$) )?
(?: (G:) ( [A-Za-z0-9-]+? ) (?=D:|S:|$) )?
(?: (D:) ((?: [A-Z]+ )? (?: \( [^)]* \) )*))?
(?: (S:) ((?: [A-Z]+ )? (?: \( [^)]* \) )*))?
$
}
if {![regexp $sddlRe $sddl -> ownerTag owner groupTag group daclTag dacl saclTag sacl]} {
error "Could not parse SDDL \"$sddl\""
}
set result [dict create]
foreach field {owner group dacl sacl} {
if {[set ${field}Tag] ne ""} {
dict set result $field [set $field]
}
}
return $result
}
proc parseSddlAcl {acl} {
# Parse a SDDL ACL component consisting of optional leading flags
# (upper case letters) followed by optional joined parenthisized expressions
|
| ︙ | ︙ | |||
296 297 298 299 300 301 302 |
file delete /tf1
testfile mv [pwd] /tf1
} -returnCodes error -result EACCES
test winFCmd-1.21 {TclpRenameFile: long src} -setup {
cleanup
} -constraints {win testfile} -body {
testfile mv $longname tf1
| | | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
file delete /tf1
testfile mv [pwd] /tf1
} -returnCodes error -result EACCES
test winFCmd-1.21 {TclpRenameFile: long src} -setup {
cleanup
} -constraints {win testfile} -body {
testfile mv $longname tf1
} -returnCodes error -result ENAMETOOLONG
test winFCmd-1.22 {TclpRenameFile: long dst} -setup {
cleanup
} -constraints {win testfile} -body {
createfile tf1
testfile mv tf1 $longname
} -returnCodes error -result ENAMETOOLONG
test winFCmd-1.23 {TclpRenameFile: move dir into self} -setup {
cleanup
} -constraints {win testfile notInCIenv} -body {
file mkdir td1
testfile mv [pwd]/td1 td1/td2
} -returnCodes error -result EINVAL
test winFCmd-1.24 {TclpRenameFile: move a root dir} -setup {
|
| ︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 |
test winFCmd-16.8 {Windows file normalization} -constraints {win} -body {
file norm ///bar
} -result "${d}:/bar"
test winFCmd-16.9 {Windows file normalization} -constraints {win} -body {
file norm /bar/foo
} -result "${d}:/bar/foo"
if {$d eq "C"} { set dd "D" } else { set dd "C" }
| | < < < < < < | | | 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 |
test winFCmd-16.8 {Windows file normalization} -constraints {win} -body {
file norm ///bar
} -result "${d}:/bar"
test winFCmd-16.9 {Windows file normalization} -constraints {win} -body {
file norm /bar/foo
} -result "${d}:/bar/foo"
if {$d eq "C"} { set dd "D" } else { set dd "C" }
test winFCmd-16.10 {Windows file normalization} -constraints {win} -body {
file norm ${dd}:foo
} -result "${dd}:/foo"
test winFCmd-16.11 {Windows file normalization} -body {
cd ${d}:
cd $cdrom
cd ${d}:
cd $cdrom
# Must not crash
set result "no crash"
|
| ︙ | ︙ | |||
1323 1324 1325 1326 1327 1328 1329 |
set ::env(HOME) ${d}:
cd
pwd
} -cleanup {
set ::env(HOME) $oldhome
cd $pwd
} -result $pwd
| < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 |
set ::env(HOME) ${d}:
cd
pwd
} -cleanup {
set ::env(HOME) $oldhome
cd $pwd
} -result $pwd
# Following test only run under constraint allowfilesecuritychanges to
# protect against consequences from bugs that clobber permissions. Bitter
# experience - write-protected my entire work tree and wondered why compiles
# failed.
proc test_bug_d40d8db3 {id comment subdir} {
set testScript {
test @ID@ {
@COMMENT@
} -constraints {
win testchmod testfilesddl allowfilesecuritychanges
} -setup {
set dir [tcltest::makeDirectory @ID@]
if {[file exists $dir]} {
testchmod 0o777 $dir
file delete -force $dir
if {[file exists $dir]} {
error "Could not delete $dir"
}
}
set aclTarget [file join $dir @SUBDIR@]
set path [file join $aclTarget tail]
file mkdir $path
set secd [parseSddl [testfilesddl $aclTarget]]
set dacl [dict getdef $secd dacl ""]
lassign [parseSddlAcl [dict getdef $secd dacl ""]] aclFlags aces
ledit aces 0 -1 "(D;;0x1;;;[dict get $secd owner])"
set sddl "D:$aclFlags[join $aces {}]"
testfilesddl $aclTarget $sddl
} -cleanup {
testchmod 0o777 $path
testchmod 0o777 $aclTarget
testchmod 0o777 $dir
file delete -force $dir
unset -nocomplain dir path secd dacl aclFlags aces sddl
} -body {
file normalize $path
} -result [file join [tcltest::temporaryDirectory] @ID@ @SUBDIR@ tail]
}
uplevel 1 [string map [list @ID@ $id @COMMENT@ $comment @SUBDIR@ $subdir] $testScript]
}
test_bug_d40d8db3 winFCmd-16.25.1 {
Windows file normalization - Bug d40d8db3 - denied dir read
} middledir
test_bug_d40d8db3 winFCmd-16.25.2 {
|
| ︙ | ︙ | |||
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 |
} -constraints haveTwoDrives -body {
glob $pathInOther/$pathInOther
} -result {}
test winFCmd-20.2 {
Bug b0682c3c24 - absolute paths in pattern (-directory)
} -constraints haveTwoDrives -body {
glob -directory $pathInOther $pathInOther
} -result {}
unset -nocomplain drive otherDrive pathInOther
| > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 |
} -constraints haveTwoDrives -body {
glob $pathInOther/$pathInOther
} -result {}
test winFCmd-20.2 {
Bug b0682c3c24 - absolute paths in pattern (-directory)
} -constraints haveTwoDrives -body {
puts $pathInOther
glob -directory $pathInOther $pathInOther
} -result {}
unset -nocomplain drive otherDrive pathInOther
# This block of code used to occur after the "return" call, so I'm
# commenting it out and assuming that this code is still under construction.
#foreach source {tef ted tnf tnd "" nul com1} {
# foreach chmodsrc {000 755} {
# foreach dest "tfn tfe tdn tdempty tdfull td1/td2 $p $p/td1 {} nul" {
# foreach chmoddst {000 755} {
|
| ︙ | ︙ |
Changes to tests/winPipe.test.
| ︙ | ︙ | |||
188 189 190 191 192 193 194 |
close $f
set x 1
} else {
set line [read $f ]
set result "$result$line"
}
}
| | | 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
close $f
set x 1
} else {
set line [read $f ]
set result "$result$line"
}
}
set f [open "|[list $cat32] < $path(big) 2> $path(stderr)" r]
fconfigure $f -buffering none -blocking 0
fileevent $f readable "readResults $f"
set x 0
set result ""
vwait x
list $result $x [contents $path(stderr)]
} "{$big} 1 stderr32"
|
| ︙ | ︙ | |||
322 323 324 325 326 327 328 |
variable path
if {![info exists path(echoArgs.tcl)] || ![file exists $path(echoArgs.tcl)]} {
set path(echoArgs.tcl) [makeFile {
puts "[list [file tail $argv0] {*}$argv]"
} echoArgs.tcl]
}
if {![info exists path(echoArgs.bat)] || ![file exists $path(echoArgs.bat)]} {
| | | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
variable path
if {![info exists path(echoArgs.tcl)] || ![file exists $path(echoArgs.tcl)]} {
set path(echoArgs.tcl) [makeFile {
puts "[list [file tail $argv0] {*}$argv]"
} echoArgs.tcl]
}
if {![info exists path(echoArgs.bat)] || ![file exists $path(echoArgs.bat)]} {
set path(echoArgs.bat) [makeFile "@[file native [interpreter]] $path(echoArgs.tcl) %*" "echoArgs.bat"]
}
set cmds [list [list [interpreter] $path(echoArgs.tcl)]]
if {"exe-only" ni $flags} {
if {"batch2" ni $flags} {
lappend cmds [list $path(echoArgs.bat)]
} else {
if {![info exists path(echoArgs2.bat)] || ![file exists $path(echoArgs2.bat)]} {
set path(echoArgs2.bat) [makeFile \
"@[file native [interpreter]] $path(echoArgs.tcl) %*" \
"echo(Cmd)Test Args & Batch.bat" [makeDirectory test(Dir)Check]]
}
lappend cmds [list $path(echoArgs2.bat)]
}
}
set broken {}
foreach args $args {
|
| ︙ | ︙ |
Changes to tests/zipfs.test.
| ︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 |
file delete -force $dst
} -cleanup {
file delete -force $dst
cleanup
} -body {
file copy [file join $defMountPt testdir] $dst
zipfs find $dst
| | | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 |
file delete -force $dst
} -cleanup {
file delete -force $dst
cleanup
} -body {
file copy [file join $defMountPt testdir] $dst
zipfs find $dst
} -result [file join [temporaryDirectory] dstdir.tmp test2]
test zipfs-file-copymount-fromzip-new {Copy archive mount to native} -setup {
mount [zippath test.zip]
set dst [file join [temporaryDirectory] dstdir2.tmp]
file delete -force $dst
} -cleanup {
file delete -force $dst
cleanup
|
| ︙ | ︙ | |||
1928 1929 1930 1931 1932 1933 1934 |
test bug-8259d74a64 "Crash exiting with open files" -setup {
set path [zippath test.zip]
set script "zipfs mount $path /\n"
append script {open [zipfs root]test} \n
append script "exit\n"
} -body {
| | | 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 |
test bug-8259d74a64 "Crash exiting with open files" -setup {
set path [zippath test.zip]
set script "zipfs mount $path /\n"
append script {open [zipfs root]test} \n
append script "exit\n"
} -body {
set fd [open |[info nameofexecutable] r+]
puts $fd $script
flush $fd
read $fd
close $fd
} -result ""
# Following will only show a leak with valgrind
|
| ︙ | ︙ |
Changes to tools/README.
1 2 3 4 5 6 7 8 9 10 | This directory contains unsupported tools used to build parts of Tcl for distribution. uniClass.tcl -- Script for generating regexp class tables from the Tcl "string is" classes Generating HTML files. This script is very picky about the organization of man pages, effectively acting as a style enforcer. | > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | This directory contains unsupported tools used to build parts of Tcl for distribution. uniParse.tcl -- Script for converting the Unicode character database into a compact table stored in generic/tclUniData.c. uniClass.tcl -- Script for generating regexp class tables from the Tcl "string is" classes Generating HTML files. This script is very picky about the organization of man pages, effectively acting as a style enforcer. |
| ︙ | ︙ |
Changes to tools/encoding/txt2enc.c.
1 2 3 4 5 6 7 | /* * txt2enc.c -- * * Simple program to compile up the encodings tables from the CD that * came with "The Unicode Standard, Version 2.0" into a form that can * be quickly loaded into Tcl. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * txt2enc.c -- * * Simple program to compile up the encodings tables from the CD that * came with "The Unicode Standard, Version 2.0" into a form that can * be quickly loaded into Tcl. * * Copyright (c) 1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) txt2enc.c 1.1 98/01/28 11:42:09 */ |
| ︙ | ︙ |
Changes to tools/findBadExternals.tcl.
| ︙ | ︙ | |||
17 18 19 20 21 22 23 |
#----------------------------------------------------------------------
proc main {argc argv} {
if {$argc != 1} {
puts stderr "syntax is: [info script] libtcl"
return 1
}
| < < | | > > | > | | > | > | | > > > > | | | | | | | < < | < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#----------------------------------------------------------------------
proc main {argc argv} {
if {$argc != 1} {
puts stderr "syntax is: [info script] libtcl"
return 1
}
switch -exact -- $::tcl_platform(platform) {
unix -
macosx {
set status [catch {
exec nm --extern-only --defined-only [lindex $argv 0]
} result]
}
windows {
set status [catch {
exec dumpbin /exports [lindex $argv 0]
} result]
}
}
if {$status != 0 && $::errorCode ne "NONE"} {
puts $result
return 1
}
foreach line [split $result \n] {
if {! [string match {* [Tt]cl*} $line]} {
puts $line
}
}
return 0
}
exit [main $::argc $::argv]
|
Changes to tools/mkVfs.tcl.
| ︙ | ︙ | |||
62 63 64 65 66 67 68 |
set PLATFORM [lindex $argv 2]
set TKDLL [lindex $argv 3]
set TKVER [lindex $argv 4]
puts "Building [file tail $TCL_SCRIPT_DIR] for $PLATFORM"
copyDir ${TCLSRC_ROOT}/library ${TCL_SCRIPT_DIR}
| | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
set PLATFORM [lindex $argv 2]
set TKDLL [lindex $argv 3]
set TKVER [lindex $argv 4]
puts "Building [file tail $TCL_SCRIPT_DIR] for $PLATFORM"
copyDir ${TCLSRC_ROOT}/library ${TCL_SCRIPT_DIR}
if {$PLATFORM == "windows"} {
set ddedll [glob -nocomplain ${TCLSRC_ROOT}/win/tcldde*.dll]
puts "DDE DLL $ddedll"
if {$ddedll != {}} {
file copy $ddedll ${TCL_SCRIPT_DIR}/dde
}
set regdll [glob -nocomplain ${TCLSRC_ROOT}/win/tclreg*.dll]
puts "REG DLL $ddedll"
|
| ︙ | ︙ |
Changes to tools/tcltk-man2html.tcl.
| ︙ | ︙ | |||
639 640 641 642 643 644 645 |
Tk_Justify Tk_GetJustify
Ttk_Theme Ttk_GetTheme
}
array set exclude_refs_map {
bind.n {button destroy option}
clock.n {next}
history.n {exec}
| | < < < | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
Tk_Justify Tk_GetJustify
Ttk_Theme Ttk_GetTheme
}
array set exclude_refs_map {
bind.n {button destroy option}
clock.n {next}
history.n {exec}
next.n {unknown}
zlib.n {binary close filename text}
canvas.n {bitmap text}
console.n {eval}
checkbutton.n {image}
clipboard.n {string}
entry.n {string}
event.n {return}
font.n {menu}
getOpenFile.n {file open text}
grab.n {global}
interp.n {time}
menu.n {checkbutton radiobutton}
messageBox.n {error info}
options.n {bitmap image set}
radiobutton.n {image}
safe.n {join split}
scale.n {label variable}
|
| ︙ | ︙ |
Changes to tools/tsdPerf.c.
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <tcl.h>
extern DLLEXPORT Tcl_LibraryInitProc Tsdperf_Init;
static Tcl_ThreadDataKey key;
typedef struct {
Tcl_WideInt value;
} TsdPerf;
static int
| | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include <tcl.h>
extern DLLEXPORT Tcl_LibraryInitProc Tsdperf_Init;
static Tcl_ThreadDataKey key;
typedef struct {
Tcl_WideInt value;
} TsdPerf;
static int
tsdPerfSetObjCmd(void *cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) {
TsdPerf *perf = Tcl_GetThreadData(&key, sizeof(TsdPerf));
Tcl_WideInt i;
if (2 != objc) {
Tcl_WrongNumArgs(interp, 1, objv, "value");
return TCL_ERROR;
}
if (TCL_OK != Tcl_GetWideIntFromObj(interp, objv[1], &i)) {
return TCL_ERROR;
}
perf->value = i;
return TCL_OK;
}
static int
tsdPerfGetObjCmd(void *cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) {
TsdPerf *perf = Tcl_GetThreadData(&key, sizeof(TsdPerf));
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(perf->value));
return TCL_OK;
}
int
Tsdperf_Init(Tcl_Interp *interp) {
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "tsdPerfSet", tsdPerfSetObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "tsdPerfGet", tsdPerfGetObjCmd, NULL, NULL);
return TCL_OK;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to tools/uniClass.tcl.
1 2 3 4 5 6 7 8 9 10 |
#!/bin/sh
# The next line is executed by /bin/sh, but not tcl \
exec tclsh "$0" ${1+"$@"}
#
# uniClass.tcl --
#
# Generates the character ranges and singletons that are used in
# generic/regc_locale.c for translation of character classes.
# This file must be generated using a tclsh that contains the
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#!/bin/sh
# The next line is executed by /bin/sh, but not tcl \
exec tclsh "$0" ${1+"$@"}
#
# uniClass.tcl --
#
# Generates the character ranges and singletons that are used in
# generic/regc_locale.c for translation of character classes.
# This file must be generated using a tclsh that contains the
# correct corresponding tclUniData.c file (generated by uniParse.tcl)
# in order for the class ranges to match.
#
proc emitRange {first last} {
global ranges numranges chars numchars extchars extranges
if {$first < ($last-1)} {
|
| ︙ | ︙ |
Added tools/uniParse.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
# uniParse.tcl --
#
# This program parses the UnicodeData file and generates the
# corresponding tclUniData.c file with compressed character
# data tables. The input to this program should be the latest
# UnicodeData file from:
# ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
#
# Copyright © 1998-1999 Scriptics Corporation.
# All rights reserved.
namespace eval uni {
set shift 5; # number of bits of data within a page
# This value can be adjusted to find the
# best split to minimize table size
variable pMap; # map from page to page index, each entry is
# an index into the pages table, indexed by
# page number
variable pages; # map from page index to page info, each
# entry is a list of indices into the groups
# table, the list is indexed by the offset
variable groups; # list of character info values, indexed by
# group number, initialized with the
# unassigned character group
variable categories {
Cn Lu Ll Lt Lm Lo Mn Me Mc Nd Nl No Zs Zl Zp
Cc Cf Co Cs Pc Pd Ps Pe Pi Pf Po Sm Sc Sk So
}; # Ordered list of character categories, must
# match the enumeration in the header file.
}
proc uni::getValue {items index} {
variable categories
# Extract character info
set category [lindex $items 2]
if {[scan [lindex $items 12] %x toupper] == 1} {
set toupper [expr {$index - $toupper}]
} else {
set toupper 0
}
if {[scan [lindex $items 13] %x tolower] == 1} {
set tolower [expr {$tolower - $index}]
} else {
set tolower 0
}
if {[scan [lindex $items 14] %x totitle] == 1} {
set totitle [expr {$index - $totitle}]
} elseif {$tolower} {
set totitle 0
} else {
set totitle $toupper
}
set categoryIndex [lsearch -exact $categories $category]
if {$categoryIndex < 0} {
error "Unexpected character category: $index($category)"
}
return [list $categoryIndex $toupper $tolower $totitle]
}
proc uni::getGroup {value} {
variable groups
set gIndex [lsearch -exact $groups $value]
if {$gIndex < 0} {
set gIndex [llength $groups]
lappend groups $value
}
return $gIndex
}
proc uni::addPage {info} {
variable pMap
variable pages
variable shift
set pIndex [lsearch -exact $pages $info]
if {$pIndex < 0} {
set pIndex [llength $pages]
lappend pages $info
}
lappend pMap [expr {$pIndex << $shift}]
return
}
proc uni::buildTables {data} {
variable shift
variable pMap {}
variable pages {}
variable groups {{0 0 0 0}}
variable next 0
set info {} ;# temporary page info
set mask [expr {(1 << $shift) - 1}]
foreach line [split $data \n] {
if {$line eq ""} {
if {!($next & $mask)} {
# next character is already on page boundary
continue
}
# fill remaining page
set line [format %X [expr {($next-1)|$mask}]]
append line ";;Cn;0;ON;;;;;N;;;;;\n"
}
set items [split $line \;]
scan [lindex $items 0] %x index
if {$index > 0x3FFFF} then {
# Ignore characters > plane 3
continue
}
set index [format %d $index]
set gIndex [getGroup [getValue $items $index]]
# Since the input table omits unassigned characters, these will
# show up as gaps in the index sequence. There are a few special cases
# where the gaps correspond to a uniform block of assigned characters.
# These are indicated as such in the character name.
# Enter all unassigned characters up to the current character.
if {($index > $next) \
&& ![regexp "Last>$" [lindex $items 1]]} {
for {} {$next < $index} {incr next} {
lappend info 0
if {($next & $mask) == $mask} {
addPage $info
set info {}
}
}
}
# Enter all assigned characters up to the current character
for {set i $next} {$i <= $index} {incr i} {
# Add the group index to the info for the current page
lappend info $gIndex
# If this is the last entry in the page, add the page
if {($i & $mask) == $mask} {
addPage $info
set info {}
}
}
set next [expr {$index + 1}]
}
return
}
proc uni::main {} {
global argc argv0 argv
variable pMap
variable pages
variable groups
variable shift
variable next
if {$argc != 2} {
puts stderr "\nusage: $argv0 <datafile> <outdir>\n"
exit 1
}
set f [open [lindex $argv 0] r]
set data [read $f]
close $f
buildTables $data
puts "X = [llength $pMap] Y= [llength $pages] A= [llength $groups]"
set size [expr {[llength $pMap]*2 + ([llength $pages]<<$shift)}]
puts "shift = $shift, space = $size"
set f [open [file join [lindex $argv 1] tclUniData.c] w]
fconfigure $f -translation lf -encoding utf-8
puts $f "/*
* tclUniData.c --
*
* Declarations of Unicode character information tables. This file is
* automatically generated by the tools/uniParse.tcl script. Do not
* modify this file by hand.
*
* Copyright © 1998 Scriptics Corporation.
* All rights reserved.
*/
/*
* A 16-bit Unicode character is split into two parts in order to index
* into the following tables. The lower OFFSET_BITS comprise an offset
* into a page of characters. The upper bits comprise the page number.
*/
#define OFFSET_BITS $shift
/*
* The pageMap is indexed by page number and returns an alternate page number
* that identifies a unique page of characters. Many Unicode characters map
* to the same alternate page number.
*/
static const unsigned short pageMap\[\] = {"
set line " "
set last [expr {[llength $pMap] - 1}]
for {set i 0} {$i <= $last} {incr i} {
if {$i == [expr {0x10000 >> $shift}]} {
set line [string trimright $line " \t,"]
puts $f $line
set lastpage [expr {[lindex $line end] >> $shift}]
puts stdout "lastpage: $lastpage"
puts $f "#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8"
set line " ,"
}
append line [lindex $pMap $i]
if {$i != $last} {
append line ", "
}
if {[string length $line] > 70} {
puts $f [string trimright $line]
set line " "
}
}
puts $f $line
puts $f "#endif /* TCL_UTF_MAX > 3 */"
puts $f "};
/*
* The groupMap is indexed by combining the alternate page number with
* the page offset and returns a group number that identifies a unique
* set of character attributes.
*/
static const unsigned char groupMap\[\] = {"
set line " "
set lasti [expr {[llength $pages] - 1}]
for {set i 0} {$i <= $lasti} {incr i} {
set page [lindex $pages $i]
set lastj [expr {[llength $page] - 1}]
if {$i == ($lastpage + 1)} {
puts $f [string trimright $line " \t,"]
puts $f "#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8"
set line " ,"
}
for {set j 0} {$j <= $lastj} {incr j} {
append line [lindex $page $j]
if {$j != $lastj || $i != $lasti} {
append line ", "
}
if {[string length $line] > 70} {
puts $f [string trimright $line]
set line " "
}
}
}
puts $f $line
puts $f "#endif /* TCL_UTF_MAX > 3 */"
puts $f "};
/*
* Each group represents a unique set of character attributes. The attributes
* are encoded into a 32-bit value as follows:
*
* Bits 0-4 Character category: see the constants listed below.
*
* Bits 5-7 Case delta type: 000 = identity
* 010 = add delta for lower
* 011 = add delta for lower, add 1 for title
* 100 = subtract delta for title/upper
* 101 = sub delta for upper, sub 1 for title
* 110 = sub delta for upper, add delta for lower
* 111 = subtract delta for upper
*
* Bits 8-31 Case delta: delta for case conversions. This should be the
* highest field so we can easily sign extend.
*/
static const int groups\[\] = {"
set line " "
set last [expr {[llength $groups] - 1}]
for {set i 0} {$i <= $last} {incr i} {
foreach {type toupper tolower totitle} [lindex $groups $i] {}
# Compute the case conversion type and delta
if {$totitle} {
if {$totitle == $toupper} {
# subtract delta for title or upper
set case 4
set delta $toupper
if {$tolower} {
error "New case conversion type needed: $toupper $tolower $totitle"
}
} elseif {$toupper} {
# subtract delta for upper, subtract 1 for title
set case 5
set delta $toupper
if {($totitle != 1) || $tolower} {
error "New case conversion type needed: $toupper $tolower $totitle"
}
} else {
# add delta for lower, add 1 for title
set case 3
set delta $tolower
if {$totitle != -1} {
error "New case conversion type needed: $toupper $tolower $totitle"
}
}
} elseif {$toupper} {
set delta $toupper
if {$tolower == $toupper} {
# subtract delta for upper, add delta for lower
set case 6
} elseif {!$tolower} {
# subtract delta for upper
set case 7
} else {
error "New case conversion type needed: $toupper $tolower $totitle"
}
} elseif {$tolower} {
# add delta for lower
set case 2
set delta $tolower
} else {
# noop
set case 0
set delta 0
}
append line [expr {($delta << 8) | ($case << 5) | $type}]
if {$i != $last} {
append line ", "
}
if {[string length $line] > 65} {
puts $f [string trimright $line]
set line " "
}
}
puts $f $line
puts -nonewline $f "};
#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8
# define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1FFFFF) >= [format 0x%X $next])
#else
# define UNICODE_OUT_OF_RANGE(ch) (((ch) & 0x1F0000) != 0)
#endif
/*
* The following constants are used to determine the category of a
* Unicode character.
*/
enum {
UNASSIGNED,
UPPERCASE_LETTER,
LOWERCASE_LETTER,
TITLECASE_LETTER,
MODIFIER_LETTER,
OTHER_LETTER,
NON_SPACING_MARK,
ENCLOSING_MARK,
COMBINING_SPACING_MARK,
DECIMAL_DIGIT_NUMBER,
LETTER_NUMBER,
OTHER_NUMBER,
SPACE_SEPARATOR,
LINE_SEPARATOR,
PARAGRAPH_SEPARATOR,
CONTROL,
FORMAT,
PRIVATE_USE,
SURROGATE,
CONNECTOR_PUNCTUATION,
DASH_PUNCTUATION,
OPEN_PUNCTUATION,
CLOSE_PUNCTUATION,
INITIAL_QUOTE_PUNCTUATION,
FINAL_QUOTE_PUNCTUATION,
OTHER_PUNCTUATION,
MATH_SYMBOL,
CURRENCY_SYMBOL,
MODIFIER_SYMBOL,
OTHER_SYMBOL
};
/*
* The following macros extract the fields of the character info. The
* GetDelta() macro is complicated because we can't rely on the C compiler
* to do sign extension on right shifts.
*/
#define GetCaseType(info) (((info) & 0xE0) >> 5)
#define GetCategory(ch) (GetUniCharInfo(ch) & 0x1F)
#define GetDelta(info) ((info) >> 8)
/*
* This macro extracts the information about a character from the
* Unicode character tables.
*/
#if TCL_UTF_MAX > 3 || TCL_MAJOR_VERSION > 8
# define GetUniCharInfo(ch) (groups\[groupMap\[pageMap\[((ch) & 0x1FFFFF) >> OFFSET_BITS\] | ((ch) & ((1 << OFFSET_BITS)-1))\]\])
#else
# define GetUniCharInfo(ch) (groups\[groupMap\[pageMap\[((ch) & 0xFFFF) >> OFFSET_BITS\] | ((ch) & ((1 << OFFSET_BITS)-1))\]\])
#endif
"
close $f
}
uni::main
return
|
Changes to unix/Makefile.in.
| ︙ | ︙ | |||
222 223 224 225 226 227 228 | AC_FLAGS = @DEFS@ AR = @AR@ RANLIB = @RANLIB@ DTRACE = @DTRACE@ SRC_DIR = @srcdir@ TOP_DIR = @TCL_SRC_DIR@ BUILD_DIR = @builddir@ | < < | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
AC_FLAGS = @DEFS@
AR = @AR@
RANLIB = @RANLIB@
DTRACE = @DTRACE@
SRC_DIR = @srcdir@
TOP_DIR = @TCL_SRC_DIR@
BUILD_DIR = @builddir@
GENERIC_DIR = $(TOP_DIR)/generic
COMPAT_DIR = $(TOP_DIR)/compat
TOOL_DIR = $(TOP_DIR)/tools
UNIX_DIR = $(TOP_DIR)/unix
MAC_OSX_DIR = $(TOP_DIR)/macosx
PKGS_DIR = $(TOP_DIR)/pkgs
# Must be absolute because of the cd dltest $(DLTEST_DIR)/configure below.
DLTEST_DIR = @TCL_SRC_DIR@/unix/dltest
# Must be absolute to so the corresponding tcltest's tcl_library is absolute.
TCL_BUILDTIME_LIBRARY = @TCL_BUILDTIME_LIBRARY@
ZLIB_DIR = ${COMPAT_DIR}/zlib
ZLIB_INCLUDE = @ZLIB_INCLUDE@
TOMMATH_DIR = $(TOP_DIR)/libtommath
TOMMATH_INCLUDE = @TOMMATH_INCLUDE@
CC = @CC@
OBJEXT = @OBJEXT@
#CC = purify -best-effort @CC@ -DPURIFY
# Flags to be passed to installManPage to control how the manpages should be
|
| ︙ | ︙ | |||
279 280 281 282 283 284 285 |
#--------------------------------------------------------------------------
STUB_CC_SWITCHES = -I"${BUILD_DIR}" -I${UNIX_DIR} -I${GENERIC_DIR} -I${TOMMATH_DIR} \
${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} \
${AC_FLAGS} ${ENV_FLAGS} ${EXTRA_CFLAGS} @EXTRA_CC_SWITCHES@ \
${NO_DEPRECATED_FLAGS} -DMP_FIXED_CUTOFFS
| | | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
#--------------------------------------------------------------------------
STUB_CC_SWITCHES = -I"${BUILD_DIR}" -I${UNIX_DIR} -I${GENERIC_DIR} -I${TOMMATH_DIR} \
${CFLAGS} ${CFLAGS_WARNING} ${SHLIB_CFLAGS} \
${AC_FLAGS} ${ENV_FLAGS} ${EXTRA_CFLAGS} @EXTRA_CC_SWITCHES@ \
${NO_DEPRECATED_FLAGS} -DMP_FIXED_CUTOFFS
CC_SWITCHES = $(STUB_CC_SWITCHES) -DBUILD_tcl
APP_CC_SWITCHES = $(STUB_CC_SWITCHES) @EXTRA_APP_CC_SWITCHES@
LIBS = @TCL_LIBS@
DEPEND_SWITCHES = ${CFLAGS} -I${UNIX_DIR} -I${GENERIC_DIR} \
${AC_FLAGS} ${EXTRA_CFLAGS} @EXTRA_CC_SWITCHES@
|
| ︙ | ︙ | |||
304 305 306 307 308 309 310 | GENERIC_OBJS = regcomp.o regexec.o regfree.o regerror.o tclAlloc.o \ tclArithSeries.o tclAssembly.o tclAsync.o tclBasic.o tclBinary.o \ tclCkalloc.o tclClock.o tclClockFmt.o tclCmdAH.o tclCmdIL.o tclCmdMZ.o \ tclCompCmds.o tclCompCmdsGR.o tclCompCmdsSZ.o tclCompExpr.o \ tclCompile.o tclConfig.o tclDate.o tclDictObj.o tclDisassemble.o \ tclEncoding.o tclEnsemble.o \ tclEnv.o tclEvent.o tclExecute.o tclFCmd.o tclFileName.o tclGet.o \ | | | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | GENERIC_OBJS = regcomp.o regexec.o regfree.o regerror.o tclAlloc.o \ tclArithSeries.o tclAssembly.o tclAsync.o tclBasic.o tclBinary.o \ tclCkalloc.o tclClock.o tclClockFmt.o tclCmdAH.o tclCmdIL.o tclCmdMZ.o \ tclCompCmds.o tclCompCmdsGR.o tclCompCmdsSZ.o tclCompExpr.o \ tclCompile.o tclConfig.o tclDate.o tclDictObj.o tclDisassemble.o \ tclEncoding.o tclEnsemble.o \ tclEnv.o tclEvent.o tclExecute.o tclFCmd.o tclFileName.o tclGet.o \ tclHash.o tclHistory.o \ tclIcu.o tclIndexObj.o tclInterp.o tclIO.o tclIOCmd.o \ tclIORChan.o tclIORTrans.o tclIOGT.o tclIOSock.o tclIOUtil.o \ tclLink.o tclListObj.o \ tclLiteral.o tclLoad.o tclMain.o tclNamesp.o tclNotify.o \ tclObj.o tclOptimize.o tclPanic.o tclParse.o tclPathObj.o tclPipe.o \ tclPkg.o tclPkgConfig.o tclPosixStr.o \ tclPreserve.o tclProc.o tclProcess.o tclRegexp.o \ tclResolve.o tclResult.o tclScan.o tclStringObj.o tclStrIdxTree.o \ tclStrToD.o tclThread.o \ tclThreadAlloc.o tclThreadJoin.o tclThreadStorage.o tclStubInit.o \ tclTimer.o tclTrace.o tclUtf.o tclUtil.o tclVar.o tclZlib.o \ tclTomMathInterface.o tclZipfs.o OO_OBJS = tclOO.o tclOOBasic.o tclOOCall.o tclOODefineCmds.o tclOOInfo.o \ tclOOMethod.o tclOOProp.o tclOOStubInit.o TOMMATH_OBJS = bn_s_mp_reverse.o bn_s_mp_mul_digs_fast.o \ |
| ︙ | ︙ | |||
346 347 348 349 350 351 352 | bn_mp_sqr.o bn_mp_sqrt.o bn_mp_sub.o bn_mp_sub_d.o \ bn_mp_signed_rsh.o \ bn_mp_to_ubin.o bn_mp_unpack.o \ bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o bn_mp_to_radix.o \ bn_mp_ubin_size.o bn_mp_xor.o bn_mp_zero.o bn_s_mp_add.o \ bn_s_mp_mul_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o | < < | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
bn_mp_sqr.o bn_mp_sqrt.o bn_mp_sub.o bn_mp_sub_d.o \
bn_mp_signed_rsh.o \
bn_mp_to_ubin.o bn_mp_unpack.o \
bn_s_mp_toom_mul.o bn_s_mp_toom_sqr.o bn_mp_to_radix.o \
bn_mp_ubin_size.o bn_mp_xor.o bn_mp_zero.o bn_s_mp_add.o \
bn_s_mp_mul_digs.o bn_s_mp_sqr.o bn_s_mp_sub.o
STUB_LIB_OBJS = tclStubLib.o \
tclStubCall.o \
tclStubLibTbl.o \
tclTomMathStubLib.o \
tclOOStubLib.o \
${COMPAT_OBJS}
UNIX_OBJS = tclUnixChan.o tclUnixEvent.o tclUnixFCmd.o \
tclUnixFile.o tclUnixPipe.o tclUnixSock.o \
tclUnixTime.o tclUnixInit.o tclUnixThrd.o \
tclUnixCompat.o
NOTIFY_OBJS = tclEpollNotfy.o tclKqueueNotfy.o tclSelectNotfy.o
MAC_OSX_OBJS = tclMacOSXBundle.o tclMacOSXFCmd.o tclMacOSXNotify.o
CYGWIN_OBJS = tclWinError.o
DTRACE_OBJ = tclDTrace.o
ZLIB_OBJS = Zadler32.o Zcompress.o Zcrc32.o Zdeflate.o Zinfback.o \
Zinffast.o Zinflate.o Zinftrees.o Ztrees.o Zuncompr.o Zzutil.o
TCL_OBJS = ${GENERIC_OBJS} ${UNIX_OBJS} ${NOTIFY_OBJS} ${COMPAT_OBJS} \
${OO_OBJS} @DL_OBJS@ @PLAT_OBJS@
OBJS = ${TCL_OBJS} @DTRACE_OBJ@ @ZLIB_OBJS@ @TOMMATH_OBJS@
TCL_DECLS = \
$(GENERIC_DIR)/tcl.decls \
$(GENERIC_DIR)/tclInt.decls \
$(GENERIC_DIR)/tclOO.decls \
$(GENERIC_DIR)/tclTomMath.decls
|
| ︙ | ︙ | |||
433 434 435 436 437 438 439 | $(GENERIC_DIR)/tclEnsemble.c \ $(GENERIC_DIR)/tclEnv.c \ $(GENERIC_DIR)/tclEvent.c \ $(GENERIC_DIR)/tclExecute.c \ $(GENERIC_DIR)/tclFCmd.c \ $(GENERIC_DIR)/tclFileName.c \ $(GENERIC_DIR)/tclGet.c \ | < < | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | $(GENERIC_DIR)/tclEnsemble.c \ $(GENERIC_DIR)/tclEnv.c \ $(GENERIC_DIR)/tclEvent.c \ $(GENERIC_DIR)/tclExecute.c \ $(GENERIC_DIR)/tclFCmd.c \ $(GENERIC_DIR)/tclFileName.c \ $(GENERIC_DIR)/tclGet.c \ $(GENERIC_DIR)/tclHash.c \ $(GENERIC_DIR)/tclHistory.c \ $(GENERIC_DIR)/tclIcu.c \ $(GENERIC_DIR)/tclIndexObj.c \ $(GENERIC_DIR)/tclInterp.c \ $(GENERIC_DIR)/tclIO.c \ $(GENERIC_DIR)/tclIOCmd.c \ $(GENERIC_DIR)/tclIOGT.c \ $(GENERIC_DIR)/tclIOSock.c \ $(GENERIC_DIR)/tclIOUtil.c \ $(GENERIC_DIR)/tclIORChan.c \ $(GENERIC_DIR)/tclIORTrans.c \ $(GENERIC_DIR)/tclLink.c \ $(GENERIC_DIR)/tclListObj.c \ $(GENERIC_DIR)/tclLiteral.c \ $(GENERIC_DIR)/tclLoad.c \ $(GENERIC_DIR)/tclMain.c \ $(GENERIC_DIR)/tclNamesp.c \ $(GENERIC_DIR)/tclNotify.c \ $(GENERIC_DIR)/tclObj.c \ $(GENERIC_DIR)/tclOptimize.c \ |
| ︙ | ︙ | |||
479 480 481 482 483 484 485 486 487 488 489 490 491 492 | $(GENERIC_DIR)/tclStrToD.c \ $(GENERIC_DIR)/tclTest.c \ $(GENERIC_DIR)/tclTestABSList.c \ $(GENERIC_DIR)/tclTestObj.c \ $(GENERIC_DIR)/tclTestProcBodyObj.c \ $(GENERIC_DIR)/tclThread.c \ $(GENERIC_DIR)/tclThreadAlloc.c \ $(GENERIC_DIR)/tclThreadStorage.c \ $(GENERIC_DIR)/tclTimer.c \ $(GENERIC_DIR)/tclTrace.c \ $(GENERIC_DIR)/tclUtil.c \ $(GENERIC_DIR)/tclVar.c \ $(GENERIC_DIR)/tclAssembly.c \ $(GENERIC_DIR)/tclZlib.c \ | > | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | $(GENERIC_DIR)/tclStrToD.c \ $(GENERIC_DIR)/tclTest.c \ $(GENERIC_DIR)/tclTestABSList.c \ $(GENERIC_DIR)/tclTestObj.c \ $(GENERIC_DIR)/tclTestProcBodyObj.c \ $(GENERIC_DIR)/tclThread.c \ $(GENERIC_DIR)/tclThreadAlloc.c \ $(GENERIC_DIR)/tclThreadJoin.c \ $(GENERIC_DIR)/tclThreadStorage.c \ $(GENERIC_DIR)/tclTimer.c \ $(GENERIC_DIR)/tclTrace.c \ $(GENERIC_DIR)/tclUtil.c \ $(GENERIC_DIR)/tclVar.c \ $(GENERIC_DIR)/tclAssembly.c \ $(GENERIC_DIR)/tclZlib.c \ |
| ︙ | ︙ | |||
701 702 703 704 705 706 707 | MAC_OSX_SRCS = \ $(MAC_OSX_DIR)/tclMacOSXBundle.c \ $(MAC_OSX_DIR)/tclMacOSXFCmd.c \ $(MAC_OSX_DIR)/tclMacOSXNotify.c CYGWIN_SRCS = \ | | < < < < < | | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 | MAC_OSX_SRCS = \ $(MAC_OSX_DIR)/tclMacOSXBundle.c \ $(MAC_OSX_DIR)/tclMacOSXFCmd.c \ $(MAC_OSX_DIR)/tclMacOSXNotify.c CYGWIN_SRCS = \ $(TOP_DIR)/win/tclWinError.c DTRACE_HDR = tclDTrace.h DTRACE_SRC = $(GENERIC_DIR)/tclDTrace.d ZLIB_SRCS = \ $(ZLIB_DIR)/adler32.c \ $(ZLIB_DIR)/compress.c \ $(ZLIB_DIR)/crc32.c \ $(ZLIB_DIR)/deflate.c \ $(ZLIB_DIR)/infback.c \ $(ZLIB_DIR)/inffast.c \ $(ZLIB_DIR)/inflate.c \ $(ZLIB_DIR)/inftrees.c \ $(ZLIB_DIR)/trees.c \ $(ZLIB_DIR)/uncompr.c \ $(ZLIB_DIR)/zutil.c # Note: don't include DL_SRCS or MAC_OSX_SRCS in SRCS: most of those files # won't compile on the current machine, and they will cause problems for # things like "make depend". SRCS = $(GENERIC_SRCS) $(UNIX_SRCS) $(NOTIFY_SRCS) \ $(OO_SRCS) $(STUB_SRCS) @PLAT_SRCS@ @ZLIB_SRCS@ @TOMMATH_SRCS@ ### # Tip 430 - ZipFS Modifications ### TCL_ZIP_FILE = @TCL_ZIP_FILE@ TCL_VFS_ROOT = libtcl.vfs |
| ︙ | ︙ | |||
795 796 797 798 799 800 801 |
@echo "creating ${TCL_VFS_PATH} (prepare compression)"
@if \
ln -s $(TOP_DIR)/library/* ${TCL_VFS_PATH}/; \
then : ; else \
cp -a $(TOP_DIR)/library/* ${TCL_VFS_PATH}; \
fi
mv ${TCL_VFS_PATH}/manifest.txt ${TCL_VFS_PATH}/pkgIndex.tcl
| | | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
@echo "creating ${TCL_VFS_PATH} (prepare compression)"
@if \
ln -s $(TOP_DIR)/library/* ${TCL_VFS_PATH}/; \
then : ; else \
cp -a $(TOP_DIR)/library/* ${TCL_VFS_PATH}; \
fi
mv ${TCL_VFS_PATH}/manifest.txt ${TCL_VFS_PATH}/pkgIndex.tcl
rm -rf ${TCL_VFS_PATH}/dde ${TCL_VFS_PATH}/registry
@find ${TCL_VFS_ROOT} -type d -empty -delete
@echo "creating ${TCL_ZIP_FILE} from ${TCL_VFS_PATH}"
@(zip=`(realpath '${NATIVE_ZIP}' || readlink -m '${NATIVE_ZIP}' || \
echo '${NATIVE_ZIP}' | sed "s?^\./?$$(pwd)/?") 2>/dev/null`; \
echo 'cd ${TCL_VFS_ROOT} &&' $$zip '${ZIP_PROG_OPTIONS} ../${TCL_ZIP_FILE} ${ZIP_PROG_VFSSEARCH}'; \
cd ${TCL_VFS_ROOT} && \
$$zip ${ZIP_PROG_OPTIONS} ../${TCL_ZIP_FILE} ${ZIP_PROG_VFSSEARCH} >/dev/null)
|
| ︙ | ︙ | |||
1087 1088 1089 1090 1091 1092 1093 | @echo "Installing package opt0.4 files to $(SCRIPT_INSTALL_DIR)/opt0.4/" @for i in $(TOP_DIR)/library/opt/*.tcl; do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)/opt0.4"; \ done @echo "Installing package msgcat 1.7.1 as a Tcl Module" @$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl \ "$(MODULE_INSTALL_DIR)/9.0/msgcat-1.7.1.tm" | | | | | | 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 | @echo "Installing package opt0.4 files to $(SCRIPT_INSTALL_DIR)/opt0.4/" @for i in $(TOP_DIR)/library/opt/*.tcl; do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)/opt0.4"; \ done @echo "Installing package msgcat 1.7.1 as a Tcl Module" @$(INSTALL_DATA) $(TOP_DIR)/library/msgcat/msgcat.tcl \ "$(MODULE_INSTALL_DIR)/9.0/msgcat-1.7.1.tm" @echo "Installing package tcltest 2.5.11 as a Tcl Module" @$(INSTALL_DATA) $(TOP_DIR)/library/tcltest/tcltest.tcl \ "$(MODULE_INSTALL_DIR)/9.0/tcltest-2.5.11.tm" @echo "Installing package platform 1.1.1 as a Tcl Module" @$(INSTALL_DATA) $(TOP_DIR)/library/platform/platform.tcl \ "$(MODULE_INSTALL_DIR)/9.0/platform-1.1.1.tm" @echo "Installing package platform::shell 1.1.4 as a Tcl Module" @$(INSTALL_DATA) $(TOP_DIR)/library/platform/shell.tcl \ "$(MODULE_INSTALL_DIR)/9.0/platform/shell-1.1.4.tm" @echo "Installing encoding files to $(SCRIPT_INSTALL_DIR)/encoding/" @for i in $(TOP_DIR)/library/encoding/*.enc; do \ $(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)/encoding"; \ done |
| ︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 | tclFileName.o: $(GENERIC_DIR)/tclFileName.c $(FSHDR) $(TCLREHDRS) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclFileName.c tclGet.o: $(GENERIC_DIR)/tclGet.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclGet.c | < < < | < < < < < < < < < | 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 | tclFileName.o: $(GENERIC_DIR)/tclFileName.c $(FSHDR) $(TCLREHDRS) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclFileName.c tclGet.o: $(GENERIC_DIR)/tclGet.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclGet.c tclHash.o: $(GENERIC_DIR)/tclHash.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclHash.c tclHistory.o: $(GENERIC_DIR)/tclHistory.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclHistory.c tclIcu.o: $(GENERIC_DIR)/tclIcu.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIcu.c tclIndexObj.o: $(GENERIC_DIR)/tclIndexObj.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIndexObj.c tclInterp.o: $(GENERIC_DIR)/tclInterp.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclInterp.c tclIO.o: $(GENERIC_DIR)/tclIO.c $(IOHDR) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIO.c tclIOCmd.o: $(GENERIC_DIR)/tclIOCmd.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclIOCmd.c |
| ︙ | ︙ | |||
1437 1438 1439 1440 1441 1442 1443 | tclLink.o: $(GENERIC_DIR)/tclLink.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLink.c tclListObj.o: $(GENERIC_DIR)/tclListObj.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclListObj.c | < < < | 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 | tclLink.o: $(GENERIC_DIR)/tclLink.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLink.c tclListObj.o: $(GENERIC_DIR)/tclListObj.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclListObj.c tclLiteral.o: $(GENERIC_DIR)/tclLiteral.c $(COMPILEHDR) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclLiteral.c tclObj.o: $(GENERIC_DIR)/tclObj.c $(COMPILEHDR) $(MATHHDRS) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclObj.c tclOptimize.o: $(GENERIC_DIR)/tclOptimize.c $(COMPILEHDR) |
| ︙ | ︙ | |||
1589 1590 1591 1592 1593 1594 1595 | tclTrace.o: $(GENERIC_DIR)/tclTrace.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclTrace.c tclUtil.o: $(GENERIC_DIR)/tclUtil.c $(PARSEHDR) $(TRIMHDR) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclUtil.c | | | 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 | tclTrace.o: $(GENERIC_DIR)/tclTrace.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclTrace.c tclUtil.o: $(GENERIC_DIR)/tclUtil.c $(PARSEHDR) $(TRIMHDR) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclUtil.c tclUtf.o: $(GENERIC_DIR)/tclUtf.c $(GENERIC_DIR)/tclUniData.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclUtf.c tclVar.o: $(GENERIC_DIR)/tclVar.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclVar.c tclZlib.o: $(GENERIC_DIR)/tclZlib.c $(CC) -c $(CC_SWITCHES) $(ZLIB_INCLUDE) $(GENERIC_DIR)/tclZlib.c |
| ︙ | ︙ | |||
1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 | tclThread.o: $(GENERIC_DIR)/tclThread.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThread.c tclThreadAlloc.o: $(GENERIC_DIR)/tclThreadAlloc.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThreadAlloc.c tclThreadStorage.o: $(GENERIC_DIR)/tclThreadStorage.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThreadStorage.c tclMutexTest.o: $(GENERIC_DIR)/tclMutexTest.c $(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tclMutexTest.c tclThreadTest.o: $(GENERIC_DIR)/tclThreadTest.c | > > > | 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 | tclThread.o: $(GENERIC_DIR)/tclThread.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThread.c tclThreadAlloc.o: $(GENERIC_DIR)/tclThreadAlloc.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThreadAlloc.c tclThreadJoin.o: $(GENERIC_DIR)/tclThreadJoin.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThreadJoin.c tclThreadStorage.o: $(GENERIC_DIR)/tclThreadStorage.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclThreadStorage.c tclMutexTest.o: $(GENERIC_DIR)/tclMutexTest.c $(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tclMutexTest.c tclThreadTest.o: $(GENERIC_DIR)/tclThreadTest.c |
| ︙ | ︙ | |||
1891 1892 1893 1894 1895 1896 1897 | tclUnixInit.o: $(UNIX_DIR)/tclUnixInit.c tclConfig.sh $(CC) -c $(CC_SWITCHES) $(TCL_LOCATIONS) $(UNIX_DIR)/tclUnixInit.c tclUnixCompat.o: $(UNIX_DIR)/tclUnixCompat.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixCompat.c | < < < | | 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 | tclUnixInit.o: $(UNIX_DIR)/tclUnixInit.c tclConfig.sh $(CC) -c $(CC_SWITCHES) $(TCL_LOCATIONS) $(UNIX_DIR)/tclUnixInit.c tclUnixCompat.o: $(UNIX_DIR)/tclUnixCompat.c $(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixCompat.c # The following are Mac OS X only sources: tclMacOSXBundle.o: $(MAC_OSX_DIR)/tclMacOSXBundle.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXBundle.c tclMacOSXFCmd.o: $(MAC_OSX_DIR)/tclMacOSXFCmd.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXFCmd.c tclMacOSXNotify.o: $(MAC_OSX_DIR)/tclMacOSXNotify.c $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXNotify.c # The following is a CYGWIN only source: tclWinError.o: $(TOP_DIR)/win/tclWinError.c $(CC) -c $(CC_SWITCHES) $(TOP_DIR)/win/tclWinError.c # DTrace support $(TCL_OBJS) $(STUB_LIB_OBJS) $(TCLSH_OBJS) $(TCLTEST_OBJS) $(XTTEST_OBJS) $(TOMMATH_OBJS): @DTRACE_HDR@ $(DTRACE_HDR): $(DTRACE_SRC) $(DTRACE) -h $(DTRACE_SWITCHES) -o $@ -s $(DTRACE_SRC) $(DTRACE_OBJ): $(DTRACE_SRC) $(TCL_OBJS) $(DTRACE) -G $(DTRACE_SWITCHES) -o $@ -s $(DTRACE_SRC) $(TCL_OBJS) |
| ︙ | ︙ | |||
2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 |
# Propagate configure args like --enable-64bit to package configure
PKG_CFG_ARGS = @PKG_CFG_ARGS@
# If PKG_DIR is changed to a different relative depth to the build dir, need
# to adapt the ../.. relative paths below and at the top of configure.ac (we
# cannot use absolute paths due to issues in nested configure when path to
# build dir contains spaces).
PKG_DIR = ./pkgs
configure-packages:
@for i in $(PKGS_DIR)/*; do \
if [ -d $$i ] ; then \
if [ -x $$i/configure ] ; then \
pkg=`basename $$i`; \
echo "Configuring package '$$pkg'"; \
mkdir -p $(PKG_DIR)/$$pkg; \
if [ ! -f $(PKG_DIR)/$$pkg/Makefile ] ; then \
( cd $(PKG_DIR)/$$pkg; \
$$i/configure --with-tcl=../.. \
--with-tclinclude=$(GENERIC_DIR) \
$(PKG_CFG_ARGS) --libdir=$(PACKAGE_DIR) \
--enable-shared; ) || exit $$?; \
fi; \
fi; \
fi; \
done
packages: configure-packages ${STUB_LIB_FILE}
@for i in $(PKGS_DIR)/*; do \
if [ -d $$i ] ; then \
pkg=`basename $$i`; \
if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \
echo "Building package '$$pkg'"; \
( cd $(PKG_DIR)/$$pkg; $(MAKE); ) || exit $$?; \
fi; \
fi; \
done
install-packages: packages
@for i in $(PKGS_DIR)/*; do \
if [ -d $$i ] ; then \
pkg=`basename $$i`; \
if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \
echo "Installing package '$$pkg'"; \
( cd $(PKG_DIR)/$$pkg; $(MAKE) install \
"DESTDIR=$(INSTALL_ROOT)"; ) || exit $$?; \
fi; \
fi; \
done
| > > > > > > > > > > > > > > > > > > | 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 |
# Propagate configure args like --enable-64bit to package configure
PKG_CFG_ARGS = @PKG_CFG_ARGS@
# If PKG_DIR is changed to a different relative depth to the build dir, need
# to adapt the ../.. relative paths below and at the top of configure.ac (we
# cannot use absolute paths due to issues in nested configure when path to
# build dir contains spaces).
PKG_DIR = ./pkgs
PKG8_DIR = ./pkgs8
configure-packages:
@for i in $(PKGS_DIR)/*; do \
if [ -d $$i ] ; then \
if [ -x $$i/configure ] ; then \
pkg=`basename $$i`; \
echo "Configuring package '$$pkg'"; \
mkdir -p $(PKG8_DIR)/$$pkg; \
if [ ! -f $(PKG8_DIR)/$$pkg/Makefile ] ; then \
( cd $(PKG8_DIR)/$$pkg; \
$$i/configure --with-tcl8 --with-tcl=../.. \
--with-tclinclude=$(GENERIC_DIR) \
$(PKG_CFG_ARGS) --libdir=$(PACKAGE_DIR) \
--enable-shared; ) || exit $$?; \
fi; \
mkdir -p $(PKG_DIR)/$$pkg; \
if [ ! -f $(PKG_DIR)/$$pkg/Makefile ] ; then \
( cd $(PKG_DIR)/$$pkg; \
$$i/configure --with-tcl=../.. \
--with-tclinclude=$(GENERIC_DIR) \
$(PKG_CFG_ARGS) --libdir=$(PACKAGE_DIR) \
--enable-shared; ) || exit $$?; \
fi; \
fi; \
fi; \
done
packages: configure-packages ${STUB_LIB_FILE}
@for i in $(PKGS_DIR)/*; do \
if [ -d $$i ] ; then \
pkg=`basename $$i`; \
if [ -f $(PKG8_DIR)/$$pkg/Makefile ] ; then \
echo "Building package '$$pkg' for Tcl 8"; \
( cd $(PKG8_DIR)/$$pkg; $(MAKE); ) || exit $$?; \
fi; \
if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \
echo "Building package '$$pkg'"; \
( cd $(PKG_DIR)/$$pkg; $(MAKE); ) || exit $$?; \
fi; \
fi; \
done
install-packages: packages
@for i in $(PKGS_DIR)/*; do \
if [ -d $$i ] ; then \
pkg=`basename $$i`; \
if [ -f $(PKG8_DIR)/$$pkg/Makefile ] ; then \
echo "Installing package '$$pkg' for Tcl 8"; \
( cd $(PKG8_DIR)/$$pkg; $(MAKE) install \
"DESTDIR=$(INSTALL_ROOT)"; ) || exit $$?; \
fi; \
if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \
echo "Installing package '$$pkg'"; \
( cd $(PKG_DIR)/$$pkg; $(MAKE) install \
"DESTDIR=$(INSTALL_ROOT)"; ) || exit $$?; \
fi; \
fi; \
done
|
| ︙ | ︙ | |||
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 | fi; \ done clean-packages: @for i in $(PKGS_DIR)/*; do \ if [ -d $$i ] ; then \ pkg=`basename $$i`; \ if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \ ( cd $(PKG_DIR)/$$pkg; $(MAKE) clean; ) \ fi; \ fi; \ done distclean-packages: @for i in $(PKGS_DIR)/*; do \ if [ -d $$i ] ; then \ pkg=`basename $$i`; \ if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \ ( cd $(PKG_DIR)/$$pkg; $(MAKE) distclean; ) \ fi; \ rm -rf $(PKG_DIR)/$$pkg; \ fi; \ done; \ rm -rf $(PKG_DIR) dist-packages: configure-packages @rm -rf $(DISTROOT)/pkgs; \ mkdir -p $(DISTROOT)/pkgs; \ for i in $(PKGS_DIR)/*; do \ if [ -d $$i ] ; then \ | > > > > > > > > | 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 | fi; \ done clean-packages: @for i in $(PKGS_DIR)/*; do \ if [ -d $$i ] ; then \ pkg=`basename $$i`; \ if [ -f $(PKG8_DIR)/$$pkg/Makefile ] ; then \ ( cd $(PKG8_DIR)/$$pkg; $(MAKE) clean; ) \ fi; \ if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \ ( cd $(PKG_DIR)/$$pkg; $(MAKE) clean; ) \ fi; \ fi; \ done distclean-packages: @for i in $(PKGS_DIR)/*; do \ if [ -d $$i ] ; then \ pkg=`basename $$i`; \ if [ -f $(PKG8_DIR)/$$pkg/Makefile ] ; then \ ( cd $(PKG8_DIR)/$$pkg; $(MAKE) distclean; ) \ fi; \ rm -rf $(PKG8_DIR)/$$pkg; \ if [ -f $(PKG_DIR)/$$pkg/Makefile ] ; then \ ( cd $(PKG_DIR)/$$pkg; $(MAKE) distclean; ) \ fi; \ rm -rf $(PKG_DIR)/$$pkg; \ fi; \ done; \ rm -rf $(PKG8_DIR) rm -rf $(PKG_DIR) dist-packages: configure-packages @rm -rf $(DISTROOT)/pkgs; \ mkdir -p $(DISTROOT)/pkgs; \ for i in $(PKGS_DIR)/*; do \ if [ -d $$i ] ; then \ |
| ︙ | ︙ | |||
2305 2306 2307 2308 2309 2310 2311 | DISTDIR = $(DISTROOT)/$(DISTNAME) DIST_INSTALL_DATA = $(INSTALL) -p -m 644 DIST_INSTALL_SCRIPT = $(INSTALL) -p -m 755 BUILTIN_PACKAGE_LIST = cookiejar http opt msgcat registry dde tcltest platform $(UNIX_DIR)/configure: $(UNIX_DIR)/configure.ac $(UNIX_DIR)/tcl.m4 \ $(UNIX_DIR)/aclocal.m4 | | | > | | | | 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 |
DISTDIR = $(DISTROOT)/$(DISTNAME)
DIST_INSTALL_DATA = $(INSTALL) -p -m 644
DIST_INSTALL_SCRIPT = $(INSTALL) -p -m 755
BUILTIN_PACKAGE_LIST = cookiejar http opt msgcat registry dde tcltest platform
$(UNIX_DIR)/configure: $(UNIX_DIR)/configure.ac $(UNIX_DIR)/tcl.m4 \
$(UNIX_DIR)/aclocal.m4
cd $(UNIX_DIR); autoconf
$(MAC_OSX_DIR)/configure: $(MAC_OSX_DIR)/configure.ac $(UNIX_DIR)/configure
cd $(MAC_OSX_DIR); autoconf
$(UNIX_DIR)/tclConfig.h.in: $(MAC_OSX_DIR)/configure
cd $(MAC_OSX_DIR); autoheader; touch $@
tclUuid.h: $(TOP_DIR)/manifest.uuid
echo "#define TCL_VERSION_UUID \\" >$@
cat $(TOP_DIR)/manifest.uuid >>$@
echo "" >>$@
$(TOP_DIR)/manifest.uuid:
printf "git-" >$(TOP_DIR)/manifest.uuid
(cd $(TOP_DIR); git rev-parse HEAD >>$(TOP_DIR)/manifest.uuid || \
(printf "svn-r" >$(TOP_DIR)/manifest.uuid ; \
svn info --show-item last-changed-revision >>$(TOP_DIR)/manifest.uuid) || \
printf "unknown" >$(TOP_DIR)/manifest.uuid)
dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in genstubs \
$(MAC_OSX_DIR)/configure $(TOP_DIR)/manifest.uuid dist-packages ${NATIVE_TCLSH}
rm -rf $(DISTDIR)
$(INSTALL_DATA_DIR) $(DISTDIR)/unix
$(DIST_INSTALL_DATA) $(TOP_DIR)/manifest.uuid $(DISTDIR)
$(DIST_INSTALL_DATA) $(UNIX_DIR)/*.c $(UNIX_DIR)/tclUnixPort.h $(DISTDIR)/unix
$(DIST_INSTALL_DATA) $(UNIX_DIR)/Makefile.in $(DISTDIR)/unix
$(DIST_INSTALL_DATA) $(UNIX_DIR)/configure.ac \
$(UNIX_DIR)/tcl.m4 $(UNIX_DIR)/aclocal.m4 \
|
| ︙ | ︙ | |||
2377 2378 2379 2380 2381 2382 2383 | | ( cd $(COMPAT_DIR)/zlib ; xargs tar cf - ) \ | ( cd $(DISTDIR)/compat/zlib ; tar xfp - ) $(INSTALL_DATA_DIR) $(DISTDIR)/libtommath @echo cp -r $(TOP_DIR)/libtommath $(DISTDIR)/libtommath @( cd $(TOP_DIR)/libtommath; find . -type f -print ) \ | ( cd $(TOP_DIR)/libtommath ; xargs tar cf - ) \ | ( cd $(DISTDIR)/libtommath ; tar xfp - ) | < < < < < < < < | 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 | | ( cd $(COMPAT_DIR)/zlib ; xargs tar cf - ) \ | ( cd $(DISTDIR)/compat/zlib ; tar xfp - ) $(INSTALL_DATA_DIR) $(DISTDIR)/libtommath @echo cp -r $(TOP_DIR)/libtommath $(DISTDIR)/libtommath @( cd $(TOP_DIR)/libtommath; find . -type f -print ) \ | ( cd $(TOP_DIR)/libtommath ; xargs tar cf - ) \ | ( cd $(DISTDIR)/libtommath ; tar xfp - ) $(INSTALL_DATA_DIR) $(DISTDIR)/tests $(DIST_INSTALL_DATA) $(TOP_DIR)/license.terms $(DISTDIR)/tests $(DIST_INSTALL_DATA) $(TOP_DIR)/tests/*.test $(TOP_DIR)/tests/README \ $(TOP_DIR)/tests/*.bench $(TOP_DIR)/tests/*.tar.gz \ $(TOP_DIR)/tests/httpd $(TOP_DIR)/tests/*.tcl \ $(TOP_DIR)/tests/*.zip $(DISTDIR)/tests @mkdir $(DISTDIR)/tests/auto0 |
| ︙ | ︙ | |||
2414 2415 2416 2417 2418 2419 2420 | $(DISTDIR)/tests/zipfiles $(DIST_INSTALL_DATA) $(TOP_DIR)/tests/zipfiles/README \ $(DISTDIR)/tests/zipfiles $(DIST_INSTALL_DATA) $(TOP_DIR)/tests/zipfiles/LICENSE-libzip \ $(DISTDIR)/tests/zipfiles $(INSTALL_DATA_DIR) $(DISTDIR)/tests-perf $(DIST_INSTALL_DATA) $(TOP_DIR)/tests-perf/*.tcl $(DISTDIR)/tests-perf | < < < < < < < < > | > | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 | $(DISTDIR)/tests/zipfiles $(DIST_INSTALL_DATA) $(TOP_DIR)/tests/zipfiles/README \ $(DISTDIR)/tests/zipfiles $(DIST_INSTALL_DATA) $(TOP_DIR)/tests/zipfiles/LICENSE-libzip \ $(DISTDIR)/tests/zipfiles $(INSTALL_DATA_DIR) $(DISTDIR)/tests-perf $(DIST_INSTALL_DATA) $(TOP_DIR)/tests-perf/*.tcl $(DISTDIR)/tests-perf $(INSTALL_DATA_DIR) $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/win/Makefile.in $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/win/configure.ac \ $(TOP_DIR)/win/tclConfig.sh.in $(TOP_DIR)/win/tclooConfig.sh \ $(TOP_DIR)/win/tcl.m4 $(TOP_DIR)/win/aclocal.m4 \ $(TOP_DIR)/win/tclsh.exe.manifest.in $(TOP_DIR)/win/tclUuid.h.in \ $(TOP_DIR)/win/gitmanifest.in $(TOP_DIR)/win/svnmanifest.in \ $(TOP_DIR)/win/x86_64-w64-mingw32-nmakehlp.exe $(DISTDIR)/win chmod 775 $(DISTDIR)/win/x86_64-w64-mingw32-nmakehlp.exe $(DIST_INSTALL_SCRIPT) $(TOP_DIR)/win/configure $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/win/*.c $(TOP_DIR)/win/*.ico $(TOP_DIR)/win/*.rc \ $(TOP_DIR)/win/tclWinInt.h $(TOP_DIR)/win/tclWinPort.h \ $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/win/*.bat $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/win/*.vc $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/win/tcl.ds* $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/win/README $(DISTDIR)/win $(DIST_INSTALL_DATA) $(TOP_DIR)/license.terms $(DISTDIR)/win $(INSTALL_DATA_DIR) $(DISTDIR)/macosx $(DIST_INSTALL_DATA) $(MAC_OSX_DIR)/GNUmakefile $(MAC_OSX_DIR)/README \ $(MAC_OSX_DIR)/*.c $(MAC_OSX_DIR)/*.in \ $(MAC_OSX_DIR)/*.ac \ $(DISTDIR)/macosx $(DIST_INSTALL_SCRIPT) $(MAC_OSX_DIR)/configure $(DISTDIR)/macosx $(DIST_INSTALL_DATA) $(TOP_DIR)/license.terms $(DISTDIR)/macosx $(INSTALL_DATA_DIR) $(DISTDIR)/unix/dltest $(DIST_INSTALL_DATA) $(UNIX_DIR)/dltest/*.c $(UNIX_DIR)/dltest/Makefile.in \ $(UNIX_DIR)/dltest/README $(DISTDIR)/unix/dltest $(INSTALL_DATA_DIR) $(DISTDIR)/tools $(DIST_INSTALL_DATA) $(TOOL_DIR)/README $(TOOL_DIR)/*.c $(TOOL_DIR)/*.svg \ $(TOOL_DIR)/*.tcl $(TOOL_DIR)/*.bmp $(TOOL_DIR)/*.png $(TOOL_DIR)/valgrind_suppress \ |
| ︙ | ︙ |
Changes to unix/configure.
1 2 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | | 1 2 3 4 5 6 7 8 9 10 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.73 for tcl 9.0. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation |
| ︙ | ︙ | |||
581 582 583 584 585 586 587 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tcl' PACKAGE_TARNAME='tcl' | | | | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tcl' PACKAGE_TARNAME='tcl' PACKAGE_VERSION='9.0' PACKAGE_STRING='tcl 9.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stddef.h> #ifdef HAVE_STDIO_H |
| ︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF | | | 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF 'configure' configures tcl 9.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. |
| ︙ | ︙ | |||
1408 1409 1410 1411 1412 1413 1414 | cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in | | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 |
cat <<\_ACEOF
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of tcl 9.0:";;
esac
cat <<\_ACEOF
Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
|
| ︙ | ︙ | |||
1525 1526 1527 1528 1529 1530 1531 |
cd "$ac_pwd" || { ac_status=$?; break; }
done
fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
| | | 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 |
cd "$ac_pwd" || { ac_status=$?; break; }
done
fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
tcl configure 9.0
generated by GNU Autoconf 2.73
Copyright (C) 2026 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
exit
|
| ︙ | ︙ | |||
2008 2009 2010 2011 2012 2013 2014 |
ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
esac
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
| | | 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 |
ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
esac
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by tcl $as_me 9.0, which was
generated by GNU Autoconf 2.73. Invocation command line was
$ $0$ac_configure_args_raw
_ACEOF
exec 5>>config.log
{
|
| ︙ | ︙ | |||
2822 2823 2824 2825 2826 2827 2828 | ac_compiler_gnu=$ac_cv_c_compiler_gnu | | | | | 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 |
ac_compiler_gnu=$ac_cv_c_compiler_gnu
TCL_VERSION=9.0
TCL_MAJOR_VERSION=9
TCL_MINOR_VERSION=0
TCL_PATCH_LEVEL=".5"
VERSION=${TCL_VERSION}
EXTRA_INSTALL_BINARIES=${EXTRA_INSTALL_BINARIES:-"@:"}
EXTRA_BUILD_HTML=${EXTRA_BUILD_HTML:-"@:"}
#------------------------------------------------------------------------
# Setup configure arguments for bundled packages
|
| ︙ | ︙ | |||
4595 4596 4597 4598 4599 4600 4601 |
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5
printf '%s\n' "$ac_cv_lib_inet_main" >&6; }
if test "x$ac_cv_lib_inet_main" = xyes
then :
LIBS="$LIBS -linet"
fi
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 |
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_main" >&5
printf '%s\n' "$ac_cv_lib_inet_main" >&6; }
if test "x$ac_cv_lib_inet_main" = xyes
then :
LIBS="$LIBS -linet"
fi
ac_fn_c_check_header_compile "$LINENO" "net/errno.h" "ac_cv_header_net_errno_h" "$ac_includes_default"
if test "x$ac_cv_header_net_errno_h" = xyes
then :
printf '%s\n' "#define HAVE_NET_ERRNO_H 1" >>confdefs.h
|
| ︙ | ︙ | |||
5117 5118 5119 5120 5121 5122 5123 | fi ac_fn_c_check_func "$LINENO" "pthread_atfork" "ac_cv_func_pthread_atfork" if test "x$ac_cv_func_pthread_atfork" = xyes then : printf '%s\n' "#define HAVE_PTHREAD_ATFORK 1" >>confdefs.h | < < < < < < | 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 |
fi
ac_fn_c_check_func "$LINENO" "pthread_atfork" "ac_cv_func_pthread_atfork"
if test "x$ac_cv_func_pthread_atfork" = xyes
then :
printf '%s\n' "#define HAVE_PTHREAD_ATFORK 1" >>confdefs.h
fi
LIBS=$ac_saved_libs
# Add the threads support libraries
LIBS="$LIBS$THREADS_LIBS"
|
| ︙ | ︙ | |||
5178 5179 5180 5181 5182 5183 5184 |
e)
search_path=`echo ${PATH} | sed -e 's/:/ /g'`
for dir in $search_path ; do
for j in `ls -r $dir/tclsh[8-9]* 2> /dev/null` \
`ls -r $dir/tclsh* 2> /dev/null` ; do
if test x"$ac_cv_path_tclsh" = x ; then
if test -f "$j" ; then
| < < < < | | < | 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 |
e)
search_path=`echo ${PATH} | sed -e 's/:/ /g'`
for dir in $search_path ; do
for j in `ls -r $dir/tclsh[8-9]* 2> /dev/null` \
`ls -r $dir/tclsh* 2> /dev/null` ; do
if test x"$ac_cv_path_tclsh" = x ; then
if test -f "$j" ; then
ac_cv_path_tclsh=$j
break
fi
fi
done
done
;;
esac
fi
|
| ︙ | ︙ | |||
10690 10691 10692 10693 10694 10695 10696 | fi ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags" if test "x$ac_cv_func_chflags" = xyes then : printf '%s\n' "#define HAVE_CHFLAGS 1" >>confdefs.h | < < < < < < > > > > > > > | 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 |
fi
ac_fn_c_check_func "$LINENO" "chflags" "ac_cv_func_chflags"
if test "x$ac_cv_func_chflags" = xyes
then :
printf '%s\n' "#define HAVE_CHFLAGS 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "mkstemps" "ac_cv_func_mkstemps"
if test "x$ac_cv_func_mkstemps" = xyes
then :
printf '%s\n' "#define HAVE_MKSTEMPS 1" >>confdefs.h
fi
#--------------------------------------------------------------------
# Darwin specific API checks and defines
#--------------------------------------------------------------------
if test "`uname -s`" = "Darwin" ; then
ac_fn_c_check_func "$LINENO" "getattrlist" "ac_cv_func_getattrlist"
if test "x$ac_cv_func_getattrlist" = xyes
then :
printf '%s\n' "#define HAVE_GETATTRLIST 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "copyfile.h" "ac_cv_header_copyfile_h" "$ac_includes_default"
if test "x$ac_cv_header_copyfile_h" = xyes
then :
printf '%s\n' "#define HAVE_COPYFILE_H 1" >>confdefs.h
fi
|
| ︙ | ︙ | |||
12112 12113 12114 12115 12116 12117 12118 | test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" | | | 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 | test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by tcl $as_me 9.0, which was generated by GNU Autoconf 2.73. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ |
| ︙ | ︙ | |||
12171 12172 12173 12174 12175 12176 12177 | _ACEOF ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ | | | 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 | _ACEOF ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ tcl config.status 9.0 configured by $0, generated by GNU Autoconf 2.73, with options \\"\$ac_cs_config\\" Copyright (C) 2026 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." |
| ︙ | ︙ |
Changes to unix/configure.ac.
1 2 3 4 5 | #! /bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#! /bin/bash -norc
dnl This file is an input file used by the GNU "autoconf" program to
dnl generate the file "configure", which is run during Tcl installation
dnl to configure the system for the local environment.
AC_INIT([tcl],[9.0])
AC_PREREQ([2.69])
dnl This is only used when included from macosx/configure.ac
m4_ifdef([SC_USE_CONFIG_HEADERS], [
AC_CONFIG_HEADERS([tclConfig.h:../unix/tclConfig.h.in])
AC_CONFIG_COMMANDS_PRE([DEFS="-DHAVE_TCL_CONFIG_H -imacros tclConfig.h"])
AH_TOP([
#ifndef _TCLCONFIG
#define _TCLCONFIG])
AH_BOTTOM([
/* Undef unused package specific autoheader defines so that we can
* include both tclConfig.h and tkConfig.h at the same time: */
/* override */ #undef PACKAGE_NAME
/* override */ #undef PACKAGE_TARNAME
/* override */ #undef PACKAGE_VERSION
/* override */ #undef PACKAGE_STRING
#endif /* _TCLCONFIG */])
])
TCL_VERSION=9.0
TCL_MAJOR_VERSION=9
TCL_MINOR_VERSION=0
TCL_PATCH_LEVEL=".5"
VERSION=${TCL_VERSION}
EXTRA_INSTALL_BINARIES=${EXTRA_INSTALL_BINARIES:-"@:"}
EXTRA_BUILD_HTML=${EXTRA_BUILD_HTML:-"@:"}
#------------------------------------------------------------------------
# Setup configure arguments for bundled packages
|
| ︙ | ︙ | |||
514 515 516 517 518 519 520 | SC_ENABLE_LANGINFO #-------------------------------------------------------------------- # Check for support of cfmakeraw, chflags and mkstemps functions #-------------------------------------------------------------------- | | > | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
SC_ENABLE_LANGINFO
#--------------------------------------------------------------------
# Check for support of cfmakeraw, chflags and mkstemps functions
#--------------------------------------------------------------------
AC_CHECK_FUNCS(cfmakeraw chflags mkstemps)
#--------------------------------------------------------------------
# Darwin specific API checks and defines
#--------------------------------------------------------------------
if test "`uname -s`" = "Darwin" ; then
AC_CHECK_FUNCS(getattrlist)
AC_CHECK_HEADERS(copyfile.h)
AC_CHECK_FUNCS(copyfile)
if test $tcl_corefoundation = yes; then
AC_CHECK_HEADERS(libkern/OSAtomic.h)
AC_CHECK_FUNCS(OSSpinLockLock)
fi
AC_DEFINE(TCL_LOAD_FROM_MEMORY, 1,
|
| ︙ | ︙ |
Changes to unix/dltest/Makefile.in.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 |
LDFLAGS = @LDFLAGS_DEFAULT@ @LDFLAGS@
CC_SWITCHES = $(CFLAGS) -I${SRC_DIR}/../../generic \
${SHLIB_CFLAGS} -DUSE_TCL_STUBS ${AC_FLAGS}
all: embtest tcl9pkga${SHLIB_SUFFIX} tcl9pkgb${SHLIB_SUFFIX} tcl9pkgc${SHLIB_SUFFIX} \
tcl9pkgd${SHLIB_SUFFIX} tcl9pkge${SHLIB_SUFFIX} tcl9pkgt${SHLIB_SUFFIX} tcl9pkgua${SHLIB_SUFFIX} \
| | | > > > > > > > > > > > > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
LDFLAGS = @LDFLAGS_DEFAULT@ @LDFLAGS@
CC_SWITCHES = $(CFLAGS) -I${SRC_DIR}/../../generic \
${SHLIB_CFLAGS} -DUSE_TCL_STUBS ${AC_FLAGS}
all: embtest tcl9pkga${SHLIB_SUFFIX} tcl9pkgb${SHLIB_SUFFIX} tcl9pkgc${SHLIB_SUFFIX} \
tcl9pkgd${SHLIB_SUFFIX} tcl9pkge${SHLIB_SUFFIX} tcl9pkgt${SHLIB_SUFFIX} tcl9pkgua${SHLIB_SUFFIX} \
tcl9pkgooa${SHLIB_SUFFIX} pkga${SHLIB_SUFFIX} pkgb${SHLIB_SUFFIX} pkgc${SHLIB_SUFFIX} pkgt${SHLIB_SUFFIX}
@if test -n "$(DLTEST_SUFFIX)"; then $(MAKE) dltest_suffix; fi
@touch ../dltest.marker
dltest_suffix: tcl9pkga${DLTEST_SUFFIX} tcl9pkgb${DLTEST_SUFFIX} tcl9pkgc${DLTEST_SUFFIX} \
tcl9pkgd${DLTEST_SUFFIX} tcl9pkge${DLTEST_SUFFIX} tcl9pkgt${DLTEST_SUFFIX} tcl9pkgua${DLTEST_SUFFIX} \
tcl9pkgooa${DLTEST_SUFFIX} pkga${DLTEST_SUFFIX} pkgb${DLTEST_SUFFIX} pkgc${DLTEST_SUFFIX} pkgt${DLTEST_SUFFIX}
@touch ../dltest.marker
embtest.o: $(SRC_DIR)/embtest.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/embtest.c
pkgπ.o: $(SRC_DIR)/pkgπ.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgπ.c
pkga.o: $(SRC_DIR)/pkga.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkga.c
pkgb.o: $(SRC_DIR)/pkgb.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgb.c
pkgc.o: $(SRC_DIR)/pkgc.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgc.c
pkgt.o: $(SRC_DIR)/pkgt.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgt.c
tcl8pkga.o: $(SRC_DIR)/pkga.c
$(CC) -o $@ -c $(CC_SWITCHES) -DTCL_MAJOR_VERSION=8 $(SRC_DIR)/pkga.c
tcl8pkgb.o: $(SRC_DIR)/pkgb.c
$(CC) -o $@ -c $(CC_SWITCHES) -DTCL_MAJOR_VERSION=8 $(SRC_DIR)/pkgb.c
tcl8pkgc.o: $(SRC_DIR)/pkgc.c
$(CC) -o $@ -c $(CC_SWITCHES) -DTCL_MAJOR_VERSION=8 $(SRC_DIR)/pkgc.c
tcl8pkgt.o: $(SRC_DIR)/pkgt.c
$(CC) -o $@ -c $(CC_SWITCHES) -DTCL_MAJOR_VERSION=8 $(SRC_DIR)/pkgt.c
pkgd.o: $(SRC_DIR)/pkgd.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkgd.c
pkge.o: $(SRC_DIR)/pkge.c
$(CC) -c $(CC_SWITCHES) $(SRC_DIR)/pkge.c
pkgua.o: $(SRC_DIR)/pkgua.c
|
| ︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
tcl9pkgc${SHLIB_SUFFIX}: pkgc.o
${SHLIB_LD} -o $@ pkgc.o ${SHLIB_LD_LIBS}
tcl9pkgt${SHLIB_SUFFIX}: pkgt.o
${SHLIB_LD} -o $@ pkgt.o ${SHLIB_LD_LIBS}
tcl9pkgd${SHLIB_SUFFIX}: pkgd.o
${SHLIB_LD} -o $@ pkgd.o ${SHLIB_LD_LIBS}
tcl9pkge${SHLIB_SUFFIX}: pkge.o
${SHLIB_LD} -o $@ pkge.o ${SHLIB_LD_LIBS}
tcl9pkgua${SHLIB_SUFFIX}: pkgua.o
| > > > > > > > > > > > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
tcl9pkgc${SHLIB_SUFFIX}: pkgc.o
${SHLIB_LD} -o $@ pkgc.o ${SHLIB_LD_LIBS}
tcl9pkgt${SHLIB_SUFFIX}: pkgt.o
${SHLIB_LD} -o $@ pkgt.o ${SHLIB_LD_LIBS}
pkga${SHLIB_SUFFIX}: tcl8pkga.o
${SHLIB_LD} -o $@ tcl8pkga.o ${SHLIB_LD_LIBS}
pkgb${SHLIB_SUFFIX}: tcl8pkgb.o
${SHLIB_LD} -o $@ tcl8pkgb.o ${SHLIB_LD_LIBS}
pkgc${SHLIB_SUFFIX}: tcl8pkgc.o
${SHLIB_LD} -o $@ tcl8pkgc.o ${SHLIB_LD_LIBS}
pkgt${SHLIB_SUFFIX}: tcl8pkgt.o
${SHLIB_LD} -o $@ tcl8pkgt.o ${SHLIB_LD_LIBS}
tcl9pkgd${SHLIB_SUFFIX}: pkgd.o
${SHLIB_LD} -o $@ pkgd.o ${SHLIB_LD_LIBS}
tcl9pkge${SHLIB_SUFFIX}: pkge.o
${SHLIB_LD} -o $@ pkge.o ${SHLIB_LD_LIBS}
tcl9pkgua${SHLIB_SUFFIX}: pkgua.o
|
| ︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
tcl9pkgc${DLTEST_SUFFIX}: pkgc.o
${DLTEST_LD} -o $@ pkgc.o ${SHLIB_LD_LIBS}
tcl9pkgt${DLTEST_SUFFIX}: pkgt.o
${DLTEST_LD} -o $@ pkgt.o ${SHLIB_LD_LIBS}
tcl9pkgd${DLTEST_SUFFIX}: pkgd.o
${DLTEST_LD} -o $@ pkgd.o ${SHLIB_LD_LIBS}
tcl9pkge${DLTEST_SUFFIX}: pkge.o
${DLTEST_LD} -o $@ pkge.o ${SHLIB_LD_LIBS}
tcl9pkgua${DLTEST_SUFFIX}: pkgua.o
| > > > > > > > > > > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
tcl9pkgc${DLTEST_SUFFIX}: pkgc.o
${DLTEST_LD} -o $@ pkgc.o ${SHLIB_LD_LIBS}
tcl9pkgt${DLTEST_SUFFIX}: pkgt.o
${DLTEST_LD} -o $@ pkgt.o ${SHLIB_LD_LIBS}
pkga${DLTEST_SUFFIX}: tcl8pkga.o
${DLTEST_LD} -o $@ tcl8pkga.o ${SHLIB_LD_LIBS}
pkgb${DLTEST_SUFFIX}: tcl8pkgb.o
${DLTEST_LD} -o $@ tcl8pkgb.o ${SHLIB_LD_LIBS}
pkgc${DLTEST_SUFFIX}: tcl8pkgc.o
${DLTEST_LD} -o $@ tcl8pkgc.o ${SHLIB_LD_LIBS}
pkgt${DLTEST_SUFFIX}: tcl8pkgt.o
${DLTEST_LD} -o $@ tcl8pkgt.o ${SHLIB_LD_LIBS}
tcl9pkgd${DLTEST_SUFFIX}: pkgd.o
${DLTEST_LD} -o $@ pkgd.o ${SHLIB_LD_LIBS}
tcl9pkge${DLTEST_SUFFIX}: pkge.o
${DLTEST_LD} -o $@ pkge.o ${SHLIB_LD_LIBS}
tcl9pkgua${DLTEST_SUFFIX}: pkgua.o
|
| ︙ | ︙ |
Changes to unix/dltest/pkga.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * pkga.c -- * * This file contains a simple Tcl package "pkga" that is intended for * testing the Tcl dynamic loading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkga_EqObjCmd -- * * This procedure is invoked to process the "pkga_eq" Tcl command. It | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /* * pkga.c -- * * This file contains a simple Tcl package "pkga" that is intended for * testing the Tcl dynamic loading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tcl.h" #if TCL_MAJOR_VERSION < 9 # define Tcl_Size int #endif /* *---------------------------------------------------------------------- * * Pkga_EqObjCmd -- * * This procedure is invoked to process the "pkga_eq" Tcl command. It |
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
*----------------------------------------------------------------------
*/
static int
Pkga_EqObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
*----------------------------------------------------------------------
*/
static int
Pkga_EqObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result;
const char *str1, *str2;
Tcl_Size len1, len2;
(void)dummy;
if (objc != 3) {
|
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
*----------------------------------------------------------------------
*/
static int
Pkga_QuoteObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
*----------------------------------------------------------------------
*/
static int
Pkga_QuoteObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument strings. */
{
(void)dummy;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "value");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
121 122 123 124 125 126 127 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkga", "1.0");
if (code != TCL_OK) {
return code;
}
| | | | 126 127 128 129 130 131 132 133 134 135 136 137 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkga", "1.0");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkga_eq", Pkga_EqObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "pkga_quote", Pkga_QuoteObjCmd, NULL,
NULL);
return TCL_OK;
}
|
Changes to unix/dltest/pkgb.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /* * pkgb.c -- * * This file contains a simple Tcl package "pkgb" that is intended for * testing the Tcl dynamic loading facilities. It can be used in both * safe and unsafe interpreters. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" #if defined(_WIN32) && defined(_MSC_VER) # define snprintf _snprintf #endif /* *---------------------------------------------------------------------- * * Pkgb_SubObjCmd -- * | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /* * pkgb.c -- * * This file contains a simple Tcl package "pkgb" that is intended for * testing the Tcl dynamic loading facilities. It can be used in both * safe and unsafe interpreters. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tcl.h" #if defined(_WIN32) && defined(_MSC_VER) # define snprintf _snprintf #endif #if TCL_MAJOR_VERSION < 9 # define Tcl_Size int #endif /* *---------------------------------------------------------------------- * * Pkgb_SubObjCmd -- * |
| ︙ | ︙ | |||
33 34 35 36 37 38 39 |
*----------------------------------------------------------------------
*/
static int
Pkgb_SubObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
*----------------------------------------------------------------------
*/
static int
Pkgb_SubObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int first, second;
(void)dummy;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "num num");
return TCL_ERROR;
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
*----------------------------------------------------------------------
*/
static int
Pkgb_UnsafeObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
*----------------------------------------------------------------------
*/
static int
Pkgb_UnsafeObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
(void)dummy;
(void)objc;
(void)objv;
return Tcl_EvalEx(interp, "list unsafe command invoked", -1, TCL_EVAL_GLOBAL);
}
static int
Pkgb_DemoObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_WideInt numChars;
int result;
(void)dummy;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "arg1 arg2 num");
|
| ︙ | ︙ | |||
139 140 141 142 143 144 145 |
if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgb", "2.3");
if (code != TCL_OK) {
return code;
}
| | | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgb", "2.3");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkgb_sub", Pkgb_SubObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "pkgb_unsafe", Pkgb_UnsafeObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "pkgb_demo", Pkgb_DemoObjCmd, NULL, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Pkgb_SafeInit --
|
| ︙ | ︙ | |||
176 177 178 179 180 181 182 |
if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgb", "2.3");
if (code != TCL_OK) {
return code;
}
| | | 180 181 182 183 184 185 186 187 188 189 |
if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgb", "2.3");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkgb_sub", Pkgb_SubObjCmd, NULL, NULL);
return TCL_OK;
}
|
Changes to unix/dltest/pkgc.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* * pkgc.c -- * * This file contains a simple Tcl package "pkgc" that is intended for * testing the Tcl dynamic loading facilities. It can be used in both * safe and unsafe interpreters. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkgc_SubObjCmd -- * * This procedure is invoked to process the "pkgc_sub" Tcl command. It | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* * pkgc.c -- * * This file contains a simple Tcl package "pkgc" that is intended for * testing the Tcl dynamic loading facilities. It can be used in both * safe and unsafe interpreters. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tcl.h" #if TCL_MAJOR_VERSION < 9 # define Tcl_Size int #endif /* *---------------------------------------------------------------------- * * Pkgc_SubObjCmd -- * * This procedure is invoked to process the "pkgc_sub" Tcl command. It |
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
*----------------------------------------------------------------------
*/
static int
Pkgc_SubObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
*----------------------------------------------------------------------
*/
static int
Pkgc_SubObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int first, second;
(void)dummy;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "num num");
return TCL_ERROR;
|
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
*----------------------------------------------------------------------
*/
static int
Pkgc_UnsafeObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
*----------------------------------------------------------------------
*/
static int
Pkgc_UnsafeObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
(void)dummy;
(void)objc;
(void)objv;
Tcl_SetObjResult(interp, Tcl_NewStringObj("unsafe command invoked", -1));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Pkgc_Init --
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgc", "1.7.2");
if (code != TCL_OK) {
return code;
}
| | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgc", "1.7.2");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkgc_sub", Pkgc_SubObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "pkgc_unsafe", Pkgc_UnsafeObjCmd, NULL,
NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
148 149 150 151 152 153 154 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgc", "1.7.2");
if (code != TCL_OK) {
return code;
}
| | | 153 154 155 156 157 158 159 160 161 162 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgc", "1.7.2");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkgc_sub", Pkgc_SubObjCmd, NULL, NULL);
return TCL_OK;
}
|
Changes to unix/dltest/pkgd.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * pkgd.c -- * * This file contains a simple Tcl package "pkgd" that is intended for * testing the Tcl dynamic loading facilities. It can be used in both * safe and unsafe interpreters. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkgd_SubObjCmd -- * | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* * pkgd.c -- * * This file contains a simple Tcl package "pkgd" that is intended for * testing the Tcl dynamic loading facilities. It can be used in both * safe and unsafe interpreters. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkgd_SubObjCmd -- * |
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
*----------------------------------------------------------------------
*/
static int
Pkgd_SubObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
*----------------------------------------------------------------------
*/
static int
Pkgd_SubObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int first, second;
(void)dummy;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "num num");
return TCL_ERROR;
|
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
*----------------------------------------------------------------------
*/
static int
Pkgd_UnsafeObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
*----------------------------------------------------------------------
*/
static int
Pkgd_UnsafeObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
(void)dummy;
(void)objc;
(void)objv;
Tcl_SetObjResult(interp, Tcl_NewStringObj("unsafe command invoked", -1));
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Pkgd_Init --
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgd", "7.3");
if (code != TCL_OK) {
return code;
}
| | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgd", "7.3");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkgd_sub", Pkgd_SubObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "pkgd_unsafe", Pkgd_UnsafeObjCmd, NULL,
NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
148 149 150 151 152 153 154 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgd", "7.3");
if (code != TCL_OK) {
return code;
}
| | | 149 150 151 152 153 154 155 156 157 158 |
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgd", "7.3");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkgd_sub", Pkgd_SubObjCmd, NULL, NULL);
return TCL_OK;
}
|
Changes to unix/dltest/pkge.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * pkge.c -- * * This file contains a simple Tcl package "pkge" that is intended for * testing the Tcl dynamic loading facilities. Its Init procedure returns * an error in order to test how this is handled. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkge_Init -- * | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* * pkge.c -- * * This file contains a simple Tcl package "pkge" that is intended for * testing the Tcl dynamic loading facilities. Its Init procedure returns * an error in order to test how this is handled. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkge_Init -- * |
| ︙ | ︙ | |||
36 37 38 39 40 41 42 |
* made available. */
{
static const char script[] = "if 44 {open non_existent}";
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
| | | 37 38 39 40 41 42 43 44 45 |
* made available. */
{
static const char script[] = "if 44 {open non_existent}";
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
return Tcl_EvalEx(interp, script, -1, 0);
}
|
Changes to unix/dltest/pkgooa.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * pkgooa.c -- * * This file contains a simple Tcl package "pkgooa" that is intended for * testing the Tcl dynamic loading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclOO.h" #include <string.h> /* *---------------------------------------------------------------------- * * Pkgooa_StubsOKObjCmd -- | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * pkgooa.c -- * * This file contains a simple Tcl package "pkgooa" that is intended for * testing the Tcl dynamic loading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tclOO.h" #include <string.h> /* *---------------------------------------------------------------------- * * Pkgooa_StubsOKObjCmd -- |
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
*----------------------------------------------------------------------
*/
static int
Pkgooa_StubsOKObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
*----------------------------------------------------------------------
*/
static int
Pkgooa_StubsOKObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
(void)dummy;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
tclOOStubsPtr = &stubsCopy;
code = Tcl_PkgProvide(interp, "pkgooa", "1.0");
if (code != TCL_OK) {
return code;
}
| | | 139 140 141 142 143 144 145 146 147 148 |
tclOOStubsPtr = &stubsCopy;
code = Tcl_PkgProvide(interp, "pkgooa", "1.0");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "pkgooa_stubsok", Pkgooa_StubsOKObjCmd, NULL, NULL);
return TCL_OK;
}
|
Changes to unix/dltest/pkgt.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/*
* pkgt.c --
*
* This file contains a simple Tcl package "pkgt" that is intended for
* testing the Tcl dynamic loading facilities.
*
* Copyright © 1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tcl.h"
static int TraceProc2 (
void *clientData,
Tcl_Interp *interp,
Tcl_Size level,
const char *command,
Tcl_Command commandInfo,
| > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/*
* pkgt.c --
*
* This file contains a simple Tcl package "pkgt" that is intended for
* testing the Tcl dynamic loading facilities.
*
* Copyright © 1995 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#undef STATIC_BUILD
#include "tcl.h"
#if TCL_MAJOR_VERSION < 9
# define Tcl_Size int
#endif
static int TraceProc2 (
void *clientData,
Tcl_Interp *interp,
Tcl_Size level,
const char *command,
Tcl_Command commandInfo,
|
| ︙ | ︙ | |||
51 52 53 54 55 56 57 |
*/
static int
Pkgt_EqObjCmd2(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
| | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
*/
static int
Pkgt_EqObjCmd2(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
Tcl_WideInt result;
const char *str1, *str2;
Tcl_Size len1, len2;
(void)dummy;
if (objc != 3) {
|
| ︙ | ︙ |
Changes to unix/dltest/pkgua.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* * pkgua.c -- * * This file contains a simple Tcl package "pkgua" that is intended for * testing the Tcl dynamic unloading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * Copyright © 2004 Georgios Petasis * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* * In the following hash table we are going to store a struct that holds all * the command tokens created by Tcl_CreateObjCommand in an interpreter, * indexed by the interpreter. In this way, we can find which command tokens * we have registered in a specific interpreter, in order to unload them. We * need to keep the various command tokens we have registered, as they are the | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* * pkgua.c -- * * This file contains a simple Tcl package "pkgua" that is intended for * testing the Tcl dynamic unloading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * Copyright © 2004 Georgios Petasis * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tcl.h" #if TCL_MAJOR_VERSION < 9 # define Tcl_Size int #endif /* * In the following hash table we are going to store a struct that holds all * the command tokens created by Tcl_CreateObjCommand in an interpreter, * indexed by the interpreter. In this way, we can find which command tokens * we have registered in a specific interpreter, in order to unload them. We * need to keep the various command tokens we have registered, as they are the |
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
static void
PkguaDeleteTokens(
Tcl_Interp *interp)
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
Tcl_HashEntry *entryPtr =
| | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
static void
PkguaDeleteTokens(
Tcl_Interp *interp)
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
Tcl_HashEntry *entryPtr =
Tcl_FindHashEntry(&tsdPtr->interpTokenMap, (char *) interp);
if (entryPtr) {
Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
Tcl_DeleteHashEntry(entryPtr);
}
}
|
| ︙ | ︙ | |||
118 119 120 121 122 123 124 |
*----------------------------------------------------------------------
*/
static int
PkguaEqObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
*----------------------------------------------------------------------
*/
static int
PkguaEqObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
int result;
const char *str1, *str2;
Tcl_Size len1, len2;
(void)dummy;
if (objc != 3) {
|
| ︙ | ︙ | |||
165 166 167 168 169 170 171 |
*----------------------------------------------------------------------
*/
static int
PkguaQuoteObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
*----------------------------------------------------------------------
*/
static int
PkguaQuoteObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument strings. */
{
(void)dummy;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "value");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
223 224 225 226 227 228 229 |
return code;
}
Tcl_SetVar2(interp, "::pkgua_loaded", NULL, ".", TCL_APPEND_VALUE);
cmdTokens = PkguaInterpToTokens(interp);
cmdTokens[0] =
| | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
return code;
}
Tcl_SetVar2(interp, "::pkgua_loaded", NULL, ".", TCL_APPEND_VALUE);
cmdTokens = PkguaInterpToTokens(interp);
cmdTokens[0] =
Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, &cmdTokens[0],
CommandDeleted);
cmdTokens[1] =
Tcl_CreateObjCommand(interp, "pkgua_quote", PkguaQuoteObjCmd,
&cmdTokens[1], CommandDeleted);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ |
Changes to unix/dltest/pkgπ.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * pkgπ.c -- * * This file contains a simple Tcl package "pkgπ" that is intended for * testing the Tcl dynamic loading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkga_EqObjCmd -- * | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * pkgπ.c -- * * This file contains a simple Tcl package "pkgπ" that is intended for * testing the Tcl dynamic loading facilities. * * Copyright © 1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #include "tcl.h" /* *---------------------------------------------------------------------- * * Pkga_EqObjCmd -- * |
| ︙ | ︙ | |||
30 31 32 33 34 35 36 |
*----------------------------------------------------------------------
*/
static int
Pkg\u03C0_\u03A0ObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
| | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
*----------------------------------------------------------------------
*/
static int
Pkg\u03C0_\u03A0ObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
(void)dummy;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
if (Tcl_InitStubs(interp, "9.0-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgπ", "1.0");
if (code != TCL_OK) {
return code;
}
| | | 76 77 78 79 80 81 82 83 84 85 |
if (Tcl_InitStubs(interp, "9.0-", 0) == NULL) {
return TCL_ERROR;
}
code = Tcl_PkgProvide(interp, "pkgπ", "1.0");
if (code != TCL_OK) {
return code;
}
Tcl_CreateObjCommand(interp, "Ï€", Pkg\u03C0_\u03A0ObjCmd, NULL, NULL);
return TCL_OK;
}
|
Changes to unix/tcl.m4.
| ︙ | ︙ | |||
89 90 91 92 93 94 95 |
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in `ls -d ${libdir} 2>/dev/null` \
`ls -d ${exec_prefix}/lib 2>/dev/null` \
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
| | | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
if test x"${ac_cv_c_tclconfig}" = x ; then
for i in `ls -d ${libdir} 2>/dev/null` \
`ls -d ${exec_prefix}/lib 2>/dev/null` \
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib/tcl9.0 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
`ls -d /usr/local/lib/tcl9.0 2>/dev/null` \
`ls -d /usr/local/lib/tcl/tcl9.0 2>/dev/null` \
; do
if test -f "$i/tclConfig.sh" ; then
ac_cv_c_tclconfig="`(cd $i; pwd)`"
break
fi
done
fi
|
| ︙ | ︙ | |||
222 223 224 225 226 227 228 |
if test x"${ac_cv_c_tkconfig}" = x ; then
for i in `ls -d ${libdir} 2>/dev/null` \
`ls -d ${exec_prefix}/lib 2>/dev/null` \
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
| | | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
if test x"${ac_cv_c_tkconfig}" = x ; then
for i in `ls -d ${libdir} 2>/dev/null` \
`ls -d ${exec_prefix}/lib 2>/dev/null` \
`ls -d ${prefix}/lib 2>/dev/null` \
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib/tk9.0 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
`ls -d /usr/local/lib/tk9.0 2>/dev/null` \
`ls -d /usr/local/lib/tcl/tk9.0 2>/dev/null` \
; do
if test -f "$i/tkConfig.sh" ; then
ac_cv_c_tkconfig="`(cd $i; pwd)`"
break
fi
done
fi
|
| ︙ | ︙ | |||
437 438 439 440 441 442 443 |
AC_CACHE_VAL(ac_cv_path_tclsh, [
search_path=`echo ${PATH} | sed -e 's/:/ /g'`
for dir in $search_path ; do
for j in `ls -r $dir/tclsh[[8-9]]* 2> /dev/null` \
`ls -r $dir/tclsh* 2> /dev/null` ; do
if test x"$ac_cv_path_tclsh" = x ; then
if test -f "$j" ; then
| < < < < | | < | 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
AC_CACHE_VAL(ac_cv_path_tclsh, [
search_path=`echo ${PATH} | sed -e 's/:/ /g'`
for dir in $search_path ; do
for j in `ls -r $dir/tclsh[[8-9]]* 2> /dev/null` \
`ls -r $dir/tclsh* 2> /dev/null` ; do
if test x"$ac_cv_path_tclsh" = x ; then
if test -f "$j" ; then
ac_cv_path_tclsh=$j
break
fi
fi
done
done
])
if test -f "$ac_cv_path_tclsh" ; then
|
| ︙ | ︙ | |||
2177 2178 2179 2180 2181 2182 2183 |
#--------------------------------------------------------------------
# Interactive UNIX requires -linet instead of -lsocket, plus it
# needs net/errno.h to define the socket-related error codes.
#--------------------------------------------------------------------
AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"])
| < | 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 |
#--------------------------------------------------------------------
# Interactive UNIX requires -linet instead of -lsocket, plus it
# needs net/errno.h to define the socket-related error codes.
#--------------------------------------------------------------------
AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"])
AC_CHECK_HEADER(net/errno.h, [
AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have <net/errno.h>?])])
#--------------------------------------------------------------------
# Check for the existence of the -lsocket and -lnsl libraries.
# The order here is important, so that they end up in the right
# order in the command line generated by make. Here are some
|
| ︙ | ︙ | |||
2256 2257 2258 2259 2260 2261 2262 |
fi
# Does the pthread-implementation provide
# 'pthread_attr_setstacksize' ?
ac_saved_libs=$LIBS
LIBS="$LIBS $THREADS_LIBS"
| | | 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 |
fi
# Does the pthread-implementation provide
# 'pthread_attr_setstacksize' ?
ac_saved_libs=$LIBS
LIBS="$LIBS $THREADS_LIBS"
AC_CHECK_FUNCS(pthread_attr_setstacksize pthread_atfork)
LIBS=$ac_saved_libs
])
#--------------------------------------------------------------------
# SC_TCL_EARLY_FLAGS
#
# Check for what flags are needed to be passed so the correct OS
|
| ︙ | ︙ |
Changes to unix/tcl.spec.
1 2 3 4 5 6 |
# This file is the basis for a binary Tcl RPM for Linux.
%{!?directory:%define directory /usr/local}
Name: tcl
Summary: Tcl scripting language development environment
| | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# This file is the basis for a binary Tcl RPM for Linux.
%{!?directory:%define directory /usr/local}
Name: tcl
Summary: Tcl scripting language development environment
Version: 9.0.5
Release: 2
License: BSD
Group: Development/Languages
Source: https://prdownloads.sourceforge.net/tcl/tcl%{version}-src.tar.gz
URL: https://www.tcl-lang.org/
Buildroot: /var/tmp/%{name}%{version}
|
| ︙ | ︙ |
Changes to unix/tclAppInit.c.
1 2 3 4 5 6 | /* * tclAppInit.c -- * * Provides a default version of the main program and Tcl_AppInit * procedure for tclsh and other Tcl-based applications (without Tk). * | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/*
* tclAppInit.c --
*
* Provides a default version of the main program and Tcl_AppInit
* procedure for tclsh and other Tcl-based applications (without Tk).
*
* Copyright (c) 1993 The Regents of the University of California.
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
* Copyright (c) 1998-1999 Scriptics Corporation.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tcl.h"
#if TCL_MAJOR_VERSION < 9
# if defined(USE_TCL_STUBS)
# error "Don't build with USE_TCL_STUBS!"
# endif
# define Tcl_LibraryInitProc Tcl_PackageInitProc
# define Tcl_StaticLibrary Tcl_StaticPackage
#endif
#ifdef TCL_TEST
#ifdef __cplusplus
extern "C" {
#endif
extern Tcl_LibraryInitProc Tcltest_Init;
extern Tcl_LibraryInitProc Tcltest_SafeInit;
#ifdef __cplusplus
}
#endif
#endif /* TCL_TEST */
#ifdef TCL_XT_TEST
extern void XtToolkitInitialize(void);
extern Tcl_LibraryInitProc Tclxttest_Init;
#endif /* TCL_XT_TEST */
/*
* The following #if block allows you to change the AppInit function by using
* a #define of TCL_LOCAL_APPINIT instead of rewriting this entire file. The
* #if checks for that #define and uses Tcl_AppInit if it does not exist.
*/
#ifndef TCL_LOCAL_APPINIT
#define TCL_LOCAL_APPINIT Tcl_AppInit
#endif
#ifndef MODULE_SCOPE
# define MODULE_SCOPE extern
#endif
MODULE_SCOPE int TCL_LOCAL_APPINIT(Tcl_Interp *);
MODULE_SCOPE int main(int, char **);
/*
* The following #if block allows you to change how Tcl finds the startup
* script, prime the library or encoding paths, fiddle with the argv, etc.,
* without needing to rewrite Tcl_Main()
*/
#ifdef TCL_LOCAL_MAIN_HOOK
MODULE_SCOPE int TCL_LOCAL_MAIN_HOOK(int *argc, char ***argv);
#endif
/*
*----------------------------------------------------------------------
*
* main --
*
* This is the main program for the application.
|
| ︙ | ︙ | |||
142 143 144 145 146 147 148 |
#ifdef TCL_LOCAL_MAIN_HOOK
TCL_LOCAL_MAIN_HOOK(&argc, &argv);
#elif TCL_MAJOR_VERSION > 8 && (!defined(_WIN32) || defined(UNICODE))
/* New in Tcl 9.0. This doesn't work on Windows without UNICODE */
TclZipfs_AppHook(&argc, &argv);
#endif
| < < < < | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
#ifdef TCL_LOCAL_MAIN_HOOK
TCL_LOCAL_MAIN_HOOK(&argc, &argv);
#elif TCL_MAJOR_VERSION > 8 && (!defined(_WIN32) || defined(UNICODE))
/* New in Tcl 9.0. This doesn't work on Windows without UNICODE */
TclZipfs_AppHook(&argc, &argv);
#endif
Tcl_Main(argc, argv, TCL_LOCAL_APPINIT);
return 0; /* Needed only to prevent compiler warning. */
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
#ifdef TCL_XT_TEST
if (Tclxttest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
#endif
/*
* Call the init procedures for included packages. Each call should look
* like this:
*
* if (Mod_Init(interp) == TCL_ERROR) {
* return TCL_ERROR;
* }
| > > > > > > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
#ifdef TCL_XT_TEST
if (Tclxttest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
#endif
#ifdef TCL_TEST
if (Tcltest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticLibrary(interp, "Tcltest", Tcltest_Init, Tcltest_SafeInit);
#endif /* TCL_TEST */
/*
* Call the init procedures for included packages. Each call should look
* like this:
*
* if (Mod_Init(interp) == TCL_ERROR) {
* return TCL_ERROR;
* }
|
| ︙ | ︙ | |||
205 206 207 208 209 210 211 |
*/
/*
* Specify a user-specific startup file to invoke if the application is
* run interactively. Typically the startup file is "~/.apprc" where "app"
* is the name of the application. If this line is deleted then no
* user-specific startup file will be run under any conditions.
| < < > > > > > | | > > | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
*/
/*
* Specify a user-specific startup file to invoke if the application is
* run interactively. Typically the startup file is "~/.apprc" where "app"
* is the name of the application. If this line is deleted then no
* user-specific startup file will be run under any conditions.
*/
#ifdef DJGPP
#define INITFILENAME "tclshrc.tcl"
#else
#define INITFILENAME ".tclshrc"
#endif
(void) Tcl_EvalEx(interp,
"set tcl_rcFileName [file tildeexpand ~/" INITFILENAME "]",
-1, TCL_EVAL_GLOBAL);
return TCL_OK;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to unix/tclConfig.h.in.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | /* Define to 1 if you have the 'cfmakeraw' function. */ #undef HAVE_CFMAKERAW /* Define to 1 if you have the 'chflags' function. */ #undef HAVE_CHFLAGS | < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /* Define to 1 if you have the 'cfmakeraw' function. */ #undef HAVE_CFMAKERAW /* Define to 1 if you have the 'chflags' function. */ #undef HAVE_CHFLAGS /* Define to 1 if you have the 'copyfile' function. */ #undef HAVE_COPYFILE /* Define to 1 if you have the <copyfile.h> header file. */ #undef HAVE_COPYFILE_H /* Do we have access to Darwin CoreFoundation.framework? */ |
| ︙ | ︙ |
Changes to unix/tclEpollNotfy.c.
| ︙ | ︙ | |||
117 118 119 120 121 122 123 | static Tcl_ThreadDataKey dataKey; /* * Forward declarations. */ static void PlatformEventsControl(FileHandler *filePtr, | | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | static Tcl_ThreadDataKey dataKey; /* * Forward declarations. */ static void PlatformEventsControl(FileHandler *filePtr, ThreadSpecificData *tsdPtr, int op, int isNew); static void PlatformEventsInit(void); static int PlatformEventsTranslate(struct epoll_event *event); static int PlatformEventsWait(struct epoll_event *events, size_t numEvents, struct timeval *timePtr); /* * Incorporate the base notifier implementation. |
| ︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
TclpInitNotifier(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
PlatformEventsInit();
return tsdPtr;
}
/*
*----------------------------------------------------------------------
*
* PlatformEventsControl --
*
* This function registers interest for the file descriptor and the mask
| > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
TclpInitNotifier(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
PlatformEventsInit();
return tsdPtr;
}
/*
*----------------------------------------------------------------------
*
* PlatformEventsControl --
*
* This function registers interest for the file descriptor and the mask
|
| ︙ | ︙ | |||
188 189 190 191 192 193 194 |
*/
static void
PlatformEventsControl(
FileHandler *filePtr,
ThreadSpecificData *tsdPtr,
int op,
| | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
*/
static void
PlatformEventsControl(
FileHandler *filePtr,
ThreadSpecificData *tsdPtr,
int op,
int isNew)
{
struct epoll_event newEvent;
struct PlatformEventData *newPedPtr;
Tcl_StatBuf fdStat;
newEvent.events = 0;
if (filePtr->mask & (TCL_READABLE | TCL_EXCEPTION)) {
|
| ︙ | ︙ | |||
211 212 213 214 215 216 217 |
newPedPtr->filePtr = filePtr;
newPedPtr->tsdPtr = tsdPtr;
filePtr->pedPtr = newPedPtr;
}
newEvent.data.ptr = filePtr->pedPtr;
/*
| | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
newPedPtr->filePtr = filePtr;
newPedPtr->tsdPtr = tsdPtr;
filePtr->pedPtr = newPedPtr;
}
newEvent.data.ptr = filePtr->pedPtr;
/*
* N.B. As discussed in Tcl_WaitForEvent(), epoll(7) does not support
* regular files (S_IFREG). Therefore, filePtr is in these cases simply
* added or deleted from the list of FileHandlers associated with regular
* files belonging to tsdPtr.
*/
if (TclOSfstat(filePtr->fd, &fdStat) == -1) {
/*
|
| ︙ | ︙ | |||
615 616 617 618 619 620 621 | * Queues file events that are detected by PlatformEventsWait(). * *---------------------------------------------------------------------- */ int TclpWaitForEvent( | | > | > > > > > > > > > > > | | | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
* Queues file events that are detected by PlatformEventsWait().
*
*----------------------------------------------------------------------
*/
int
TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
FileHandler *filePtr;
Tcl_Time vTime;
struct timeval timeout, *timeoutPtr;
/* Impl. notes: timeout & timeoutPtr are used
* if, and only if threads are not enabled.
* They are the arguments for the regular
* epoll_wait() used when the core is not
* thread-enabled. */
int mask, numFound, numEvent;
struct PlatformEventData *pedPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int numQueued;
ssize_t i;
/*
* Set up the timeout structure. Note that if there are no events to check
* for, we return with a negative result rather than blocking forever.
*/
if (timePtr != NULL) {
/*
* TIP #233 (Virtualized Time). Is virtual time in effect? And do we
* actually have something to scale? If yes to both then we call the
* handler to do this scaling.
*/
if (timePtr->sec != 0 || timePtr->usec != 0) {
vTime = *timePtr;
TclScaleTime(&vTime);
timePtr = &vTime;
}
timeout.tv_sec = timePtr->sec;
timeout.tv_usec = timePtr->usec;
timeoutPtr = &timeout;
} else {
timeoutPtr = NULL;
}
/*
* Walk the list of FileHandlers associated with regular files (S_IFREG)
|
| ︙ | ︙ | |||
775 776 777 778 779 780 781 | * * Side effects: * The signal may be resent to the target thread. * *---------------------------------------------------------------------- */ | < > | | | | | | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
*
* Side effects:
* The signal may be resent to the target thread.
*
*----------------------------------------------------------------------
*/
int
TclAsyncNotifier(
int sigNumber, /* Signal number. */
Tcl_ThreadId threadId, /* Target thread. */
void *clientData, /* Notifier data. */
int *flagPtr, /* Flag to mark. */
int value) /* Value of mark. */
{
#if TCL_THREADS
/*
* WARNING:
* This code most likely runs in a signal handler. Thus,
* only few async-signal-safe system calls are allowed,
* e.g. pthread_self(), sem_post(), write().
*/
if (pthread_equal(pthread_self(), (pthread_t) threadId)) {
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
*flagPtr = value;
if (tsdPtr != NULL && !tsdPtr->asyncPending) {
tsdPtr->asyncPending = true;
TclpAlertNotifier(tsdPtr);
return 1;
}
return 0;
}
/*
* Re-send the signal to the proper target thread.
*/
pthread_kill((pthread_t) threadId, sigNumber);
#else
(void)sigNumber;
(void)threadId;
(void)clientData;
(void)flagPtr;
(void)value;
#endif
return 0;
}
#endif /* NOTIFIER_EPOLL && TCL_THREADS */
#else
TCL_MAC_EMPTY_FILE(unix_tclEpollNotfy_c)
#endif /* !HAVE_COREFOUNDATION */
|
| ︙ | ︙ |
Changes to unix/tclKqueueNotfy.c.
| ︙ | ︙ | |||
98 99 100 101 102 103 104 |
int triggerPipe[2]; /* pipe(2) used by other threads to wake
* up this thread for inter-thread IPC. */
int eventsFd; /* kqueue(2) file descriptor used to wait for
* fds. */
struct kevent *readyEvents; /* Pointer to at most maxReadyEvents events
* returned by kevent(2). */
size_t maxReadyEvents; /* Count of kevents in readyEvents. */
| | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
int triggerPipe[2]; /* pipe(2) used by other threads to wake
* up this thread for inter-thread IPC. */
int eventsFd; /* kqueue(2) file descriptor used to wait for
* fds. */
struct kevent *readyEvents; /* Pointer to at most maxReadyEvents events
* returned by kevent(2). */
size_t maxReadyEvents; /* Count of kevents in readyEvents. */
int asyncPending; /* True when signal triggered thread. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
* Forward declarations of internal functions.
*/
static void PlatformEventsControl(FileHandler *filePtr,
ThreadSpecificData *tsdPtr, int op, int isNew);
static int PlatformEventsTranslate(struct kevent *eventPtr);
static int PlatformEventsWait(struct kevent *events,
size_t numEvents, struct timeval *timePtr);
/*
* Incorporate the base notifier implementation.
*/
|
| ︙ | ︙ | |||
154 155 156 157 158 159 160 |
*/
static void
PlatformEventsControl(
FileHandler *filePtr,
ThreadSpecificData *tsdPtr,
int op,
| | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
*/
static void
PlatformEventsControl(
FileHandler *filePtr,
ThreadSpecificData *tsdPtr,
int op,
int isNew)
{
int numChanges;
struct kevent changeList[2];
struct PlatformEventData *newPedPtr;
Tcl_StatBuf fdStat;
if (isNew) {
newPedPtr = (struct PlatformEventData *)
Tcl_Alloc(sizeof(struct PlatformEventData));
newPedPtr->filePtr = filePtr;
newPedPtr->tsdPtr = tsdPtr;
filePtr->pedPtr = newPedPtr;
}
/*
* N.B. As discussed in Tcl_WaitForEvent(), kqueue(2) does not reproduce
* the `always ready' {select,poll}(2) behaviour for regular files
* (S_IFREG) prior to FreeBSD 11.0-RELEASE. Therefore, filePtr is in these
* cases simply added or deleted from the list of FileHandlers associated
* with regular files belonging to tsdPtr.
*/
if (TclOSfstat(filePtr->fd, &fdStat) == -1) {
|
| ︙ | ︙ | |||
357 358 359 360 361 362 363 |
Tcl_Panic("kqueue: %s", strerror(errno));
} else if (fcntl(tsdPtr->eventsFd, F_SETFD, FD_CLOEXEC) == -1) {
Tcl_Panic("fcntl: %s", strerror(errno));
}
filePtr = (FileHandler *) Tcl_Alloc(sizeof(FileHandler));
filePtr->fd = tsdPtr->triggerPipe[0];
filePtr->mask = TCL_READABLE;
| | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
Tcl_Panic("kqueue: %s", strerror(errno));
} else if (fcntl(tsdPtr->eventsFd, F_SETFD, FD_CLOEXEC) == -1) {
Tcl_Panic("fcntl: %s", strerror(errno));
}
filePtr = (FileHandler *) Tcl_Alloc(sizeof(FileHandler));
filePtr->fd = tsdPtr->triggerPipe[0];
filePtr->mask = TCL_READABLE;
PlatformEventsControl(filePtr, tsdPtr, EV_ADD, 1);
if (!tsdPtr->readyEvents) {
tsdPtr->maxReadyEvents = 512;
tsdPtr->readyEvents = (struct kevent *) Tcl_Alloc(
tsdPtr->maxReadyEvents * sizeof(tsdPtr->readyEvents[0]));
}
LIST_INIT(&tsdPtr->firstReadyFileHandlerPtr);
|
| ︙ | ︙ | |||
480 481 482 483 484 485 486 |
timersub(timePtr, &tv_delta, timePtr);
} else {
timePtr->tv_sec = 0;
timePtr->tv_usec = 0;
}
}
if (tsdPtr->asyncPending) {
| | | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
timersub(timePtr, &tv_delta, timePtr);
} else {
timePtr->tv_sec = 0;
timePtr->tv_usec = 0;
}
}
if (tsdPtr->asyncPending) {
tsdPtr->asyncPending = 0;
TclAsyncMarkFromNotifier();
}
return numFound;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
513 514 515 516 517 518 519 |
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
* conditions under which proc should be
* called. */
Tcl_FileProc *proc, /* Function to call for each selected
* event. */
| | | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
* conditions under which proc should be
* called. */
Tcl_FileProc *proc, /* Function to call for each selected
* event. */
void *clientData) /* Arbitrary data to pass to proc. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
FileHandler *filePtr = LookUpFileHandler(tsdPtr, fd, NULL);
int isNew = (filePtr == NULL);
if (isNew) {
filePtr = (FileHandler *) Tcl_Alloc(sizeof(FileHandler));
filePtr->fd = fd;
filePtr->readyMask = 0;
filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
tsdPtr->firstFileHandlerPtr = filePtr;
|
| ︙ | ︙ | |||
574 575 576 577 578 579 580 |
return;
}
/*
* Update the check masks for this file.
*/
| | | 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 |
return;
}
/*
* Update the check masks for this file.
*/
PlatformEventsControl(filePtr, tsdPtr, EV_DELETE, 0);
if (filePtr->pedPtr) {
Tcl_Free(filePtr->pedPtr);
}
/*
* Clean up information in the callback record.
*/
|
| ︙ | ︙ | |||
614 615 616 617 618 619 620 | * Queues file events that are detected by PlatformEventsWait(). * *---------------------------------------------------------------------- */ int TclpWaitForEvent( | | > | > > > > > > > > > > > | | | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
* Queues file events that are detected by PlatformEventsWait().
*
*----------------------------------------------------------------------
*/
int
TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
FileHandler *filePtr;
int mask;
Tcl_Time vTime;
struct timeval timeout, *timeoutPtr;
/* Impl. notes: timeout & timeoutPtr are used
* if, and only if threads are not enabled.
* They are the arguments for the regular
* epoll_wait() used when the core is not
* thread-enabled. */
int numFound, numEvent;
struct PlatformEventData *pedPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int numQueued;
ssize_t i;
char buf[1];
/*
* Set up the timeout structure. Note that if there are no events to check
* for, we return with a negative result rather than blocking forever.
*/
if (timePtr != NULL) {
/*
* TIP #233 (Virtualized Time). Is virtual time in effect? And do we
* actually have something to scale? If yes to both then we call the
* handler to do this scaling.
*/
if (timePtr->sec != 0 || timePtr->usec != 0) {
vTime = *timePtr;
TclScaleTime(&vTime);
timePtr = &vTime;
}
timeout.tv_sec = timePtr->sec;
timeout.tv_usec = timePtr->usec;
timeoutPtr = &timeout;
} else {
timeoutPtr = NULL;
}
/*
* Walk the list of FileHandlers associated with regular files (S_IFREG)
|
| ︙ | ︙ | |||
766 767 768 769 770 771 772 | * * Side effects: * The signal may be resent to the target thread. * *---------------------------------------------------------------------- */ | < > | | | | | | | | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 |
*
* Side effects:
* The signal may be resent to the target thread.
*
*----------------------------------------------------------------------
*/
int
TclAsyncNotifier(
int sigNumber, /* Signal number. */
Tcl_ThreadId threadId, /* Target thread. */
void *clientData, /* Notifier data. */
int *flagPtr, /* Flag to mark. */
int value) /* Value of mark. */
{
#if TCL_THREADS
/*
* WARNING:
* This code most likely runs in a signal handler. Thus,
* only few async-signal-safe system calls are allowed,
* e.g. pthread_self(), sem_post(), write().
*/
if (pthread_equal(pthread_self(), (pthread_t) threadId)) {
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
*flagPtr = value;
if (tsdPtr != NULL && !tsdPtr->asyncPending) {
tsdPtr->asyncPending = 1;
TclpAlertNotifier(tsdPtr);
return 1;
}
return 0;
}
/*
* Re-send the signal to the proper target thread.
*/
pthread_kill((pthread_t) threadId, sigNumber);
#else
(void)sigNumber;
(void)threadId;
(void)clientData;
(void)flagPtr;
(void)value;
#endif
return 0;
}
#endif /* NOTIFIER_KQUEUE && TCL_THREADS */
#else
TCL_MAC_EMPTY_FILE(unix_tclKqueueNotfy_c)
#endif /* !HAVE_COREFOUNDATION */
|
| ︙ | ︙ |
Changes to unix/tclLoadAix.c.
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
* to find an exported symbol we read the loader section of the loaded module
* and build a list of exported symbols and their virtual address.
*/
typedef struct {
char *name; /* The symbols's name. */
void *addr; /* Its relocated virtual address. */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | | | < < | < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
* to find an exported symbol we read the loader section of the loaded module
* and build a list of exported symbols and their virtual address.
*/
typedef struct {
char *name; /* The symbols's name. */
void *addr; /* Its relocated virtual address. */
} Export, *ExportPtr;
/*
* xlC uses the following structure to list its constructors and destructors.
* This is gleaned from the output of munch.
*/
typedef struct {
void (*init)(void); /* call static constructors */
void (*term)(void); /* call static destructors */
} Cdtor, *CdtorPtr;
/*
* The void * handle returned from dlopen is actually a ModulePtr.
*/
typedef struct Module {
struct Module *next;
char *name; /* module name for refcounting */
int refCnt; /* the number of references */
void *entry; /* entry point from load */
struct dl_info *info; /* optional init/terminate functions */
CdtorPtr cdtors; /* optional C++ constructors */
int nExports; /* the number of exports found */
ExportPtr exports; /* the array of exports */
} Module, *ModulePtr;
/*
* We keep a list of all loaded modules to be able to call the fini handlers
* and destructors at atexit() time.
*/
static ModulePtr modList;
/*
* The last error from one of the dl* routines is kept in static variables
* here. Each error is returned only once to the caller.
*/
static char errbuf[BUFSIZ];
static int errvalid;
static void caterr(char *);
static int readExports(ModulePtr);
static void terminate(void);
static void *findMain(void);
void *
dlopen(
const char *path,
int mode)
{
ModulePtr mp;
static void *mainModule;
/*
* Upon the first call register a terminate handler that will close all
* libraries. Also get a reference to the main module for use with
* loadbind.
*/
if (!mainModule) {
mainModule = findMain();
if (mainModule == NULL) {
return NULL;
}
atexit(terminate);
}
/*
* Scan the list of modules if we have the module already loaded.
*/
for (mp = modList; mp; mp = mp->next) {
if (strcmp(mp->name, path) == 0) {
mp->refCnt++;
return (void *)mp;
}
}
mp = (ModulePtr) calloc(1, sizeof(*mp));
if (mp == NULL) {
errvalid++;
strcpy(errbuf, "calloc: ");
strcat(errbuf, strerror(errno));
return NULL;
}
mp->name = malloc(strlen(path) + 1);
strcpy(mp->name, path);
/*
* load should be declared load(const char *...). Thus we cast the path to
* a normal char *. Ugly.
*/
mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL);
if (mp->entry == NULL) {
free(mp->name);
free(mp);
errvalid++;
strcpy(errbuf, "dlopen: ");
strcat(errbuf, path);
strcat(errbuf, ": ");
/*
* If AIX says the file is not executable, the error can be further
* described by querying the loader about the last error.
*/
if (errno == ENOEXEC) {
char *tmp[BUFSIZ/sizeof(char *)], **p;
if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1) {
strcpy(errbuf, strerror(errno));
} else {
for (p=tmp ; *p ; p++) {
caterr(*p);
}
}
} else {
strcat(errbuf, strerror(errno));
}
return NULL;
}
mp->refCnt = 1;
mp->next = modList;
modList = mp;
if (loadbind(0, mainModule, mp->entry) == -1) {
loadbindFailure:
dlclose(mp);
errvalid++;
strcpy(errbuf, "loadbind: ");
strcat(errbuf, strerror(errno));
return NULL;
}
/*
* If the user wants global binding, loadbind against all other loaded
* modules.
*/
if (mode & RTLD_GLOBAL) {
ModulePtr mp1;
for (mp1 = mp->next; mp1; mp1 = mp1->next) {
if (loadbind(0, mp1->entry, mp->entry) == -1) {
goto loadbindFailure;
}
}
}
if (readExports(mp) == -1) {
dlclose(mp);
return NULL;
}
/*
* If there is a dl_info structure, call the init function.
*/
if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
if (mp->info->init) {
mp->info->init();
}
} else {
errvalid = 0;
}
/*
* If the shared object was compiled using xlC we will need to call static
* constructors (and later on dlclose destructors).
*/
if (mp->cdtors = (CdtorPtr) dlsym(mp, "__cdtors")) {
while (mp->cdtors->init) {
mp->cdtors->init();
mp->cdtors++;
}
} else {
errvalid = 0;
}
return (void *)mp;
}
/*
* Attempt to decipher an AIX loader error message and append it to our static
* error message buffer.
*/
static void
caterr(
char *s)
{
char *p = s;
while (*p >= '0' && *p <= '9') {
p++;
}
switch (atoi(s)) { /* INTL: "C", UTF safe. */
case L_ERROR_TOOMANY:
strcat(errbuf, "to many errors");
break;
case L_ERROR_NOLIB:
strcat(errbuf, "cannot load library");
strcat(errbuf, p);
break;
case L_ERROR_UNDEF:
strcat(errbuf, "cannot find symbol");
strcat(errbuf, p);
break;
case L_ERROR_RLDBAD:
strcat(errbuf, "bad RLD");
strcat(errbuf, p);
break;
case L_ERROR_FORMAT:
strcat(errbuf, "bad exec format in");
strcat(errbuf, p);
break;
case L_ERROR_ERRNO:
strcat(errbuf, strerror(atoi(++p))); /* INTL: "C", UTF safe. */
break;
default:
strcat(errbuf, s);
break;
}
}
void *
dlsym(
void *handle,
const char *symbol)
{
ModulePtr mp = (ModulePtr)handle;
ExportPtr ep;
int i;
/*
* Could speed up the search, but I assume that one assigns the result to
* function pointers anyways.
*/
for (ep = mp->exports, i = mp->nExports; i; i--, ep++) {
if (strcmp(ep->name, symbol) == 0) {
return ep->addr;
}
}
errvalid++;
strcpy(errbuf, "dlsym: undefined symbol ");
strcat(errbuf, symbol);
return NULL;
}
char *
dlerror(void)
{
if (errvalid) {
errvalid = 0;
return errbuf;
}
return NULL;
}
int
dlclose(
void *handle)
{
ModulePtr mp = (ModulePtr)handle;
int result;
ModulePtr mp1;
if (--mp->refCnt > 0) {
return 0;
}
if (mp->info && mp->info->fini) {
mp->info->fini();
}
if (mp->cdtors) {
while (mp->cdtors->term) {
mp->cdtors->term();
mp->cdtors++;
}
}
result = unload(mp->entry);
if (result == -1) {
errvalid++;
strcpy(errbuf, strerror(errno));
}
if (mp->exports) {
ExportPtr ep;
int i;
for (ep = mp->exports, i = mp->nExports; i; i--, ep++) {
if (ep->name) {
free(ep->name);
}
}
free(mp->exports);
|
| ︙ | ︙ | |||
376 377 378 379 380 381 382 |
}
free(mp->name);
free(mp);
return result;
}
| < < < < < < < < < < < < < < < | < < < < | | < < | < < < < < | | | | < < < < | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 |
}
free(mp->name);
free(mp);
return result;
}
static void
terminate(void)
{
while (modList) {
dlclose(modList);
}
}
/*
* Build the export table from the XCOFF .loader section.
*/
static int
readExports(
ModulePtr mp)
{
LDFILE *ldp = NULL;
SCNHDR sh, shdata;
LDHDR *lhp;
char *ldbuf;
LDSYM *ls;
int i;
ExportPtr ep;
const char *errMsg;
#define Error(msg) do{errMsg=(msg);goto error;}while(0)
#define SysErr() Error(strerror(errno))
ldp = ldopen(mp->name, ldp);
if (ldp == NULL) {
struct ld_info *lp;
char *buf;
int size = 0;
|
| ︙ | ︙ | |||
544 545 546 547 548 549 550 |
for (i = lhp->l_nsyms; i; i--, ls++) {
if (!LDR_EXPORT(*ls)) {
continue;
}
mp->nExports++;
}
| | | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
for (i = lhp->l_nsyms; i; i--, ls++) {
if (!LDR_EXPORT(*ls)) {
continue;
}
mp->nExports++;
}
mp->exports = (ExportPtr) calloc(mp->nExports, sizeof(*mp->exports));
if (mp->exports == NULL) {
free(ldbuf);
SysErr();
}
/*
* Fill in the export table. All entries are relative to the entry point
|
| ︙ | ︙ | |||
596 597 598 599 600 601 602 |
/*
* This is a factoring out of the error-handling code to make the rest of
* the function much simpler to read.
*/
error:
| | | | < < < < | | | < < | < < | | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
/*
* This is a factoring out of the error-handling code to make the rest of
* the function much simpler to read.
*/
error:
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, errMsg);
if (ldp != NULL) {
while (ldclose(ldp) == FAILURE) {
/* Empty body */
}
}
return -1;
}
/*
* Find the main modules entry point. This is used as export pointer for
* loadbind() to be able to resolve references to the main part.
*/
static void *
findMain(void)
{
struct ld_info *lp;
char *buf;
int size = 4*1024;
int i;
void *ret;
|
| ︙ | ︙ | |||
660 661 662 663 664 665 666 |
lp = (struct ld_info *) buf;
ret = lp->ldinfo_dataorg;
free(buf);
return ret;
error:
| | | | | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
lp = (struct ld_info *) buf;
ret = lp->ldinfo_dataorg;
free(buf);
return ret;
error:
errvalid++;
strcpy(errbuf, "findMain: ");
strcat(errbuf, strerror(errno));
return NULL;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to unix/tclLoadDyld.c.
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
*/
MODULE_SCOPE int
TclpDlopen(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Obj *pathPtr, /* Name of the file containing the desired
* code (UTF-8). */
| | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
*/
MODULE_SCOPE int
TclpDlopen(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Obj *pathPtr, /* Name of the file containing the desired
* code (UTF-8). */
Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded
* file which will be passed back to
* (*unloadProcPtr)() to unload the file. */
Tcl_FSUnloadFileProc **unloadProcPtr,
/* Filled with address of Tcl_FSUnloadFileProc
* function which should be used for this
* file. */
int flags)
|
| ︙ | ︙ | |||
341 342 343 344 345 346 347 | * *---------------------------------------------------------------------- */ #ifdef TCL_LOAD_FROM_MEMORY MODULE_SCOPE void * TclpLoadMemoryGetBuffer( | | | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
*
*----------------------------------------------------------------------
*/
#ifdef TCL_LOAD_FROM_MEMORY
MODULE_SCOPE void *
TclpLoadMemoryGetBuffer(
size_t size) /* Size of desired buffer. */
{
void *buffer = NULL;
/*
* We must allocate the buffer using vm_allocate, because
* NSCreateObjectFileImageFromMemory will dispose of it using
* vm_deallocate.
|
| ︙ | ︙ | |||
382 383 384 385 386 387 388 |
#ifdef TCL_LOAD_FROM_MEMORY
MODULE_SCOPE int
TclpLoadMemory(
void *buffer, /* Buffer containing the desired code
* (allocated with TclpLoadMemoryGetBuffer). */
size_t size, /* Allocation size of buffer. */
| | | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 |
#ifdef TCL_LOAD_FROM_MEMORY
MODULE_SCOPE int
TclpLoadMemory(
void *buffer, /* Buffer containing the desired code
* (allocated with TclpLoadMemoryGetBuffer). */
size_t size, /* Allocation size of buffer. */
Tcl_Size codeSize, /* Size of code data read into buffer or -1 if
* an error occurred and the buffer should
* just be freed. */
const char *path,
Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded
* file which will be passed back to
* (*unloadProcPtr)() to unload the file. */
Tcl_FSUnloadFileProc **unloadProcPtr,
/* Filled with address of Tcl_FSUnloadFileProc
* function which should be used for this
* file. */
int flags)
|
| ︙ | ︙ | |||
420 421 422 423 424 425 426 | # define mh_magic MH_MAGIC # define arch_abi 0 #else const struct mach_header_64 *mh = NULL; # define mh_size sizeof(struct mach_header_64) # define mh_magic MH_MAGIC_64 # define arch_abi CPU_ARCH_ABI64 | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
# define mh_magic MH_MAGIC
# define arch_abi 0
#else
const struct mach_header_64 *mh = NULL;
# define mh_size sizeof(struct mach_header_64)
# define mh_magic MH_MAGIC_64
# define arch_abi CPU_ARCH_ABI64
#endif /* __LP64__ */
if ((size_t)codeSize >= sizeof(struct fat_header)
&& fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) {
uint32_t fh_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
/*
* Fat binary, try to find mach_header for our architecture
|
| ︙ | ︙ | |||
462 463 464 465 466 467 468 | * Thin binary */ mh = (const struct mach_header_64 *)buffer; ms = codeSize; } if (ms && !(ms >= mh_size && mh->magic == mh_magic && | | | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
* Thin binary
*/
mh = (const struct mach_header_64 *)buffer;
ms = codeSize;
}
if (ms && !(ms >= mh_size && mh->magic == mh_magic &&
mh->filetype == MH_BUNDLE)) {
err = NSObjectFileImageInappropriateFile;
}
if (err == NSObjectFileImageSuccess) {
err = NSCreateObjectFileImageFromMemory(buffer, codeSize,
&dyldObjFileImage);
}
}
|
| ︙ | ︙ |
Changes to unix/tclSelectNotfy.c.
| ︙ | ︙ | |||
164 165 166 167 168 169 170 | static int notifierThreadRunning = 0; /* * The following static flag indicates that async handlers are pending. */ | | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | static int notifierThreadRunning = 0; /* * The following static flag indicates that async handlers are pending. */ static int asyncPending = 0; /* * The notifier thread signals the notifierCV when it has finished * initializing the triggerPipe and right before the notifier thread * terminates. This condition is used to deal with the signal mask, too. */ |
| ︙ | ︙ | |||
263 264 265 266 267 268 269 | extern unsigned char DestroyWindow(void *); extern int DispatchMessageW(const MSG *); extern unsigned char GetMessageW(MSG *, void *, int, int); extern void MsgWaitForMultipleObjects(unsigned int, void *, unsigned char, unsigned int, unsigned int); extern unsigned char PeekMessageW(MSG *, void *, int, int, int); extern unsigned char PostMessageW(void *, unsigned int, void *, | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | extern unsigned char DestroyWindow(void *); extern int DispatchMessageW(const MSG *); extern unsigned char GetMessageW(MSG *, void *, int, int); extern void MsgWaitForMultipleObjects(unsigned int, void *, unsigned char, unsigned int, unsigned int); extern unsigned char PeekMessageW(MSG *, void *, int, int, int); extern unsigned char PostMessageW(void *, unsigned int, void *, void *); extern void PostQuitMessage(int); extern void * RegisterClassW(const WNDCLASSW *); extern unsigned char ResetEvent(void *); extern unsigned char TranslateMessage(const MSG *); /* * Threaded-cygwin specific constants and functions in this file: |
| ︙ | ︙ | |||
425 426 427 428 429 430 431 |
}
notifierThreadRunning = 0;
/*
* If async marks are outstanding, perform actions now.
*/
if (asyncPending) {
| | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
}
notifierThreadRunning = 0;
/*
* If async marks are outstanding, perform actions now.
*/
if (asyncPending) {
asyncPending = 0;
TclAsyncMarkFromNotifier();
}
}
}
/*
* Clean up any synchronization objects in the thread local storage.
|
| ︙ | ︙ | |||
635 636 637 638 639 640 641 | * Queues file events that are detected by the select. * *---------------------------------------------------------------------- */ int TclpWaitForEvent( | | > | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 |
* Queues file events that are detected by the select.
*
*----------------------------------------------------------------------
*/
int
TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
FileHandler *filePtr;
int mask;
Tcl_Time vTime;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#if TCL_THREADS
int waitForFiles;
# ifdef __CYGWIN__
MSG msg;
# endif /* __CYGWIN__ */
#else /* !TCL_THREADS */
|
| ︙ | ︙ | |||
661 662 663 664 665 666 667 |
#endif /* TCL_THREADS */
/*
* Set up the timeout structure. Note that if there are no events to check
* for, we return with a negative result rather than blocking forever.
*/
| | > > > > > > > > > > | | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
#endif /* TCL_THREADS */
/*
* Set up the timeout structure. Note that if there are no events to check
* for, we return with a negative result rather than blocking forever.
*/
if (timePtr != NULL) {
/*
* TIP #233 (Virtualized Time). Is virtual time in effect? And do we
* actually have something to scale? If yes to both then we call the
* handler to do this scaling.
*/
if (timePtr->sec != 0 || timePtr->usec != 0) {
vTime = *timePtr;
TclScaleTime(&vTime);
timePtr = &vTime;
}
#if !TCL_THREADS
timeout.tv_sec = timePtr->sec;
timeout.tv_usec = timePtr->usec;
timeoutPtr = &timeout;
} else if (tsdPtr->numFdBits == 0) {
/*
* If there are no threads, no timeout, and no fds registered, then
* there are no events possible and we must avoid deadlock. Note that
* this is not entirely correct because there might be a signal that
* could interrupt the select call, but we don't handle that case if
|
| ︙ | ︙ | |||
693 694 695 696 697 698 699 |
* timeout.
*/
StartNotifierThread("Tcl_WaitForEvent");
pthread_mutex_lock(¬ifierMutex);
| | | | | | 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
* timeout.
*/
StartNotifierThread("Tcl_WaitForEvent");
pthread_mutex_lock(¬ifierMutex);
if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0
#if defined(__APPLE__) && defined(__LP64__)
/*
* On 64-bit Darwin, pthread_cond_timedwait() appears to have a
* bug that causes it to wait forever when passed an absolute time
* which has already been exceeded by the system time; as a
* workaround, when given a very brief timeout, just do a poll.
* [Bug 1457797]
*/
|| timePtr->usec < 10
#endif /* __APPLE__ && __LP64__ */
)) {
/*
* Cannot emulate a polling select with a polling condition variable.
* Instead, pretend to wait for files and tell the notifier thread
* what we are doing. The notifier thread makes sure it goes through
* select with its select mask in the same state as ours currently is.
* We block until that happens.
*/
waitForFiles = 1;
tsdPtr->pollState = POLL_WANT;
timePtr = NULL;
} else {
waitForFiles = (tsdPtr->numFdBits > 0);
tsdPtr->pollState = 0;
}
if (waitForFiles) {
/*
|
| ︙ | ︙ | |||
751 752 753 754 755 756 757 |
FD_ZERO(&tsdPtr->readyMasks.exception);
if (!tsdPtr->eventReady) {
#ifdef __CYGWIN__
if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
long long timeout;
| | | | | | | > | | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
FD_ZERO(&tsdPtr->readyMasks.exception);
if (!tsdPtr->eventReady) {
#ifdef __CYGWIN__
if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
long long timeout;
if (timePtr) {
timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
if (timeout > UINT_MAX) {
timeout = UINT_MAX;
}
} else {
timeout = UINT_MAX;
}
pthread_mutex_unlock(¬ifierMutex);
MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, (unsigned int)timeout, 1279);
pthread_mutex_lock(¬ifierMutex);
}
#else /* !__CYGWIN__ */
if (timePtr != NULL) {
Tcl_Time now;
struct timespec ptime;
Tcl_GetTime(&now);
ptime.tv_sec = timePtr->sec + now.sec +
(timePtr->usec + now.usec) / 1000000;
ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
pthread_cond_timedwait(&tsdPtr->waitCV, ¬ifierMutex, &ptime);
} else {
pthread_cond_wait(&tsdPtr->waitCV, ¬ifierMutex);
}
#endif /* __CYGWIN__ */
}
|
| ︙ | ︙ | |||
900 901 902 903 904 905 906 | * Side effetcs: * The trigger pipe is written when called from the notifier * thread. * *---------------------------------------------------------------------- */ | < > | | | | | | | | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 |
* Side effetcs:
* The trigger pipe is written when called from the notifier
* thread.
*
*----------------------------------------------------------------------
*/
int
TclAsyncNotifier(
int sigNumber, /* Signal number. */
TCL_UNUSED(Tcl_ThreadId), /* Target thread. */
TCL_UNUSED(void *), /* Notifier data. */
int *flagPtr, /* Flag to mark. */
int value) /* Value of mark. */
{
#if TCL_THREADS
/*
* WARNING:
* This code most likely runs in a signal handler. Thus,
* only few async-signal-safe system calls are allowed,
* e.g. pthread_self(), sem_post(), write().
*/
if (pthread_equal(pthread_self(), (pthread_t) notifierThread)) {
if (notifierThreadRunning) {
*flagPtr = value;
if (!asyncPending) {
asyncPending = 1;
if (write(triggerPipe, "S", 1) != 1) {
asyncPending = 0;
return 0;
};
}
return 1;
}
return 0;
}
/*
* Re-send the signal to the notifier thread.
*/
pthread_kill((pthread_t) notifierThread, sigNumber);
#else
(void)sigNumber;
(void)flagPtr;
(void)value;
#endif
return 0;
}
/*
*----------------------------------------------------------------------
*
* NotifierThreadProc --
*
|
| ︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 |
if (ret == -1) {
/*
* In case a signal was caught during select(),
* perform work on async handlers now.
*/
if (errno == EINTR && asyncPending) {
| | | 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 |
if (ret == -1) {
/*
* In case a signal was caught during select(),
* perform work on async handlers now.
*/
if (errno == EINTR && asyncPending) {
asyncPending = 0;
TclAsyncMarkFromNotifier();
}
/*
* Try again immediately on select() error.
*/
continue;
|
| ︙ | ︙ | |||
1177 1178 1179 1180 1181 1182 1183 |
*/
break;
}
} while (1);
if (asyncPending) {
| | | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 |
*/
break;
}
} while (1);
if (asyncPending) {
asyncPending = 0;
TclAsyncMarkFromNotifier();
}
if ((i == 0) || (buf[0] == 'q')) {
break;
}
}
|
| ︙ | ︙ |
Changes to unix/tclUnixChan.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* Internal definitions for Tcl. */ #include "tclFileSystem.h" #include "tclIO.h" /* To get Channel type declaration. */ #if defined(HAVE_TERMIOS_H) # include <termios.h> # ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> # endif /* HAVE_SYS_IOCTL_H */ # ifdef HAVE_SYS_MODEM_H # include <sys/modem.h> # endif /* HAVE_SYS_MODEM_H */ | > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* Internal definitions for Tcl. */ #include "tclFileSystem.h" #include "tclIO.h" /* To get Channel type declaration. */ #undef SUPPORTS_TTY #if defined(HAVE_TERMIOS_H) # define SUPPORTS_TTY 1 # include <termios.h> # ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> # endif /* HAVE_SYS_IOCTL_H */ # ifdef HAVE_SYS_MODEM_H # include <sys/modem.h> # endif /* HAVE_SYS_MODEM_H */ |
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
int validMask; /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION: indicates
* which operations are valid on the file. */
} FileState;
typedef struct {
FileState fileState;
| | | | | | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
int validMask; /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION: indicates
* which operations are valid on the file. */
} FileState;
typedef struct {
FileState fileState;
#ifdef SUPPORTS_TTY
int closeMode; /* One of CLOSE_DEFAULT, CLOSE_DRAIN or
* CLOSE_DISCARD. */
int doReset; /* Whether we should do a terminal reset on
* close. */
struct termios initState; /* The state of the terminal when it was
* opened. */
#endif /* SUPPORTS_TTY */
} TtyState;
#ifdef SUPPORTS_TTY
/*
* The following structure is used to set or get the serial port attributes in
* a platform-independent manner.
*/
typedef struct {
int baud;
int parity;
int data;
int stop;
} TtyAttrs;
#endif /* SUPPORTS_TTY */
#define UNSUPPORTED_OPTION(detail) \
if (interp) { \
Tcl_SetObjResult(interp, Tcl_ObjPrintf( \
"%s not supported for this platform", (detail))); \
Tcl_SetErrorCode(interp, "TCL", "UNSUPPORTED", (char *)NULL); \
}
|
| ︙ | ︙ | |||
131 132 133 134 135 136 137 | static int FileOutputProc(void *instanceData, const char *buf, int toWrite, int *errorCode); static int FileTruncateProc(void *instanceData, long long length); static long long FileWideSeekProc(void *instanceData, long long offset, int mode, int *errorCode); static void FileWatchProc(void *instanceData, int mask); | | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
static int FileOutputProc(void *instanceData,
const char *buf, int toWrite, int *errorCode);
static int FileTruncateProc(void *instanceData,
long long length);
static long long FileWideSeekProc(void *instanceData,
long long offset, int mode, int *errorCode);
static void FileWatchProc(void *instanceData, int mask);
#ifdef SUPPORTS_TTY
static int TtyCloseProc(void *instanceData,
Tcl_Interp *interp, int flags);
static void TtyGetAttributes(int fd, TtyAttrs *ttyPtr);
static int TtyGetOptionProc(void *instanceData,
Tcl_Interp *interp, const char *optionName,
Tcl_DString *dsPtr);
static int TtyGetBaud(speed_t speed);
static speed_t TtyGetSpeed(int baud);
static void TtyInit(int fd);
static void TtyModemStatusStr(int status, Tcl_DString *dsPtr);
static int TtyParseMode(Tcl_Interp *interp, const char *mode,
TtyAttrs *ttyPtr);
static void TtySetAttributes(int fd, TtyAttrs *ttyPtr);
static int TtySetOptionProc(void *instanceData,
Tcl_Interp *interp, const char *optionName,
const char *value);
#endif /* SUPPORTS_TTY */
/*
* This structure describes the channel type structure for file based IO:
*/
static const Tcl_ChannelType fileChannelType = {
"file", /* Type name. */
|
| ︙ | ︙ | |||
174 175 176 177 178 179 180 |
NULL, /* Flush proc. */
NULL, /* Bubbled event handler proc. */
FileWideSeekProc,
NULL, /* Thread action proc. */
FileTruncateProc
};
| | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
NULL, /* Flush proc. */
NULL, /* Bubbled event handler proc. */
FileWideSeekProc,
NULL, /* Thread action proc. */
FileTruncateProc
};
#ifdef SUPPORTS_TTY
/*
* This structure describes the channel type structure for serial IO.
* Note that this type is a subclass of the "file" type.
*/
static const Tcl_ChannelType ttyChannelType = {
"tty",
|
| ︙ | ︙ | |||
199 200 201 202 203 204 205 |
FileBlockModeProc,
NULL, /* Flush proc. */
NULL, /* Bubbled event handler proc. */
NULL, /* Seek proc. */
NULL, /* Thread action proc. */
NULL /* Truncate proc. */
};
| | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
FileBlockModeProc,
NULL, /* Flush proc. */
NULL, /* Bubbled event handler proc. */
NULL, /* Seek proc. */
NULL, /* Thread action proc. */
NULL /* Truncate proc. */
};
#endif /* SUPPORTS_TTY */
/*
*----------------------------------------------------------------------
*
* FileBlockModeProc --
*
* Helper function to set blocking and nonblocking modes on a file based
|
| ︙ | ︙ | |||
260 261 262 263 264 265 266 |
void *instanceData, /* File state. */
char *buf, /* Where to store data read. */
int toRead, /* How much space is available in the
* buffer? */
int *errorCodePtr) /* Where to store error code. */
{
FileState *fsPtr = (FileState *)instanceData;
| | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
void *instanceData, /* File state. */
char *buf, /* Where to store data read. */
int toRead, /* How much space is available in the
* buffer? */
int *errorCodePtr) /* Where to store error code. */
{
FileState *fsPtr = (FileState *)instanceData;
ssize_t bytesRead; /* How many bytes were actually read from the
* input device? */
*errorCodePtr = 0;
/*
* Assume there is always enough input available. This will block
* appropriately, and read will unblock as soon as a short read is
|
| ︙ | ︙ | |||
377 378 379 380 381 382 383 |
errorCode = errno;
}
}
Tcl_Free(fsPtr);
return errorCode;
}
| | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
errorCode = errno;
}
}
Tcl_Free(fsPtr);
return errorCode;
}
#ifdef SUPPORTS_TTY
static int
TtyCloseProc(
void *instanceData,
Tcl_Interp *interp,
int flags)
{
TtyState *ttyPtr = (TtyState*)instanceData;
|
| ︙ | ︙ | |||
419 420 421 422 423 424 425 |
/*
* Delegate to close for files.
*/
return FileCloseProc(instanceData, interp, flags);
}
| | | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
/*
* Delegate to close for files.
*/
return FileCloseProc(instanceData, interp, flags);
}
#endif /* SUPPORTS_TTY */
/*
*----------------------------------------------------------------------
*
* FileWideSeekProc --
*
* This function is called by the generic IO level to move the access
|
| ︙ | ︙ | |||
461 462 463 464 465 466 467 |
*errorCodePtr = (newLoc == -1) ? errno : 0;
return newLoc;
}
/*
*----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 |
*errorCodePtr = (newLoc == -1) ? errno : 0;
return newLoc;
}
/*
*----------------------------------------------------------------------
*
* FileWatchProc --
*
* Initialize the notifier to watch the fd from this channel.
*
* Results:
* None.
*
* Side effects:
* Sets up the notifier so that a future event on the channel will
* be seen by Tcl.
*
*----------------------------------------------------------------------
*/
/*
* Bug ad5a57f2f271: Tcl_NotifyChannel is not a Tcl_FileProc,
* so do not pass it to directly to Tcl_CreateFileHandler.
* Instead, pass a wrapper which is a Tcl_FileProc.
*/
static void
FileWatchNotifyChannelWrapper(
void *clientData,
int mask)
{
Tcl_Channel channel = (Tcl_Channel)clientData;
Tcl_NotifyChannel(channel, mask);
}
static void
FileWatchProc(
void *instanceData, /* The file state. */
int mask) /* Events of interest; an OR-ed combination of
* TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
|
| ︙ | ︙ | |||
657 658 659 660 661 662 663 664 |
FileGetOptionProc(
void *instanceData,
Tcl_Interp *interp,
const char *optionName,
Tcl_DString *dsPtr)
{
FileState *fsPtr = (FileState *)instanceData;
size_t len;
| > < | | 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
FileGetOptionProc(
void *instanceData,
Tcl_Interp *interp,
const char *optionName,
Tcl_DString *dsPtr)
{
FileState *fsPtr = (FileState *)instanceData;
int valid = 0; /* Flag if valid option parsed. */
size_t len;
if (optionName == NULL) {
len = 0;
valid = 1;
} else {
len = strlen(optionName);
}
/*
* Get option -stat
* Option is readonly and returned by [fconfigure chan -stat] but not
|
| ︙ | ︙ | |||
700 701 702 703 704 705 706 |
Tcl_DecrRefCount(dictObj);
return TCL_OK;
}
if (valid) {
return TCL_OK;
}
| | > | | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 |
Tcl_DecrRefCount(dictObj);
return TCL_OK;
}
if (valid) {
return TCL_OK;
}
return Tcl_BadChannelOption(interp, optionName,
"stat");
}
#ifdef SUPPORTS_TTY
/*
*----------------------------------------------------------------------
*
* TtyModemStatusStr --
*
* Converts a RS232 modem status list of readable flags
*
|
| ︙ | ︙ | |||
954 955 956 957 958 959 960 |
#endif /* TIOCSBRK & TIOCCBRK */
} else {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad signal \"%s\" for -ttycontrol: must be"
" DTR, RTS or BREAK", argv[i]));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE",
| | | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 |
#endif /* TIOCSBRK & TIOCCBRK */
} else {
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad signal \"%s\" for -ttycontrol: must be"
" DTR, RTS or BREAK", argv[i]));
Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE",
"VALUE", (char *)NULL);
}
Tcl_Free(argv);
return TCL_ERROR;
}
} /* -ttycontrol options loop */
ioctl(fsPtr->fileState.fd, TIOCMSET, &control);
|
| ︙ | ︙ | |||
1105 1106 1107 1108 1109 1110 1111 |
Tcl_Interp *interp, /* For error reporting - can be NULL. */
const char *optionName, /* Option to get. */
Tcl_DString *dsPtr) /* Where to store value(s). */
{
TtyState *fsPtr = (TtyState *)instanceData;
size_t len;
char buf[3*TCL_INTEGER_SPACE + 16];
| | | 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 |
Tcl_Interp *interp, /* For error reporting - can be NULL. */
const char *optionName, /* Option to get. */
Tcl_DString *dsPtr) /* Where to store value(s). */
{
TtyState *fsPtr = (TtyState *)instanceData;
size_t len;
char buf[3*TCL_INTEGER_SPACE + 16];
int valid = 0; /* Flag if valid option parsed. */
struct termios iostate;
if (optionName == NULL) {
len = 0;
} else {
len = strlen(optionName);
}
|
| ︙ | ︙ | |||
1146 1147 1148 1149 1150 1151 1152 |
* represents what almost all scripts really want to know.
*/
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-inputmode");
}
if (len==0 || (len>1 && strncmp(optionName, "-inputmode", len)==0)) {
| | | 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 |
* represents what almost all scripts really want to know.
*/
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-inputmode");
}
if (len==0 || (len>1 && strncmp(optionName, "-inputmode", len)==0)) {
valid = 1;
if (tcgetattr(fsPtr->fileState.fd, &iostate) < 0) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't read serial terminal control state: %s",
Tcl_PosixError(interp)));
}
return TCL_ERROR;
|
| ︙ | ︙ | |||
1176 1177 1178 1179 1180 1181 1182 |
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-mode");
}
if (len==0 || (len>2 && strncmp(optionName, "-mode", len)==0)) {
TtyAttrs tty;
| | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 |
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-mode");
}
if (len==0 || (len>2 && strncmp(optionName, "-mode", len)==0)) {
TtyAttrs tty;
valid = 1;
TtyGetAttributes(fsPtr->fileState.fd, &tty);
snprintf(buf, sizeof(buf), "%d,%c,%d,%d", tty.baud, tty.parity, tty.data, tty.stop);
Tcl_DStringAppendElement(dsPtr, buf);
}
/*
* Get option -xchar
*/
if (len == 0) {
Tcl_DStringAppendElement(dsPtr, "-xchar");
Tcl_DStringStartSublist(dsPtr);
}
if (len==0 || (len>1 && strncmp(optionName, "-xchar", len)==0)) {
Tcl_DString ds;
valid = 1;
tcgetattr(fsPtr->fileState.fd, &iostate);
Tcl_DStringInit(&ds);
Tcl_ExternalToUtfDStringEx(NULL, NULL, (char *) &iostate.c_cc[VSTART],
1, TCL_ENCODING_PROFILE_TCL8, &ds, NULL);
Tcl_DStringAppendElement(dsPtr, Tcl_DStringValue(&ds));
TclDStringClear(&ds);
|
| ︙ | ︙ | |||
1220 1221 1222 1223 1224 1225 1226 |
* Option is readonly and returned by [fconfigure chan -queue] but not
* returned by unnamed [fconfigure chan].
*/
if ((len > 1) && (strncmp(optionName, "-queue", len) == 0)) {
int inQueue=0, outQueue=0, inBuffered, outBuffered;
| | | 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 |
* Option is readonly and returned by [fconfigure chan -queue] but not
* returned by unnamed [fconfigure chan].
*/
if ((len > 1) && (strncmp(optionName, "-queue", len) == 0)) {
int inQueue=0, outQueue=0, inBuffered, outBuffered;
valid = 1;
GETREADQUEUE(fsPtr->fileState.fd, inQueue);
GETWRITEQUEUE(fsPtr->fileState.fd, outQueue);
inBuffered = Tcl_InputBuffered(fsPtr->fileState.channel);
outBuffered = Tcl_OutputBuffered(fsPtr->fileState.channel);
snprintf(buf, sizeof(buf), "%d", inBuffered+inQueue);
Tcl_DStringAppendElement(dsPtr, buf);
|
| ︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 |
* Option is readonly and returned by [fconfigure chan -ttystatus] but not
* returned by unnamed [fconfigure chan].
*/
if ((len > 4) && (strncmp(optionName, "-ttystatus", len) == 0)) {
int status;
| | | | 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 |
* Option is readonly and returned by [fconfigure chan -ttystatus] but not
* returned by unnamed [fconfigure chan].
*/
if ((len > 4) && (strncmp(optionName, "-ttystatus", len) == 0)) {
int status;
valid = 1;
ioctl(fsPtr->fileState.fd, TIOCMGET, &status);
TtyModemStatusStr(status, dsPtr);
}
#endif /* TIOCMGET */
#if defined(TIOCGWINSZ)
/*
* Get option -winsize
* Option is readonly and returned by [fconfigure chan -winsize] but not
* returned by [fconfigure chan] without explicit option name.
*/
if ((len > 1) && (strncmp(optionName, "-winsize", len) == 0)) {
struct winsize ws;
valid = 1;
if (ioctl(fsPtr->fileState.fd, TIOCGWINSZ, &ws) < 0) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't read terminal size: %s",
Tcl_PosixError(interp)));
}
return TCL_ERROR;
|
| ︙ | ︙ | |||
1714 1715 1716 1717 1718 1719 1720 |
iostate.c_cflag |= CREAD;
iostate.c_cc[VMIN] = 1;
iostate.c_cc[VTIME] = 0;
tcsetattr(fd, TCSADRAIN, &iostate);
}
}
| | | 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 |
iostate.c_cflag |= CREAD;
iostate.c_cc[VMIN] = 1;
iostate.c_cc[VTIME] = 0;
tcsetattr(fd, TCSADRAIN, &iostate);
}
}
#endif /* SUPPORTS_TTY */
/*
*----------------------------------------------------------------------
*
* TclpOpenFileChannel --
*
* Open an file based channel on Unix systems.
|
| ︙ | ︙ | |||
1815 1816 1817 1818 1819 1820 1821 |
/*
* Set close-on-exec flag on the fd so that child processes will not
* inherit this fd.
*/
fcntl(fd, F_SETFD, FD_CLOEXEC);
| | | | | | | 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 |
/*
* Set close-on-exec flag on the fd so that child processes will not
* inherit this fd.
*/
fcntl(fd, F_SETFD, FD_CLOEXEC);
#ifdef SUPPORTS_TTY
if (strcmp(native, "/dev/tty") != 0 && isatty(fd)) {
/*
* Initialize the serial port to a set of sane parameters. Especially
* important if the remote device is set to echo and the serial port
* driver was also set to echo -- as soon as a char were sent to the
* serial port, the remote device would echo it, then the serial
* driver would echo it back to the device, etc.
*
* Note that we do not do this if we're dealing with /dev/tty itself,
* as that tends to cause Bad Things To Happen when you're working
* interactively. Strictly a better check would be to see if the FD
* being set up is a device and has the same major/minor as the
* initial std FDs (beware reopening!) but that's nearly as messy.
*/
translation = "auto crlf";
channelTypePtr = &ttyChannelType;
TtyInit(fd);
snprintf(channelName, sizeof(channelName), "serial%d", fd);
} else
#endif /* SUPPORTS_TTY */
{
translation = NULL;
channelTypePtr = &fileChannelType;
snprintf(channelName, sizeof(channelName), "file%d", fd);
}
fsPtr = (TtyState *)Tcl_Alloc(sizeof(TtyState));
fsPtr->fileState.validMask = channelPermissions | TCL_EXCEPTION;
fsPtr->fileState.fd = fd;
#ifdef SUPPORTS_TTY
if (channelTypePtr == &ttyChannelType) {
fsPtr->closeMode = CLOSE_DEFAULT;
fsPtr->doReset = 0;
tcgetattr(fsPtr->fileState.fd, &fsPtr->initState);
}
#endif /* SUPPORTS_TTY */
fsPtr->fileState.channel = Tcl_CreateChannel(channelTypePtr, channelName,
fsPtr, channelPermissions);
if (translation != NULL) {
/*
* Gotcha. Most modems need a "\r" at the end of the command sequence.
|
| ︙ | ︙ | |||
1908 1909 1910 1911 1912 1913 1914 |
const Tcl_ChannelType *channelTypePtr;
Tcl_StatBuf buf;
if (mode == 0) {
return NULL;
}
| | | | 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 |
const Tcl_ChannelType *channelTypePtr;
Tcl_StatBuf buf;
if (mode == 0) {
return NULL;
}
#ifdef SUPPORTS_TTY
if (isatty(fd)) {
channelTypePtr = &ttyChannelType;
snprintf(channelName, sizeof(channelName), "serial%d", fd);
} else
#endif /* SUPPORTS_TTY */
if (TclOSfstat(fd, &buf) == 0 && S_ISSOCK(buf.st_mode)) {
struct sockaddr sockaddr;
socklen_t sockaddrLen = sizeof(sockaddr);
sockaddr.sa_family = AF_UNSPEC;
if ((getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0)
&& (sockaddrLen > 0)
|
| ︙ | ︙ | |||
1937 1938 1939 1940 1941 1942 1943 |
}
fsPtr = (TtyState *)Tcl_Alloc(sizeof(TtyState));
fsPtr->fileState.fd = fd;
fsPtr->fileState.validMask = mode | TCL_EXCEPTION;
fsPtr->fileState.channel = Tcl_CreateChannel(channelTypePtr, channelName,
fsPtr, mode);
| | | | | 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 |
}
fsPtr = (TtyState *)Tcl_Alloc(sizeof(TtyState));
fsPtr->fileState.fd = fd;
fsPtr->fileState.validMask = mode | TCL_EXCEPTION;
fsPtr->fileState.channel = Tcl_CreateChannel(channelTypePtr, channelName,
fsPtr, mode);
#ifdef SUPPORTS_TTY
if (channelTypePtr == &ttyChannelType) {
fsPtr->closeMode = CLOSE_DEFAULT;
fsPtr->doReset = 0;
tcgetattr(fsPtr->fileState.fd, &fsPtr->initState);
}
#endif /* SUPPORTS_TTY */
return fsPtr->fileState.channel;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
2099 2100 2101 2102 2103 2104 2105 |
* We allow creating a FILE * out of file based, pipe based and socket
* based channels. We currently do not allow any other channel types,
* because it is likely that stdio will not know what to do with them.
*/
chanTypePtr = Tcl_GetChannelType(chan);
if ((chanTypePtr == &fileChannelType)
| | | | 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 |
* We allow creating a FILE * out of file based, pipe based and socket
* based channels. We currently do not allow any other channel types,
* because it is likely that stdio will not know what to do with them.
*/
chanTypePtr = Tcl_GetChannelType(chan);
if ((chanTypePtr == &fileChannelType)
#ifdef SUPPORTS_TTY
|| (chanTypePtr == &ttyChannelType)
#endif /* SUPPORTS_TTY */
|| (strcmp(chanTypePtr->typeName, "tcp") == 0)
|| (strcmp(chanTypePtr->typeName, "pipe") == 0)) {
if (Tcl_GetChannelHandle(chan,
(forWriting ? TCL_WRITABLE : TCL_READABLE), &data) == TCL_OK) {
fd = (int)PTR2INT(data);
/*
|
| ︙ | ︙ |
Changes to unix/tclUnixCompat.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | #include <errno.h> #include <string.h> /* * See also: SC_BLOCKING_STYLE in unix/tcl.m4 */ | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <errno.h> #include <string.h> /* * See also: SC_BLOCKING_STYLE in unix/tcl.m4 */ #ifdef USE_FIONBIO # ifdef HAVE_SYS_FILIO_H # include <sys/filio.h> /* For FIONBIO. */ # endif # ifdef HAVE_SYS_IOCTL_H # include <sys/ioctl.h> # endif #endif /* USE_FIONBIO */ |
| ︙ | ︙ | |||
66 67 68 69 70 71 72 |
char gbuf[2048];
#endif
#if !defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)
struct hostent hent;
char hbuf[2048];
#endif
| | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
char gbuf[2048];
#endif
#if !defined(HAVE_MTSAFE_GETHOSTBYNAME) || !defined(HAVE_MTSAFE_GETHOSTBYADDR)
struct hostent hent;
char hbuf[2048];
#endif
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
#if ((!defined(HAVE_GETHOSTBYNAME_R) || !defined(HAVE_GETHOSTBYADDR_R)) && \
(!defined(HAVE_MTSAFE_GETHOSTBYNAME) || \
!defined(HAVE_MTSAFE_GETHOSTBYADDR))) || \
!defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETPWUID_R) || \
!defined(HAVE_GETGRNAM_R) || !defined(HAVE_GETGRGID_R)
|
| ︙ | ︙ | |||
160 161 162 163 164 165 166 | } /* *--------------------------------------------------------------------------- * * TclpGetPwNam -- * | | | | | | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
}
/*
*---------------------------------------------------------------------------
*
* TclpGetPwNam --
*
* Thread-safe wrappers for getpwnam(). See "man getpwnam" for more
* details.
*
* Results:
* Pointer to struct passwd on success or NULL on error.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
struct passwd *
TclpGetPwNam(
const char *name)
|
| ︙ | ︙ | |||
240 241 242 243 244 245 246 | } /* *--------------------------------------------------------------------------- * * TclpGetPwUid -- * | | | | | | 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
}
/*
*---------------------------------------------------------------------------
*
* TclpGetPwUid --
*
* Thread-safe wrappers for getpwuid(). See "man getpwuid" for more
* details.
*
* Results:
* Pointer to struct passwd on success or NULL on error.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
struct passwd *
TclpGetPwUid(
uid_t uid)
|
| ︙ | ︙ | |||
343 344 345 346 347 348 349 | #endif /* NEED_PW_CLEANER */ /* *--------------------------------------------------------------------------- * * TclpGetGrNam -- * | | | | | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
#endif /* NEED_PW_CLEANER */
/*
*---------------------------------------------------------------------------
*
* TclpGetGrNam --
*
* Thread-safe wrappers for getgrnam(). See "man getgrnam" for more
* details.
*
* Results:
* Pointer to struct group on success or NULL on error.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
struct group *
TclpGetGrNam(
const char *name)
|
| ︙ | ︙ | |||
423 424 425 426 427 428 429 | } /* *--------------------------------------------------------------------------- * * TclpGetGrGid -- * | | | | | | 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
}
/*
*---------------------------------------------------------------------------
*
* TclpGetGrGid --
*
* Thread-safe wrappers for getgrgid(). See "man getgrgid" for more
* details.
*
* Results:
* Pointer to struct group on success or NULL on error.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
struct group *
TclpGetGrGid(
gid_t gid)
|
| ︙ | ︙ | |||
526 527 528 529 530 531 532 | #endif /* NEED_GR_CLEANER */ /* *--------------------------------------------------------------------------- * * TclpGetHostByName -- * | | | | | | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
#endif /* NEED_GR_CLEANER */
/*
*---------------------------------------------------------------------------
*
* TclpGetHostByName --
*
* Thread-safe wrappers for gethostbyname(). See "man gethostbyname" for
* more details.
*
* Results:
* Pointer to struct hostent on success or NULL on error.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
struct hostent *
TclpGetHostByName(
const char *name)
{
#if !TCL_THREADS || defined(HAVE_MTSAFE_GETHOSTBYNAME)
return gethostbyname(name);
#else
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#if defined(HAVE_GETHOSTBYNAME_R_5)
int local_errno;
return gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf,
sizeof(tsdPtr->hbuf), &local_errno);
#elif defined(HAVE_GETHOSTBYNAME_R_6)
struct hostent *hePtr = NULL;
int local_errno, result;
result = gethostbyname_r(name, &tsdPtr->hent, tsdPtr->hbuf,
sizeof(tsdPtr->hbuf), &hePtr, &local_errno);
|
| ︙ | ︙ | |||
594 595 596 597 598 599 600 | } /* *--------------------------------------------------------------------------- * * TclpGetHostByAddr -- * | | | | | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 |
}
/*
*---------------------------------------------------------------------------
*
* TclpGetHostByAddr --
*
* Thread-safe wrappers for gethostbyaddr(). See "man gethostbyaddr" for
* more details.
*
* Results:
* Pointer to struct hostent on success or NULL on error.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
struct hostent *
TclpGetHostByAddr(
const char *addr,
|
| ︙ | ︙ | |||
657 658 659 660 661 662 663 | } /* *--------------------------------------------------------------------------- * * CopyGrp -- * | | | | | | 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | } /* *--------------------------------------------------------------------------- * * CopyGrp -- * * Copies string fields of the group structure to the private buffer, * honouring the size of the buffer. * * Results: * 0 on success or -1 on error (errno = ERANGE). * * Side effects: * None. * *--------------------------------------------------------------------------- */ #ifdef NEED_COPYGRP #define NEED_COPYARRAY 1 #define NEED_COPYSTRING 1 |
| ︙ | ︙ | |||
730 731 732 733 734 735 736 | #endif /* NEED_COPYGRP */ /* *--------------------------------------------------------------------------- * * CopyHostent -- * | | | | | | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | #endif /* NEED_COPYGRP */ /* *--------------------------------------------------------------------------- * * CopyHostent -- * * Copies string fields of the hostent structure to the private buffer, * honouring the size of the buffer. * * Results: * Number of bytes copied on success or -1 on error (errno = ERANGE) * * Side effects: * None * *--------------------------------------------------------------------------- */ #ifdef NEED_COPYHOSTENT #define NEED_COPYSTRING 1 #define NEED_COPYARRAY 1 |
| ︙ | ︙ | |||
792 793 794 795 796 797 798 | #endif /* NEED_COPYHOSTENT */ /* *--------------------------------------------------------------------------- * * CopyPwd -- * | | | | | | | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 | #endif /* NEED_COPYHOSTENT */ /* *--------------------------------------------------------------------------- * * CopyPwd -- * * Copies string fields of the passwd structure to the private buffer, * honouring the size of the buffer. * * Results: * 0 on success or -1 on error (errno = ERANGE). * * Side effects: * We are not copying the gecos field as it may not be supported on all * platforms. * *--------------------------------------------------------------------------- */ #ifdef NEED_COPYPWD #define NEED_COPYSTRING 1 |
| ︙ | ︙ | |||
858 859 860 861 862 863 864 | #endif /* NEED_COPYPWD */ /* *--------------------------------------------------------------------------- * * CopyArray -- * | | | | | | | | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 |
#endif /* NEED_COPYPWD */
/*
*---------------------------------------------------------------------------
*
* CopyArray --
*
* Copies array of NULL-terminated or fixed-length strings to the private
* buffer, honouring the size of the buffer.
*
* Results:
* Number of bytes copied on success or -1 on error (errno = ERANGE)
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
#ifdef NEED_COPYARRAY
static size_t
CopyArray(
char **src, /* Array of elements to copy. */
int elsize, /* Size of each element, or -1 to indicate
* that they are C strings of dynamic
* length. */
char *buf, /* Buffer to copy into. */
size_t buflen) /* Size of buffer. */
{
size_t i, j, len = 0;
char *p, **newBuffer;
if (src == NULL) {
return 0;
}
for (i = 0; src[i] != NULL; i++) {
/*
* Empty loop to count how many.
*/
}
len = sizeof(char *) * (i + 1); /* Leave place for the array. */
if (len > buflen) {
return -1;
}
newBuffer = (char **)buf;
p = buf + len;
for (j = 0; j < i; j++) {
|
| ︙ | ︙ | |||
922 923 924 925 926 927 928 | #endif /* NEED_COPYARRAY */ /* *--------------------------------------------------------------------------- * * CopyString -- * | | | | | | > > > > > > > > | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 |
#endif /* NEED_COPYARRAY */
/*
*---------------------------------------------------------------------------
*
* CopyString --
*
* Copies a NULL-terminated string to the private buffer, honouring the
* size of the buffer
*
* Results:
* 0 success or -1 on error (errno = ERANGE)
*
* Side effects:
* None
*
*---------------------------------------------------------------------------
*/
#ifdef NEED_COPYSTRING
static size_t
CopyString(
const char *src, /* String to copy. */
char *buf, /* Buffer to copy into. */
size_t buflen) /* Size of buffer. */
{
size_t len = 0;
if (src != NULL) {
len = strlen(src) + 1;
if (len > buflen) {
return -1;
}
memcpy(buf, src, len);
}
return len;
}
#endif /* NEED_COPYSTRING */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
/*
*------------------------------------------------------------------------
*
* TclWinCPUID --
*
* Get CPU ID information on an Intel box under UNIX (either Linux or Cygwin)
*
|
| ︙ | ︙ | |||
1000 1001 1002 1003 1004 1005 1006 |
status = TCL_OK;
#else
(void)index;
(void)regsPtr;
#endif
return status;
}
| | | 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 |
status = TCL_OK;
#else
(void)index;
(void)regsPtr;
#endif
return status;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to unix/tclUnixEvent.c.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 | #include "tclInt.h" #ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is * in tclMacOSXNotify.c */ /* *---------------------------------------------------------------------- * | | | < | | < | < < | | > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
#include "tclInt.h"
#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
* in tclMacOSXNotify.c */
/*
*----------------------------------------------------------------------
*
* Tcl_Sleep --
*
* Delay execution for the specified number of milliseconds.
*
* Results:
* None.
*
* Side effects:
* Time passes.
*
*----------------------------------------------------------------------
*/
void
Tcl_Sleep(
int ms) /* Number of milliseconds to sleep. */
{
struct timeval delay;
Tcl_Time before, after, vdelay;
/*
* The only trick here is that select appears to return early under some
* conditions, so we have to check to make sure that the right amount of
* time really has elapsed. If it's too early, go back to sleep again.
*/
Tcl_GetTime(&before);
after = before;
after.sec += ms/1000;
after.usec += (ms%1000)*1000;
if (after.usec > 1000000) {
after.usec -= 1000000;
after.sec += 1;
}
while (1) {
/*
* TIP #233: Scale from virtual time to real-time for select.
*/
vdelay.sec = after.sec - before.sec;
vdelay.usec = after.usec - before.usec;
if (vdelay.usec < 0) {
vdelay.usec += 1000000;
vdelay.sec -= 1;
}
if ((vdelay.sec != 0) || (vdelay.usec != 0)) {
TclScaleTime(&vdelay);
}
delay.tv_sec = vdelay.sec;
delay.tv_usec = vdelay.usec;
/*
* Special note: must convert delay.tv_sec to int before comparing to
* zero, since delay.tv_usec is unsigned on some platforms.
*/
if ((((int) delay.tv_sec) < 0)
|| ((delay.tv_usec == 0) && (delay.tv_sec == 0))) {
break;
}
(void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
(SELECT_MASK *) 0, &delay);
Tcl_GetTime(&before);
}
}
#else
TCL_MAC_EMPTY_FILE(unix_tclUnixEvent_c)
#endif /* HAVE_COREFOUNDATION */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to unix/tclUnixFCmd.c.
| ︙ | ︙ | |||
45 46 47 48 49 50 51 | #ifndef NO_FSTATFS #include <sys/statfs.h> #endif #endif /* !HAVE_STRUCT_STAT_ST_BLKSIZE */ #ifdef HAVE_FTS #include <fts.h> #endif | < < < < < < < | | | | < | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #ifndef NO_FSTATFS #include <sys/statfs.h> #endif #endif /* !HAVE_STRUCT_STAT_ST_BLKSIZE */ #ifdef HAVE_FTS #include <fts.h> #endif /* * The following constants specify the type of callback when * TraverseUnixTree() calls the traverseProc() */ #define DOTREE_PRED 1 /* pre-order directory */ #define DOTREE_POSTD 2 /* post-order directory */ #define DOTREE_F 3 /* regular file */ /* * Fallback temporary file location the temporary file generation code. Can be * overridden at compile time for when it is known that temp files can't be * written to /tmp (hello, iOS!). */ |
| ︙ | ︙ | |||
117 118 119 120 121 122 123 | * IMPORTANT: The permissions attribute is assumed to be the third item (i.e. * to be indexed with '2' in arrays) in code in tclIOUtil.c and possibly * elsewhere in Tcl's core. */ #ifndef DJGPP | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
* IMPORTANT: The permissions attribute is assumed to be the third item (i.e.
* to be indexed with '2' in arrays) in code in tclIOUtil.c and possibly
* elsewhere in Tcl's core.
*/
#ifndef DJGPP
enum {
#if defined(__CYGWIN__)
UNIX_ARCHIVE_ATTRIBUTE,
#endif
UNIX_GROUP_ATTRIBUTE,
#if defined(__CYGWIN__)
UNIX_HIDDEN_ATTRIBUTE,
#endif
|
| ︙ | ︙ | |||
235 236 237 238 239 240 241 | * should not be used with purify because of bogus warnings, but just * memset'ing the resolved path will squelch those. This assumes we are * passing the standard MAXPATHLEN size resolved arg. */ static char * Realpath(const char *path, char *resolved); | | | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
* should not be used with purify because of bogus warnings, but just
* memset'ing the resolved path will squelch those. This assumes we are
* passing the standard MAXPATHLEN size resolved arg.
*/
static char * Realpath(const char *path, char *resolved);
char *
Realpath(
const char *path,
char *resolved)
{
memset(resolved, 0, MAXPATHLEN);
return realpath(path, resolved);
}
|
| ︙ | ︙ | |||
533 534 535 536 537 538 539 | #define BINMODE |O_BINARY #else #define BINMODE #endif /* DJGPP */ #define DEFAULT_COPY_BLOCK_SIZE 4096 | | < | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
#define BINMODE |O_BINARY
#else
#define BINMODE
#endif /* DJGPP */
#define DEFAULT_COPY_BLOCK_SIZE 4096
if ((srcFd = TclOSopen(src, O_RDONLY BINMODE, 0)) < 0) { /* INTL: Native */
return TCL_ERROR;
}
dstFd = TclOSopen(dst, O_CREAT|O_TRUNC|O_WRONLY BINMODE, /* INTL: Native */
statBufPtr->st_mode);
if (dstFd < 0) {
close(srcFd);
|
| ︙ | ︙ | |||
748 749 750 751 752 753 754 |
Tcl_DecrRefCount(transPtr);
}
if (ret != TCL_OK) {
*errorPtr = srcPathPtr;
} else {
transPtr = Tcl_FSGetTranslatedPath(NULL,destPathPtr);
ret = Tcl_UtfToExternalDStringEx(NULL, NULL,
| | | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 |
Tcl_DecrRefCount(transPtr);
}
if (ret != TCL_OK) {
*errorPtr = srcPathPtr;
} else {
transPtr = Tcl_FSGetTranslatedPath(NULL,destPathPtr);
ret = Tcl_UtfToExternalDStringEx(NULL, NULL,
(transPtr != NULL ? TclGetString(transPtr) : NULL),
-1, TCL_ENCODING_PROFILE_TCL8, &dstString, NULL);
if (transPtr != NULL) {
Tcl_DecrRefCount(transPtr);
}
if (ret != TCL_OK) {
*errorPtr = destPathPtr;
} else {
ret = TraverseUnixTree(TraversalCopy, &srcString, &dstString, &ds, 0);
|
| ︙ | ︙ | |||
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 |
TCL_UNUSED(Tcl_DString *),
TCL_UNUSED(const Tcl_StatBuf *),
int type, /* Reason for call - see TraverseUnixTree(). */
Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free DString
* filled with UTF-8 name of file causing
* error. */
{
switch (type) {
case DOTREE_F:
if (TclpDeleteFile(Tcl_DStringValue(srcPtr)) == 0) {
return TCL_OK;
}
break;
case DOTREE_PRED:
| > | 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 |
TCL_UNUSED(Tcl_DString *),
TCL_UNUSED(const Tcl_StatBuf *),
int type, /* Reason for call - see TraverseUnixTree(). */
Tcl_DString *errorPtr) /* If non-NULL, uninitialized or free DString
* filled with UTF-8 name of file causing
* error. */
{
switch (type) {
case DOTREE_F:
if (TclpDeleteFile(Tcl_DStringValue(srcPtr)) == 0) {
return TCL_OK;
}
break;
case DOTREE_PRED:
|
| ︙ | ︙ | |||
1270 1271 1272 1273 1274 1275 1276 | * *--------------------------------------------------------------------------- */ static int CopyFileAtts( #ifdef MAC_OSX_TCL | | | 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 |
*
*---------------------------------------------------------------------------
*/
static int
CopyFileAtts(
#ifdef MAC_OSX_TCL
const char *src, /* Path name of source file (native). */
#else
TCL_UNUSED(const char *) /*src*/,
#endif
const char *dst, /* Path name of target file (native). */
const Tcl_StatBuf *statBufPtr)
/* Stat info for source file */
{
|
| ︙ | ︙ | |||
1828 1829 1830 1831 1832 1833 1834 |
/*
* We now check for an "ugoa+-=rwxst" style permissions string
*/
for (n = 0 ; modeStringPtr[n] != '\0' ; n += i) {
oldMode = *modePtr;
who = op = what = op_found = who_found = 0;
| | | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 |
/*
* We now check for an "ugoa+-=rwxst" style permissions string
*/
for (n = 0 ; modeStringPtr[n] != '\0' ; n += i) {
oldMode = *modePtr;
who = op = what = op_found = who_found = 0;
for (i = 0 ; modeStringPtr[n + i] != '\0' ; i++ ) {
if (!who_found) {
/* who */
switch (modeStringPtr[n + i]) {
case 'u':
who |= 0x9C0;
continue;
case 'g':
|
| ︙ | ︙ | |||
1911 1912 1913 1914 1915 1916 1917 |
*modePtr = (oldMode & ~who) | (who & what);
continue;
}
}
return TCL_OK;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | < < < > | > < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | < < < > > > | > > > | > > > | > | < | < < | < < < | < | < < < < < < < | 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 |
*modePtr = (oldMode & ~who) | (who & what);
continue;
}
}
return TCL_OK;
}
/*
*---------------------------------------------------------------------------
*
* TclpObjNormalizePath --
*
* Replaces each component except that last one in a pathname that is a
* symbolic link with the fully resolved target of that link.
*
* Results:
* Stores the resulting path in pathPtr and returns the offset of the last
* byte processed to obtain the resulting path.
*
* Side effects:
*
*---------------------------------------------------------------------------
*/
int
TclpObjNormalizePath(
Tcl_Interp *interp,
Tcl_Obj *pathPtr, /* An unshared object containing the path to
* normalize. */
int nextCheckpoint) /* offset to start at in pathPtr. Must either
* be 0 or the offset of a directory separator
* at the end of a path part that is already
* normalized. I.e. this is not the index of
* the byte just after the separator. */
{
const char *currentPathEndPosition;
char cur;
Tcl_Size pathLen;
const char *path = TclGetStringFromObj(pathPtr, &pathLen);
Tcl_DString ds;
const char *nativePath;
#ifndef NO_REALPATH
char normPath[MAXPATHLEN];
#endif
currentPathEndPosition = path + nextCheckpoint;
if (*currentPathEndPosition == '/') {
currentPathEndPosition++;
}
#ifndef NO_REALPATH
if (nextCheckpoint == 0 && haveRealpath) {
/*
* Try to get the entire path in one go
*/
const char *lastDir = strrchr(currentPathEndPosition, '/');
if (lastDir != NULL) {
if (Tcl_UtfToExternalDStringEx(interp, NULL, path,
lastDir-path, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return -1;
}
nativePath = Tcl_DStringValue(&ds);
if (Realpath(nativePath, normPath) != NULL) {
if (*nativePath != '/' && *normPath == '/') {
/*
* realpath transformed a relative path into an
* absolute path. Fall back to the long way.
*/
/*
* To do: This logic seems to be out of date. This whole
* routine should be reviewed and cleaed up.
*/
} else {
nextCheckpoint = (int)(lastDir - path);
goto wholeStringOk;
}
}
Tcl_DStringFree(&ds);
}
}
/*
* Else do it the slow way.
*/
#endif
while (1) {
cur = *currentPathEndPosition;
if ((cur == '/') && (path != currentPathEndPosition)) {
/*
* Reached directory separator.
*/
int accessOk;
if (Tcl_UtfToExternalDStringEx(interp, NULL, path,
currentPathEndPosition - path, 0, &ds, NULL) != TCL_OK) {
Tcl_DStringFree(&ds);
return -1;
}
nativePath = Tcl_DStringValue(&ds);
accessOk = access(nativePath, F_OK);
Tcl_DStringFree(&ds);
if (accessOk != 0) {
/*
* File doesn't exist.
*/
break;
}
/*
* Assign the end of the current component to nextCheckpoint
*/
nextCheckpoint = (int)(currentPathEndPosition - path);
} else if (cur == 0) {
/*
* The end of the string.
*/
break;
}
currentPathEndPosition++;
}
/*
* Call 'realpath' to obtain a canonical path.
*/
#ifndef NO_REALPATH
if (haveRealpath) {
if (nextCheckpoint == 0) {
/*
* The path contains at most one component, e.g. '/foo' or '/',
* so there is nothing to resolve. Also, on some platforms
* 'Realpath' transforms an empty string into the normalized pwd,
* which is the wrong answer.
*/
return 0;
}
if (Tcl_UtfToExternalDStringEx(interp, NULL, path,nextCheckpoint, 0, &ds, NULL)) {
Tcl_DStringFree(&ds);
return -1;
}
nativePath = Tcl_DStringValue(&ds);
if (Realpath(nativePath, normPath) != NULL) {
Tcl_Size newNormLen;
wholeStringOk:
newNormLen = strlen(normPath);
if ((newNormLen == Tcl_DStringLength(&ds))
&& (strcmp(normPath, nativePath) == 0)) {
/*
* The original path is unchanged.
*/
Tcl_DStringFree(&ds);
/*
* Uncommenting this would mean that this native filesystem
* routine claims the path is normalized if the file exists,
* which would permit the caller to avoid iterating through
* other filesystems. Saving lots of calls is
* probably worth the extra access() time, but in the common
* case that no other filesystems are registered this is an
|
| ︙ | ︙ | |||
2274 2275 2276 2277 2278 2279 2280 | } /* * Free the original path and replace it with the normalized path. */ Tcl_DStringFree(&ds); | < | < < | < | | < < | > > | > > > > | > > > > > < | | < < < | > | | 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 |
}
/*
* Free the original path and replace it with the normalized path.
*/
Tcl_DStringFree(&ds);
Tcl_ExternalToUtfDStringEx(NULL, NULL, normPath, newNormLen, 0, &ds, NULL);
if (path[nextCheckpoint] != '\0') {
/*
* Append the remaining path components.
*/
Tcl_Size normLen = Tcl_DStringLength(&ds);
Tcl_DStringAppend(&ds, path + nextCheckpoint,
pathLen - nextCheckpoint);
/*
* characters up to and including the directory separator have
* been processed
*/
nextCheckpoint = (int)normLen + 1;
} else {
/*
* We recognise the whole string.
*/
nextCheckpoint = (int)Tcl_DStringLength(&ds);
}
Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&ds),
Tcl_DStringLength(&ds));
}
Tcl_DStringFree(&ds);
}
#endif /* !NO_REALPATH */
return nextCheckpoint;
}
|
| ︙ | ︙ | |||
2433 2434 2435 2436 2437 2438 2439 |
unlink(Tcl_DStringValue(&templ));
errno = 0;
}
Tcl_DStringFree(&templ);
return fd;
}
| | | 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 |
unlink(Tcl_DStringValue(&templ));
errno = 0;
}
Tcl_DStringFree(&templ);
return fd;
}
/*
* Helper that does *part* of what tempnam() does.
*/
static const char *
DefaultTempDir(void)
{
|
| ︙ | ︙ | |||
2501 2502 2503 2504 2505 2506 2507 |
/*
* Build the template in writable memory from the user-supplied pieces and
* some defaults.
*/
if (dirObj) {
string = TclGetString(dirObj);
| | < | < | 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 |
/*
* Build the template in writable memory from the user-supplied pieces and
* some defaults.
*/
if (dirObj) {
string = TclGetString(dirObj);
if (Tcl_UtfToExternalDStringEx(NULL, NULL, string, dirObj->length, 0, &templ, NULL) != TCL_OK) {
return NULL;
}
} else {
Tcl_DStringInit(&templ);
Tcl_DStringAppend(&templ, DefaultTempDir(), TCL_INDEX_NONE); /* INTL: native */
}
if (Tcl_DStringValue(&templ)[Tcl_DStringLength(&templ) - 1] != '/') {
TclDStringAppendLiteral(&templ, "/");
}
if (basenameObj) {
string = TclGetString(basenameObj);
if (basenameObj->length) {
if (Tcl_UtfToExternalDStringEx(NULL, NULL, string, basenameObj->length, 0, &tmp, NULL) != TCL_OK) {
Tcl_DStringFree(&templ);
return NULL;
}
TclDStringAppendDString(&templ, &tmp);
Tcl_DStringFree(&tmp);
} else {
TclDStringAppendLiteral(&templ, DEFAULT_TEMP_DIR_PREFIX);
|
| ︙ | ︙ | |||
2586 2587 2588 2589 2590 2591 2592 |
return winPath;
}
static const int attributeArray[] = {
0x20, 0, 2, 0, 0, 1, 4
};
| | | 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 |
return winPath;
}
static const int attributeArray[] = {
0x20, 0, 2, 0, 0, 1, 4
};
/*
*----------------------------------------------------------------------
*
* GetUnixFileAttributes
*
* Gets an attribute of a file.
*
|
| ︙ | ︙ |
Changes to unix/tclUnixFile.c.
| ︙ | ︙ | |||
398 399 400 401 402 403 404 |
if (Tcl_ExternalToUtfDStringEx(interp, NULL, entryPtr->d_name, TCL_INDEX_NONE,
0, &utfDs, NULL) != TCL_OK) {
matchResult = -1;
break;
}
utfname = Tcl_DStringValue(&utfDs);
| | | < < | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
if (Tcl_ExternalToUtfDStringEx(interp, NULL, entryPtr->d_name, TCL_INDEX_NONE,
0, &utfDs, NULL) != TCL_OK) {
matchResult = -1;
break;
}
utfname = Tcl_DStringValue(&utfDs);
if (Tcl_StringCaseMatch(utfname, pattern, 0)) {
int typeOk = 1;
if (types != NULL) {
Tcl_DStringSetLength(&ds, nativeDirLen);
native = Tcl_DStringAppend(&ds, entryPtr->d_name, TCL_INDEX_NONE);
matchResult = NativeMatchType(interp, native,
entryPtr->d_name, types);
typeOk = (matchResult == 1);
}
if (typeOk) {
Tcl_ListObjAppendElement(interp, resultPtr,
TclNewFSPathObj(pathPtr, utfname,
Tcl_DStringLength(&utfDs)));
}
}
Tcl_DStringFree(&utfDs);
if (matchResult < 0) {
break;
}
}
|
| ︙ | ︙ |
Changes to unix/tclUnixInit.c.
| ︙ | ︙ | |||
40 41 42 43 44 45 46 |
static const char *const processors[NUMPROCESSORS] = {
"i686", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil",
"x86_64", "ia32_on_win64", "neutral", "arm64", "arm32_on_win64", "ia32_on_arm64"
};
typedef struct {
union {
| | | | | | | | | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
static const char *const processors[NUMPROCESSORS] = {
"i686", "mips", "alpha", "ppc", "shx", "arm", "ia64", "alpha64", "msil",
"x86_64", "ia32_on_win64", "neutral", "arm64", "arm32_on_win64", "ia32_on_arm64"
};
typedef struct {
union {
unsigned int dwOemId;
struct {
int wProcessorArchitecture;
int wReserved;
};
};
unsigned int dwPageSize;
void *lpMinimumApplicationAddress;
void *lpMaximumApplicationAddress;
void *dwActiveProcessorMask;
unsigned int dwNumberOfProcessors;
unsigned int dwProcessorType;
unsigned int dwAllocationGranularity;
int wProcessorLevel;
int wProcessorRevision;
} SYSTEM_INFO;
typedef struct {
unsigned int dwOSVersionInfoSize;
unsigned int dwMajorVersion;
unsigned int dwMinorVersion;
unsigned int dwBuildNumber;
|
| ︙ | ︙ | |||
374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
#if defined(__bsdi__) && (_BSDI_VERSION > 199501)
/*
* Find local symbols. Don't report an error if we fail.
*/
(void) dlopen(NULL, RTLD_NOW); /* INTL: Native. */
#endif
}
/*
*---------------------------------------------------------------------------
*
* TclpInitLibraryPath --
*
| > > > > > > > > > > > > > > > > > > > > | 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
#if defined(__bsdi__) && (_BSDI_VERSION > 199501)
/*
* Find local symbols. Don't report an error if we fail.
*/
(void) dlopen(NULL, RTLD_NOW); /* INTL: Native. */
#endif
/*
* Initialize the C library's locale subsystem. This is required for input
* methods to work properly on X11. We only do this for LC_CTYPE because
* that's the necessary one, and we don't want to affect LC_TIME here.
* The side effect of setting the default locale should be to load any
* locale specific modules that are needed by X. [BUG: 5422 3345 4236 2522
* 2521].
*/
setlocale(LC_CTYPE, "");
/*
* In case the initial locale is not "C", ensure that the numeric
* processing is done in "C" locale regardless. This is needed because Tcl
* relies on routines like strtol/strtoul, but should not have locale dependent
* behavior.
*/
setlocale(LC_NUMERIC, "C");
}
/*
*---------------------------------------------------------------------------
*
* TclpInitLibraryPath --
*
|
| ︙ | ︙ | |||
550 551 552 553 554 555 556 |
/* Here, search for i in the interval left <= i < right. */
while (left < right) {
int test = (left + right)/2;
int code = strcmp(localeTable[test].lang, encoding);
if (code == 0) {
| | | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
/* Here, search for i in the interval left <= i < right. */
while (left < right) {
int test = (left + right)/2;
int code = strcmp(localeTable[test].lang, encoding);
if (code == 0) {
/* Found it at i == test. */
return localeTable[test].encoding;
}
if (code < 0) {
/* Restrict the search to the interval test < i < right. */
left = test+1;
} else {
/* Restrict the search to the interval left <= i < test. */
|
| ︙ | ︙ | |||
670 671 672 673 674 675 676 |
Tcl_DStringFree(&ds);
if (Tcl_DStringLength(bufPtr)) {
return Tcl_DStringValue(bufPtr);
}
}
return Tcl_DStringAppend(bufPtr, TCL_DEFAULT_ENCODING, TCL_INDEX_NONE);
}
| < < < < < < < | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
Tcl_DStringFree(&ds);
if (Tcl_DStringLength(bufPtr)) {
return Tcl_DStringValue(bufPtr);
}
}
return Tcl_DStringAppend(bufPtr, TCL_DEFAULT_ENCODING, TCL_INDEX_NONE);
}
/*
*---------------------------------------------------------------------------
*
* TclpSetVariables --
*
* Performs platform-specific interpreter initialization related to the
|
| ︙ | ︙ |
Changes to unix/tclUnixNotfy.c.
| ︙ | ︙ | |||
209 210 211 212 213 214 215 | * None. * *---------------------------------------------------------------------- */ void TclpSetTimer( | | | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
* None.
*
*----------------------------------------------------------------------
*/
void
TclpSetTimer(
TCL_UNUSED(const Tcl_Time *)) /* Timeout value, may be NULL. */
{
/*
* The interval timer doesn't do anything in this implementation, because
* the only event loop is via Tcl_DoOneEvent, which passes timeout values
* to Tcl_WaitForEvent.
*/
}
|
| ︙ | ︙ | |||
239 240 241 242 243 244 245 |
*/
void
TclpServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
| | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
*/
void
TclpServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
if (mode == TCL_SERVICE_ALL) {
#ifdef NOTIFIER_SELECT
#if TCL_THREADS
StartNotifierThread("Tcl_ServiceModeHook");
#endif
#endif /* NOTIFIER_SELECT */
}
}
|
| ︙ | ︙ | |||
402 403 404 405 406 407 408 |
pthread_cond_destroy(¬ifierCV);
}
pthread_mutex_init(¬ifierInitMutex, NULL);
pthread_mutex_init(¬ifierMutex, NULL);
pthread_cond_init(¬ifierCV, NULL);
#ifdef NOTIFIER_SELECT
| | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
pthread_cond_destroy(¬ifierCV);
}
pthread_mutex_init(¬ifierInitMutex, NULL);
pthread_mutex_init(¬ifierMutex, NULL);
pthread_cond_init(¬ifierCV, NULL);
#ifdef NOTIFIER_SELECT
asyncPending = 0;
#endif
/*
* notifierThreadRunning == 1: thread is running, (there might be data in
* notifier lists)
* atForkInit == 0: InitNotifier was never called
* notifierCount != 0: unbalanced InitNotifier() / FinalizeNotifier calls
|
| ︙ | ︙ | |||
543 544 545 546 547 548 549 |
* TCL_EXCEPTION. */
int timeout) /* Maximum amount of time to wait for one of
* the conditions in mask to occur, in
* milliseconds. A value of 0 means don't wait
* at all, and a value of -1 means wait
* forever. */
{
| | | > > > > | > | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 |
* TCL_EXCEPTION. */
int timeout) /* Maximum amount of time to wait for one of
* the conditions in mask to occur, in
* milliseconds. A value of 0 means don't wait
* at all, and a value of -1 means wait
* forever. */
{
Tcl_Time abortTime = {0, 0}, now; /* silence gcc 4 warning */
struct timeval blockTime, *timeoutPtr;
struct pollfd pollFds[1];
int numFound, result = 0, pollTimeout;
/*
* If there is a non-zero finite timeout, compute the time when we give
* up.
*/
if (timeout > 0) {
Tcl_GetTime(&now);
abortTime.sec = now.sec + timeout / 1000;
abortTime.usec = now.usec + (timeout % 1000) * 1000;
if (abortTime.usec >= 1000000) {
abortTime.usec -= 1000000;
abortTime.sec += 1;
}
timeoutPtr = &blockTime;
} else if (timeout == 0) {
timeoutPtr = &blockTime;
blockTime.tv_sec = 0;
blockTime.tv_usec = 0;
} else {
timeoutPtr = NULL;
|
| ︙ | ︙ | |||
588 589 590 591 592 593 594 |
/*
* Loop in a mini-event loop of our own, waiting for either the file to
* become ready or a timeout to occur.
*/
do {
if (timeout > 0) {
| > > > | | > | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 |
/*
* Loop in a mini-event loop of our own, waiting for either the file to
* become ready or a timeout to occur.
*/
do {
if (timeout > 0) {
blockTime.tv_sec = abortTime.sec - now.sec;
blockTime.tv_usec = abortTime.usec - now.usec;
if (blockTime.tv_usec < 0) {
blockTime.tv_sec -= 1;
blockTime.tv_usec += 1000000;
}
if (blockTime.tv_sec < 0) {
blockTime.tv_sec = 0;
blockTime.tv_usec = 0;
}
}
/*
|
| ︙ | ︙ | |||
637 638 639 640 641 642 643 | continue; } /* * The select returned early, so we need to recompute the timeout. */ | | | > | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 |
continue;
}
/*
* The select returned early, so we need to recompute the timeout.
*/
Tcl_GetTime(&now);
} while ((abortTime.sec > now.sec)
|| (abortTime.sec == now.sec && abortTime.usec > now.usec));
return result;
}
#endif /* !HAVE_COREFOUNDATION */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to unix/tclUnixPipe.c.
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
return NULL;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
if (contents != NULL) {
Tcl_DString dstring;
char *native;
| | < | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
return NULL;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
if (contents != NULL) {
Tcl_DString dstring;
char *native;
if (Tcl_UtfToExternalDStringEx(NULL, NULL, contents, TCL_INDEX_NONE, 0, &dstring, NULL) != TCL_OK) {
close(fd);
Tcl_DStringFree(&dstring);
return NULL;
}
native = Tcl_DStringValue(&dstring);
if (write(fd, native, Tcl_DStringLength(&dstring)) == -1) {
close(fd);
|
| ︙ | ︙ | |||
235 236 237 238 239 240 241 | *---------------------------------------------------------------------- * * TclpTempFileName -- * * This function returns unique filename. * * Results: | | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | *---------------------------------------------------------------------- * * TclpTempFileName -- * * This function returns unique filename. * * Results: * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
353 354 355 356 357 358 359 | * The file is closed. * *---------------------------------------------------------------------- */ int TclpCloseFile( | | | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
* The file is closed.
*
*----------------------------------------------------------------------
*/
int
TclpCloseFile(
TclFile file) /* The file to close. */
{
int fd = GetFd(file);
/*
* Refuse to close the fds for stdin, stdout and stderr.
*/
|
| ︙ | ︙ | |||
459 460 461 462 463 464 465 |
* deallocated later
*/
dsArray = (Tcl_DString *)TclStackAlloc(interp, argc * sizeof(Tcl_DString));
newArgv = (char **)TclStackAlloc(interp, (argc+1) * sizeof(char *));
newArgv[argc] = NULL;
for (i = 0; i < argc; i++) {
| | < | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
* deallocated later
*/
dsArray = (Tcl_DString *)TclStackAlloc(interp, argc * sizeof(Tcl_DString));
newArgv = (char **)TclStackAlloc(interp, (argc+1) * sizeof(char *));
newArgv[argc] = NULL;
for (i = 0; i < argc; i++) {
if (Tcl_UtfToExternalDStringEx(interp, NULL, argv[i], TCL_INDEX_NONE, 0, &dsArray[i], NULL) != TCL_OK) {
while (i-- > 0) {
Tcl_DStringFree(&dsArray[i]);
}
TclStackFree(interp, newArgv);
TclStackFree(interp, dsArray);
goto error;
}
|
| ︙ | ︙ | |||
576 577 578 579 580 581 582 |
|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
|| (joinThisError &&
((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
snprintf(errSpace, sizeof(errSpace),
"%dforked process couldn't set up input/output", errno);
len = strlen(errSpace);
if (len != (size_t) write(fd, errSpace, len)) {
| | | 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 |
|| (!joinThisError && !SetupStdFile(errorFile, TCL_STDERR))
|| (joinThisError &&
((dup2(1,2) == -1) || (fcntl(2, F_SETFD, 0) != 0)))) {
snprintf(errSpace, sizeof(errSpace),
"%dforked process couldn't set up input/output", errno);
len = strlen(errSpace);
if (len != (size_t) write(fd, errSpace, len)) {
Tcl_Panic("TclpCreateProcess: unable to write to errPipeOut");
}
_exit(1);
}
/*
* Close the input side of the error pipe.
*/
|
| ︙ | ︙ | |||
1219 1220 1221 1222 1223 1224 1225 |
}
return (int)written;
}
/*
*----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 |
}
return (int)written;
}
/*
*----------------------------------------------------------------------
*
* PipeWatchProc --
*
* Initialize the notifier to watch the fds from this channel.
*
* Results:
* None.
*
* Side effects:
* Sets up the notifier so that a future event on the channel will be
* seen by Tcl.
*
*----------------------------------------------------------------------
*/
/*
* Bug ad5a57f2f271: Tcl_NotifyChannel is not a Tcl_FileProc,
* so do not pass it to directly to Tcl_CreateFileHandler.
* Instead, pass a wrapper which is a Tcl_FileProc.
*/
static void
PipeWatchNotifyChannelWrapper(
void *clientData,
int mask)
{
Tcl_Channel channel = (Tcl_Channel)clientData;
Tcl_NotifyChannel(channel, mask);
}
static void
PipeWatchProc(
void *instanceData, /* The pipe state. */
int mask) /* Events of interest; an OR-ed combination of
* TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
|
| ︙ | ︙ | |||
1373 1374 1375 1376 1377 1378 1379 |
*----------------------------------------------------------------------
*/
int
Tcl_PidObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 |
*----------------------------------------------------------------------
*/
int
Tcl_PidObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
Tcl_Channel chan;
PipeState *pipePtr;
size_t i;
Tcl_Obj *resultPtr;
|
| ︙ | ︙ |
Changes to unix/tclUnixPort.h.
| ︙ | ︙ | |||
8 9 10 11 12 13 14 | * file sets up the union of all UNIX-related things needed by any of the * Tcl core files. This file depends on configuration #defines such as * HAVE_SYS_PARAM_H that are set up by the "configure" script. * * Much of the material in this file was originally contributed by Karl * Lehenbauer, Mark Diekhans and Peter da Silva. * | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | * file sets up the union of all UNIX-related things needed by any of the * Tcl core files. This file depends on configuration #defines such as * HAVE_SYS_PARAM_H that are set up by the "configure" script. * * Much of the material in this file was originally contributed by Karl * Lehenbauer, Mark Diekhans and Peter da Silva. * * Copyright (c) 1991-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLUNIXPORT #define _TCLUNIXPORT |
| ︙ | ︙ | |||
84 85 86 87 88 89 90 |
/* Make some symbols available without including <windows.h> */
# define CP_UTF8 65001
# define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004
# define HMODULE void *
# define MAX_PATH 260
# define SOCKET unsigned int
# define WSAEWOULDBLOCK 10035
| < < < < < < < | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/* Make some symbols available without including <windows.h> */
# define CP_UTF8 65001
# define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004
# define HMODULE void *
# define MAX_PATH 260
# define SOCKET unsigned int
# define WSAEWOULDBLOCK 10035
typedef unsigned short WCHAR;
__declspec(dllimport) extern int GetModuleHandleExW(unsigned, const void *, void *);
__declspec(dllimport) extern int GetModuleFileNameW(void *, const void *, int);
__declspec(dllimport) extern int WideCharToMultiByte(int, int, const void *, int,
char *, int, const char *, void *);
__declspec(dllimport) extern int MultiByteToWideChar(int, int, const char *, int,
WCHAR *, int);
__declspec(dllimport) extern void OutputDebugStringW(const WCHAR *);
__declspec(dllimport) extern int IsDebuggerPresent(void);
__declspec(dllimport) extern int GetLastError(void);
|
| ︙ | ︙ | |||
649 650 651 652 653 654 655 | MODULE_SCOPE struct passwd * TclpGetPwNam(const char *name); MODULE_SCOPE struct group * TclpGetGrNam(const char *name); MODULE_SCOPE struct passwd * TclpGetPwUid(uid_t uid); MODULE_SCOPE struct group * TclpGetGrGid(gid_t gid); MODULE_SCOPE struct hostent * TclpGetHostByName(const char *name); MODULE_SCOPE struct hostent * TclpGetHostByAddr(const char *addr, int length, int type); | | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 | MODULE_SCOPE struct passwd * TclpGetPwNam(const char *name); MODULE_SCOPE struct group * TclpGetGrNam(const char *name); MODULE_SCOPE struct passwd * TclpGetPwUid(uid_t uid); MODULE_SCOPE struct group * TclpGetGrGid(gid_t gid); MODULE_SCOPE struct hostent * TclpGetHostByName(const char *name); MODULE_SCOPE struct hostent * TclpGetHostByAddr(const char *addr, int length, int type); MODULE_SCOPE void *TclpMakeTcpClientChannelMode( void *tcpSocket, int mode); #endif /* _TCLUNIXPORT */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to unix/tclUnixSock.c.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | * Helper macros to make parts of this file clearer. The macros do exactly * what they say on the tin. :-) They also only ever refer to their arguments * once, and so can be used without regard to side effects. */ #define SET_BITS(var, bits) ((var) |= (bits)) #define CLEAR_BITS(var, bits) ((var) &= ~(bits)) | | | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | * Helper macros to make parts of this file clearer. The macros do exactly * what they say on the tin. :-) They also only ever refer to their arguments * once, and so can be used without regard to side effects. */ #define SET_BITS(var, bits) ((var) |= (bits)) #define CLEAR_BITS(var, bits) ((var) &= ~(bits)) #define GOT_BITS(var, bits) (((var) & (bits)) != 0) /* "sock" + a pointer in hex + \0 */ #define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1) #define SOCK_TEMPLATE "sock%" TCL_Z_MODIFIER "x" #undef SOCKET /* Possible conflict with win32 SOCKET */ /* * This is needed to comply with the strict aliasing rules of GCC, but it also * simplifies casting between the different sockaddr types. */ |
| ︙ | ︙ | |||
80 81 82 83 84 85 86 |
int cachedBlocking; /* Cache blocking mode of async socket. */
};
/*
* These bits may be OR'ed together into the "flags" field of a TcpState
* structure.
*/
| | | | | > | | | | | | < | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
int cachedBlocking; /* Cache blocking mode of async socket. */
};
/*
* These bits may be OR'ed together into the "flags" field of a TcpState
* structure.
*/
#define TCP_NONBLOCKING (1<<0) /* Socket with non-blocking I/O */
#define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */
#define TCP_ASYNC_PENDING (1<<4) /* TcpConnect was called to
* process an async connect. This
* flag indicates that reentry is
* still pending */
#define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */
#define TCP_ASYNC_TEST_MODE (1<<8) /* Async testing activated. Do not
* automatically continue connection
* process. */
/*
* The following defines the maximum length of the listen queue. This is the
* number of outstanding yet-to-be-serviced requests for a connection on a
* server socket, more than this number of outstanding requests and the
* connection request will fail.
*/
|
| ︙ | ︙ | |||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
* The following variable holds the network name of this host.
*/
static TclInitProcessGlobalValueProc InitializeHostName;
static ProcessGlobalValue hostName =
{0, 0, NULL, NULL, InitializeHostName, NULL, NULL};
/*
* ----------------------------------------------------------------------
*
* InitializeHostName --
*
* This routine sets the process global value of the name of the local
* host on which the process is running.
| > > > > > > > > > > > > > > > > > > | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
* The following variable holds the network name of this host.
*/
static TclInitProcessGlobalValueProc InitializeHostName;
static ProcessGlobalValue hostName =
{0, 0, NULL, NULL, InitializeHostName, NULL, NULL};
#if 0
/* printf debugging */
void
printaddrinfo(
struct addrinfo *addrlist,
char *prefix)
{
char host[NI_MAXHOST], port[NI_MAXSERV];
struct addrinfo *ai;
for (ai = addrlist; ai != NULL; ai = ai->ai_next) {
getnameinfo(ai->ai_addr, ai->ai_addrlen,
host, sizeof(host), port, sizeof(port),
NI_NUMERICHOST|NI_NUMERICSERV);
fprintf(stderr,"%s: %s:%s\n", prefix, host, port);
}
}
#endif
/*
* ----------------------------------------------------------------------
*
* InitializeHostName --
*
* This routine sets the process global value of the name of the local
* host on which the process is running.
|
| ︙ | ︙ | |||
594 595 596 597 598 599 600 601 602 603 604 605 606 607 |
if (fds->fd < 0) {
continue;
}
Tcl_DeleteFileHandler(fds->fd);
if (close(fds->fd) < 0) {
errorCode = errno;
}
}
fds = statePtr->fds.next;
while (fds != NULL) {
TcpFdList *next = fds->next;
Tcl_Free(fds);
fds = next;
| > | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
if (fds->fd < 0) {
continue;
}
Tcl_DeleteFileHandler(fds->fd);
if (close(fds->fd) < 0) {
errorCode = errno;
}
}
fds = statePtr->fds.next;
while (fds != NULL) {
TcpFdList *next = fds->next;
Tcl_Free(fds);
fds = next;
|
| ︙ | ︙ | |||
1084 1085 1086 1087 1088 1089 1090 |
/*
* Async-connecting socket must get reassigned handler if it have been
* transferred to another thread. Remove the handler if the socket is
* not managed by this thread anymore and create new handler (TSD related)
* so the callback will run in the correct thread, bug [f583715154].
*/
switch (action) {
| | | | | | | 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 |
/*
* Async-connecting socket must get reassigned handler if it have been
* transferred to another thread. Remove the handler if the socket is
* not managed by this thread anymore and create new handler (TSD related)
* so the callback will run in the correct thread, bug [f583715154].
*/
switch (action) {
case TCL_CHANNEL_THREAD_REMOVE:
CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING);
Tcl_DeleteFileHandler(statePtr->fds.fd);
break;
case TCL_CHANNEL_THREAD_INSERT:
Tcl_CreateFileHandler(statePtr->fds.fd,
TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback, statePtr);
SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
break;
}
}
}
/*
* ----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 |
/*
* Async sockets use a FileHandler internally while connecting, so we
* need to cache this request until the connection has succeeded.
*/
statePtr->filehandlers = mask;
} else if (mask) {
/*
* Whether it is a bug or feature or otherwise, it is a fact of life
* that on at least some Linux kernels select() fails to report that a
* socket file descriptor is writable when the other end of the socket
* is closed. This is in contrast to the guarantees Tcl makes that
* its channels become writable and fire writable events on an error
* condition. This has caused a leak of file descriptors in a state of
| > | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 |
/*
* Async sockets use a FileHandler internally while connecting, so we
* need to cache this request until the connection has succeeded.
*/
statePtr->filehandlers = mask;
} else if (mask) {
/*
* Whether it is a bug or feature or otherwise, it is a fact of life
* that on at least some Linux kernels select() fails to report that a
* socket file descriptor is writable when the other end of the socket
* is closed. This is in contrast to the guarantees Tcl makes that
* its channels become writable and fire writable events on an error
* condition. This has caused a leak of file descriptors in a state of
|
| ︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 | * ---------------------------------------------------------------------- * * TcpConnect -- * * This function opens a new socket in client mode. * * Results: | | | | | 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 | * ---------------------------------------------------------------------- * * TcpConnect -- * * This function opens a new socket in client mode. * * Results: * TCL_OK, if the socket was successfully connected or an asynchronous * connection is in progress. If an error occurs, TCL_ERROR is returned * and an error message is left in interp. * * Side effects: * Opens a socket. * * Remarks: * A single host name may resolve to more than one IP address, e.g. for * an IPv4/IPv6 dual stack host. For handling asynchronously connecting |
| ︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 | * Attempt to connect. The connect may fail at present with an * EINPROGRESS but at a later time it will complete. The caller * will set up a file handler on the socket if she is interested * in being informed when the connect completes. */ ret = connect(statePtr->fds.fd, statePtr->addr->ai_addr, | | | 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 |
* Attempt to connect. The connect may fail at present with an
* EINPROGRESS but at a later time it will complete. The caller
* will set up a file handler on the socket if she is interested
* in being informed when the connect completes.
*/
ret = connect(statePtr->fds.fd, statePtr->addr->ai_addr,
statePtr->addr->ai_addrlen);
if (ret < 0) {
error = errno;
}
if (ret < 0 && errno == EINPROGRESS) {
Tcl_CreateFileHandler(statePtr->fds.fd,
TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback,
statePtr);
|
| ︙ | ︙ | |||
1657 1658 1659 1660 1661 1662 1663 |
* families. We try this at most MAXRETRY times to avoid an endless loop
* if all ports are taken.
*/
int retry = 0;
#define MAXRETRY 10
| | | 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 |
* families. We try this at most MAXRETRY times to avoid an endless loop
* if all ports are taken.
*/
int retry = 0;
#define MAXRETRY 10
repeat:
if (retry > 0) {
if (statePtr != NULL) {
TcpCloseProc(statePtr, NULL);
statePtr = NULL;
}
if (addrlist != NULL) {
freeaddrinfo(addrlist);
|
| ︙ | ︙ | |||
1861 1862 1863 1864 1865 1866 1867 |
return NULL;
}
/*
*----------------------------------------------------------------------
*
* TcpAccept --
| < | | 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 |
return NULL;
}
/*
*----------------------------------------------------------------------
*
* TcpAccept --
* Accept a TCP socket connection. This is called by the event loop.
*
* Results:
* None.
*
* Side effects:
* Creates a new connection socket. Calls the registered callback for the
* connection acceptance mechanism.
|
| ︙ | ︙ |
Changes to unix/tclUnixTest.c.
| ︙ | ︙ | |||
28 29 30 31 32 33 34 | /* * The following macros convert between TclFile's and fd's. The conversion * simple involves shifting fd's up by one to ensure that no valid fd is ever * the same as NULL. Note that this code is duplicated from tclUnixPipe.c */ #define MakeFile(fd) ((TclFile)INT2PTR(((int)(fd))+1)) | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/*
* The following macros convert between TclFile's and fd's. The conversion
* simple involves shifting fd's up by one to ensure that no valid fd is ever
* the same as NULL. Note that this code is duplicated from tclUnixPipe.c
*/
#define MakeFile(fd) ((TclFile)INT2PTR(((int)(fd))+1))
#define GetFd(file) (PTR2INT(file)-1)
/*
* The stuff below is used to keep track of file handlers created and
* exercised by the "testfilehandler" command.
*/
typedef struct {
|
| ︙ | ︙ | |||
60 61 62 63 64 65 66 | static const char *gotsig = "0"; /* * Forward declarations of functions defined later in this file: */ | | | | | | | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | static const char *gotsig = "0"; /* * Forward declarations of functions defined later in this file: */ static Tcl_ObjCmdProc TestalarmCmd; static Tcl_ObjCmdProc TestchmodCmd; static Tcl_ObjCmdProc TestfilehandlerCmd; static Tcl_ObjCmdProc TestfilewaitCmd; static Tcl_ObjCmdProc TestfindexecutableCmd; static Tcl_ObjCmdProc TestforkCmd; static Tcl_ObjCmdProc TestgotsigCmd; static Tcl_FileProc TestFileHandlerProc; static void AlarmHandler(int signum); /* *---------------------------------------------------------------------- * * TclplatformtestInit -- |
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
*----------------------------------------------------------------------
*/
int
TclplatformtestInit(
Tcl_Interp *interp) /* Interpreter to add commands to. */
{
| | | | | | | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
*----------------------------------------------------------------------
*/
int
TclplatformtestInit(
Tcl_Interp *interp) /* Interpreter to add commands to. */
{
Tcl_CreateObjCommand(interp, "testchmod", TestchmodCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfilehandler", TestfilehandlerCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfilewait", TestfilewaitCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfindexecutable", TestfindexecutableCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testfork", TestforkCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testalarm", TestalarmCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testgotsig", TestgotsigCmd,
NULL, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
129 130 131 132 133 134 135 |
*----------------------------------------------------------------------
*/
static int
TestfilehandlerCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
*----------------------------------------------------------------------
*/
static int
TestfilehandlerCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
Pipe *pipePtr;
int i, mask, timeout;
static int initialized = 0;
char buffer[4000];
TclFile file;
|
| ︙ | ︙ | |||
308 309 310 311 312 313 314 |
return TCL_ERROR;
}
return TCL_OK;
}
static void
TestFileHandlerProc(
| | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
return TCL_ERROR;
}
return TCL_OK;
}
static void
TestFileHandlerProc(
void *clientData, /* Points to a Pipe structure. */
int mask) /* Indicates which events happened:
* TCL_READABLE or TCL_WRITABLE. */
{
Pipe *pipePtr = (Pipe *)clientData;
if (mask & TCL_READABLE) {
pipePtr->readCount++;
|
| ︙ | ︙ | |||
343 344 345 346 347 348 349 |
*----------------------------------------------------------------------
*/
static int
TestfilewaitCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
*----------------------------------------------------------------------
*/
static int
TestfilewaitCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
int mask, result, timeout;
Tcl_Channel channel;
int fd;
void *data;
|
| ︙ | ︙ | |||
376 377 378 379 380 381 382 |
}
if (Tcl_GetChannelHandle(channel,
(mask & TCL_READABLE) ? TCL_READABLE : TCL_WRITABLE,
(void **) &data) != TCL_OK) {
Tcl_AppendResult(interp, "couldn't get channel file", (char *)NULL);
return TCL_ERROR;
}
| | | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 |
}
if (Tcl_GetChannelHandle(channel,
(mask & TCL_READABLE) ? TCL_READABLE : TCL_WRITABLE,
(void **) &data) != TCL_OK) {
Tcl_AppendResult(interp, "couldn't get channel file", (char *)NULL);
return TCL_ERROR;
}
fd = PTR2INT(data);
if (Tcl_GetIntFromObj(interp, objv[3], &timeout) != TCL_OK) {
return TCL_ERROR;
}
result = TclUnixWaitForFile(fd, mask, timeout);
if (result & TCL_READABLE) {
Tcl_AppendElement(interp, "readable");
}
|
| ︙ | ︙ | |||
411 412 413 414 415 416 417 |
*----------------------------------------------------------------------
*/
static int
TestfindexecutableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
*----------------------------------------------------------------------
*/
static int
TestfindexecutableCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
Tcl_Obj *saveName;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "argv0");
return TCL_ERROR;
|
| ︙ | ︙ | |||
453 454 455 456 457 458 459 |
*----------------------------------------------------------------------
*/
static int
TestforkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 |
*----------------------------------------------------------------------
*/
static int
TestforkCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
pid_t pid;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
|
| ︙ | ︙ | |||
499 500 501 502 503 504 505 |
*----------------------------------------------------------------------
*/
static int
TestalarmCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
*----------------------------------------------------------------------
*/
static int
TestalarmCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
#ifdef SA_RESTART
unsigned int sec = 1;
struct sigaction action;
if (objc > 1) {
|
| ︙ | ︙ | |||
577 578 579 580 581 582 583 |
*----------------------------------------------------------------------
*/
static int
TestgotsigCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
*----------------------------------------------------------------------
*/
static int
TestgotsigCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
TCL_UNUSED(int) /*objc*/,
TCL_UNUSED(Tcl_Obj *const *))
{
Tcl_AppendResult(interp, gotsig, (char *)NULL);
gotsig = "0";
return TCL_OK;
}
|
| ︙ | ︙ | |||
607 608 609 610 611 612 613 |
*
*---------------------------------------------------------------------------
*/
static int
TestchmodCmd(
TCL_UNUSED(void *),
| | | | < | | | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 |
*
*---------------------------------------------------------------------------
*/
static int
TestchmodCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
int i, mode;
Tcl_DString ds;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "mode file ?file ...?");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[1], &mode) != TCL_OK) {
return TCL_ERROR;
}
Tcl_DStringInit(&ds);
for (i = 2; i < objc; i++) {
Tcl_DString buffer;
const char *translated;
translated = Tcl_TranslateFileName(interp, Tcl_GetString(objv[i]), &buffer);
if (translated == NULL) {
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_UtfToExternalDString(NULL, translated, -1, &ds);
if (chmod(Tcl_DStringValue(&ds), mode) != 0) {
Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
(char *)NULL);
Tcl_DStringFree(&ds);
return TCL_ERROR;
}
Tcl_DStringFree(&buffer);
Tcl_DStringSetLength(&ds, 0);
|
| ︙ | ︙ |
Changes to unix/tclUnixThrd.c.
| ︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
// It's recursive
pmutexPtr->counter--;
} else {
pmutexPtr->thread = PTHREAD_NULL;
pthread_mutex_unlock(&pmutexPtr->mutex);
}
}
static void
PCondWait(
pthread_cond_t *pcondPtr,
PMutex *pmutexPtr)
{
pthread_t mythread = pthread_self();
| > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
// It's recursive
pmutexPtr->counter--;
} else {
pmutexPtr->thread = PTHREAD_NULL;
pthread_mutex_unlock(&pmutexPtr->mutex);
}
}
static void
PCondWait(
pthread_cond_t *pcondPtr,
PMutex *pmutexPtr)
{
pthread_t mythread = pthread_self();
|
| ︙ | ︙ | |||
638 639 640 641 642 643 644 |
*mutexPtr = NULL;
}
}
/*
*----------------------------------------------------------------------
*
| | | | | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
*mutexPtr = NULL;
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_ConditionWait --
*
* This procedure is invoked to wait on a condition variable. The mutex
* is automically released as part of the wait, and automatically grabbed
* when the condition is signaled.
*
* The mutex must be held when this procedure is called.
*
* Results:
* None.
*
* Side effects:
* May block the current thread. The mutex is acquired when this returns.
* Will allocate memory for a pthread_mutex_t and initialize this the
* first time this Tcl_Mutex is used.
*
*----------------------------------------------------------------------
*/
void
Tcl_ConditionWait(
Tcl_Condition *condPtr, /* Really (pthread_cond_t **) */
Tcl_Mutex *mutexPtr, /* Really (PMutex **) */
const Tcl_Time *timePtr) /* Timeout on waiting period */
{
pthread_cond_t *pcondPtr;
PMutex *pmutexPtr;
struct timespec ptime;
if (*condPtr == NULL) {
pthread_mutex_lock(&globalLock);
|
| ︙ | ︙ | |||
685 686 687 688 689 690 691 |
*condPtr = (Tcl_Condition) pcondPtr;
TclRememberCondition(condPtr);
}
pthread_mutex_unlock(&globalLock);
}
pmutexPtr = *((PMutex **)mutexPtr);
pcondPtr = *((pthread_cond_t **)condPtr);
| | | | | > | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 |
*condPtr = (Tcl_Condition) pcondPtr;
TclRememberCondition(condPtr);
}
pthread_mutex_unlock(&globalLock);
}
pmutexPtr = *((PMutex **)mutexPtr);
pcondPtr = *((pthread_cond_t **)condPtr);
if (timePtr == NULL) {
PCondWait(pcondPtr, pmutexPtr);
} else {
Tcl_Time now;
/*
* Make sure to take into account the microsecond component of the
* current time, including possible overflow situations. [Bug #411603]
*/
Tcl_GetTime(&now);
ptime.tv_sec = timePtr->sec + now.sec +
(timePtr->usec + now.usec) / 1000000;
ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
PCondTimedWait(pcondPtr, pmutexPtr, &ptime);
}
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ |
Changes to unix/tclUnixTime.c.
| ︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" #if defined(TCL_WIDE_CLICKS) && defined(MAC_OSX_TCL) #include <mach/mach_time.h> #endif /* *---------------------------------------------------------------------- * * TclpGetSeconds -- * * This procedure returns the number of seconds from the epoch. On most | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
#if defined(TCL_WIDE_CLICKS) && defined(MAC_OSX_TCL)
#include <mach/mach_time.h>
#endif
/*
* Static functions declared in this file.
*/
static void NativeScaleTime(Tcl_Time *timebuf,
void *clientData);
static void NativeGetTime(Tcl_Time *timebuf,
void *clientData);
/*
* TIP #233 (Virtualized Time): Data for the time hooks, if any.
*/
Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime;
Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
void *tclTimeClientData = NULL;
/*
* Inlined version of Tcl_GetTime.
*/
static inline void
GetTime(
Tcl_Time *timePtr)
{
tclGetTimeProcPtr(timePtr, tclTimeClientData);
}
#if defined(NO_GETTOD) || defined(TCL_WIDE_CLICKS)
static inline int
IsTimeNative(void)
{
return tclGetTimeProcPtr == NativeGetTime;
}
#endif
/*
*----------------------------------------------------------------------
*
* TclpGetSeconds --
*
* This procedure returns the number of seconds from the epoch. On most
|
| ︙ | ︙ | |||
37 38 39 40 41 42 43 |
{
return (unsigned long long) time(NULL);
}
/*
*----------------------------------------------------------------------
*
| | | | | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
{
return (unsigned long long) time(NULL);
}
/*
*----------------------------------------------------------------------
*
* TclpGetMicroseconds --
*
* This procedure returns the number of microseconds from the epoch.
* On most Unix systems the epoch is Midnight Jan 1, 1970 GMT.
*
* Results:
* Number of microseconds from the epoch.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
long long
TclpGetMicroseconds(void)
{
Tcl_Time time;
GetTime(&time);
return time.sec * 1000000 + time.usec;
}
/*
*----------------------------------------------------------------------
*
* TclpGetClicks --
*
|
| ︙ | ︙ | |||
85 86 87 88 89 90 91 92 |
unsigned long long
TclpGetClicks(void)
{
unsigned long long now;
#ifdef NO_GETTOD
| > > > > > > | | | < | | > | | | | < | < < | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
unsigned long long
TclpGetClicks(void)
{
unsigned long long now;
#ifdef NO_GETTOD
if (!IsTimeNative()) {
Tcl_Time time;
GetTime(&time);
now = ((unsigned long long)(time.sec)*1000000ULL) +
(unsigned long long)(time.usec);
} else {
/*
* A semi-NativeGetTime, specialized to clicks.
*/
struct tms dummy;
now = (unsigned long long) times(&dummy);
}
#else /* !NO_GETTOD */
Tcl_Time time;
GetTime(&time);
now = ((unsigned long long)(time.sec)*1000000ULL) +
(unsigned long long)(time.usec);
#endif /* NO_GETTOD */
return now;
}
#ifdef TCL_WIDE_CLICKS
/*
*----------------------------------------------------------------------
*
* TclpGetWideClicks --
*
* This procedure returns a WideInt value that represents the highest
* resolution clock available on the system. There are no guarantees on
|
| ︙ | ︙ | |||
130 131 132 133 134 135 136 |
*
*----------------------------------------------------------------------
*/
long long
TclpGetWideClicks(void)
{
| > > > > > > > > > | > > > > > > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
*
*----------------------------------------------------------------------
*/
long long
TclpGetWideClicks(void)
{
long long now;
if (!IsTimeNative()) {
Tcl_Time time;
GetTime(&time);
now = ((long long) time.sec)*1000000 + time.usec;
} else {
#ifdef MAC_OSX_TCL
now = (long long) (mach_absolute_time() & INT64_MAX);
#else
#error Wide high-resolution clicks not implemented on this platform
#endif /* MAC_OSX_TCL */
}
return now;
}
/*
*----------------------------------------------------------------------
*
* TclpWideClicksToNanoseconds --
*
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 |
*/
double
TclpWideClicksToNanoseconds(
long long clicks)
{
double nsec;
| > > > > > | | | | | | | | | | > > > > > | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
*/
double
TclpWideClicksToNanoseconds(
long long clicks)
{
double nsec;
if (!IsTimeNative()) {
nsec = clicks * 1000;
} else {
#ifdef MAC_OSX_TCL
static mach_timebase_info_data_t tb;
static uint64_t maxClicksForUInt64;
if (!tb.denom) {
mach_timebase_info(&tb);
maxClicksForUInt64 = UINT64_MAX / tb.numer;
}
if ((uint64_t) clicks < maxClicksForUInt64) {
nsec = ((uint64_t) clicks) * tb.numer / tb.denom;
} else {
nsec = ((long double) (uint64_t) clicks) * tb.numer / tb.denom;
}
#else
#error Wide high-resolution clicks not implemented on this platform
#endif /* MAC_OSX_TCL */
}
return nsec;
}
/*
*----------------------------------------------------------------------
*
* TclpWideClickInMicrosec --
|
| ︙ | ︙ | |||
191 192 193 194 195 196 197 |
*
*----------------------------------------------------------------------
*/
double
TclpWideClickInMicrosec(void)
{
| > > > > | | | | | | | | | | < | < < | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < | < < < < < < < < < < < < < | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
*
*----------------------------------------------------------------------
*/
double
TclpWideClickInMicrosec(void)
{
if (!IsTimeNative()) {
return 1.0;
} else {
#ifdef MAC_OSX_TCL
static int initialized = 0;
static double scale = 0.0;
if (!initialized) {
mach_timebase_info_data_t tb;
mach_timebase_info(&tb);
/* value of tb.numer / tb.denom = 1 click in nanoseconds */
scale = ((double) tb.numer) / tb.denom / 1000;
initialized = 1;
}
return scale;
#else
#error Wide high-resolution clicks not implemented on this platform
#endif /* MAC_OSX_TCL */
}
}
#endif /* TCL_WIDE_CLICKS */
/*
*----------------------------------------------------------------------
*
* Tcl_GetTime --
*
* Gets the current system time in seconds and microseconds since the
* beginning of the epoch: 00:00 UCT, January 1, 1970.
*
* This function is hooked, allowing users to specify their own virtual
* system time.
*
* Results:
* Returns the current time in timePtr.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Tcl_GetTime(
Tcl_Time *timePtr) /* Location to store time information. */
{
GetTime(timePtr);
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetTimeProc --
*
* TIP #233 (Virtualized Time): Registers two handlers for the
* virtualization of Tcl's access to time information.
*
* Results:
* None.
*
* Side effects:
* Remembers the handlers, alters core behaviour.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetTimeProc(
Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
void *clientData)
{
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
tclTimeClientData = clientData;
}
/*
*----------------------------------------------------------------------
*
* Tcl_QueryTimeProc --
*
* TIP #233 (Virtualized Time): Query which time handlers are registered.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Tcl_QueryTimeProc(
Tcl_GetTimeProc **getProc,
Tcl_ScaleTimeProc **scaleProc,
void **clientData)
{
if (getProc) {
*getProc = tclGetTimeProcPtr;
}
if (scaleProc) {
*scaleProc = tclScaleTimeProcPtr;
}
if (clientData) {
*clientData = tclTimeClientData;
}
}
/*
*----------------------------------------------------------------------
*
* NativeScaleTime --
*
* TIP #233: Scale from virtual time to the real-time. For native scaling
* the relationship is 1:1 and nothing has to be done.
*
* Results:
* Scales the time in timePtr.
*
* Side effects:
* See above.
*
*----------------------------------------------------------------------
*/
static void
NativeScaleTime(
TCL_UNUSED(Tcl_Time *),
TCL_UNUSED(void *))
{
/* Native scale is 1:1. Nothing is done */
}
/*
*----------------------------------------------------------------------
*
* NativeGetTime --
*
* TIP #233: Gets the current system time in seconds and microseconds
* since the beginning of the epoch: 00:00 UCT, January 1, 1970.
*
* Results:
* Returns the current time in timePtr.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
NativeGetTime(
Tcl_Time *timePtr,
TCL_UNUSED(void *))
{
struct timeval tv;
(void) gettimeofday(&tv, NULL);
timePtr->sec = tv.tv_sec;
timePtr->usec = tv.tv_usec;
}
|
| ︙ | ︙ |
Changes to unix/tclXtNotify.c.
| ︙ | ︙ | |||
29 30 31 32 33 34 35 |
* time FileHandlerEventProc was called for
* this file. */
XtInputId read; /* Xt read callback handle. */
XtInputId write; /* Xt write callback handle. */
XtInputId except; /* Xt exception callback handle. */
Tcl_FileProc *proc; /* Procedure to call, in the style of
* Tcl_CreateFileHandler. */
| | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
* time FileHandlerEventProc was called for
* this file. */
XtInputId read; /* Xt read callback handle. */
XtInputId write; /* Xt write callback handle. */
XtInputId except; /* Xt exception callback handle. */
Tcl_FileProc *proc; /* Procedure to call, in the style of
* Tcl_CreateFileHandler. */
void *clientData; /* Argument to pass to proc. */
struct FileHandler *nextPtr;/* Next in list of all files we care about. */
} FileHandler;
/*
* The following structure is what is added to the Tcl event queue when file
* handlers are ready to fire.
*/
|
| ︙ | ︙ | |||
259 260 261 262 263 264 265 | * Replaces any previous timer. * *---------------------------------------------------------------------- */ static void SetTimer( | | | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
* Replaces any previous timer.
*
*----------------------------------------------------------------------
*/
static void
SetTimer(
const Tcl_Time *timePtr) /* Timeout value, may be NULL. */
{
unsigned long timeout;
if (!initialized) {
InitNotifier();
}
|
| ︙ | ︙ | |||
335 336 337 338 339 340 341 |
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
* conditions under which proc should be
* called. */
Tcl_FileProc *proc, /* Procedure to call for each selected
* event. */
| | | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
* conditions under which proc should be
* called. */
Tcl_FileProc *proc, /* Procedure to call for each selected
* event. */
void *clientData) /* Arbitrary data to pass to proc. */
{
FileHandler *filePtr;
if (!initialized) {
InitNotifier();
}
|
| ︙ | ︙ | |||
623 624 625 626 627 628 629 | * Queues file events that are detected by the select. * *---------------------------------------------------------------------- */ static int WaitForEvent( | | | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
* Queues file events that are detected by the select.
*
*----------------------------------------------------------------------
*/
static int
WaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
int timeout;
if (!initialized) {
InitNotifier();
}
|
| ︙ | ︙ |
Changes to unix/tclXtTest.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | #ifndef USE_TCL_STUBS # define USE_TCL_STUBS #endif #include <X11/Intrinsic.h> #include "tcl.h" | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #ifndef USE_TCL_STUBS # define USE_TCL_STUBS #endif #include <X11/Intrinsic.h> #include "tcl.h" static Tcl_ObjCmdProc TesteventloopCmd; /* * Functions defined in tclXtNotify.c for use by users of the Xt Notifier: */ extern void InitNotifier(void); extern XtAppContext TclSetAppContext(XtAppContext ctx); |
| ︙ | ︙ | |||
48 49 50 51 52 53 54 |
Tcl_Interp *interp) /* Interpreter for application. */
{
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
XtToolkitInitialize();
InitNotifier();
| | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
Tcl_Interp *interp) /* Interpreter for application. */
{
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
XtToolkitInitialize();
InitNotifier();
Tcl_CreateObjCommand(interp, "testeventloop", TesteventloopCmd,
NULL, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
*----------------------------------------------------------------------
*/
static int
TesteventloopCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
*----------------------------------------------------------------------
*/
static int
TesteventloopCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static int *framePtr = NULL;/* Pointer to integer on stack frame of
* innermost invocation of the "wait"
* subcommand. */
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "option ...");
|
| ︙ | ︙ |
Deleted utf8proc/LICENSE.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utf8proc/README-tcl.md.
|
| < < < |
Deleted utf8proc/README.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utf8proc/utf8proc.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utf8proc/utf8proc.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted utf8proc/utf8proc_data.c.
more than 10,000 changes
Changes to win/Makefile.in.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@ # To change the compiler switches, for example to change from optimization to # debugging symbols, change the following line: #CFLAGS = $(CFLAGS_DEBUG) #CFLAGS = $(CFLAGS_OPTIMIZE) #CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE) | | < < < > > > > > | > < < | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
CFLAGS_OPTIMIZE = @CFLAGS_OPTIMIZE@
# To change the compiler switches, for example to change from optimization to
# debugging symbols, change the following line:
#CFLAGS = $(CFLAGS_DEBUG)
#CFLAGS = $(CFLAGS_OPTIMIZE)
#CFLAGS = $(CFLAGS_DEBUG) $(CFLAGS_OPTIMIZE)
CFLAGS = @CFLAGS@ @CFLAGS_DEFAULT@ -DMP_FIXED_CUTOFFS -D__USE_MINGW_ANSI_STDIO=0
# To compile without backward compatibility and deprecated code uncomment the
# following
NO_DEPRECATED_FLAGS =
#NO_DEPRECATED_FLAGS = -DTCL_NO_DEPRECATED
# To enable compilation debugging reverse the comment characters on one of the
# following lines.
COMPILE_DEBUG_FLAGS =
#COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG
#COMPILE_DEBUG_FLAGS = -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS
SRC_DIR = @srcdir@
ROOT_DIR = @srcdir@/..
TOP_DIR = $(shell cd '@srcdir@/..'; pwd -W 2>/dev/null || pwd -P)
BUILD_DIR = @builddir@
GENERIC_DIR = $(TOP_DIR)/generic
WIN_DIR = $(TOP_DIR)/win
UNIX_DIR = $(TOP_DIR)/unix
COMPAT_DIR = $(TOP_DIR)/compat
PKGS_DIR = $(TOP_DIR)/pkgs
TOOL_DIR = $(TOP_DIR)/tools
ZLIB_DIR = $(COMPAT_DIR)/zlib
MINIZIP_DIR = $(ZLIB_DIR)/contrib/minizip
TOMMATH_DIR = $(TOP_DIR)/libtommath
# Converts a POSIX path to a Windows native path.
CYGPATH = @CYGPATH@
libdir_native = $(shell $(CYGPATH) '$(libdir)')
bindir_native = $(shell $(CYGPATH) '$(bindir)')
includedir_native = $(shell $(CYGPATH) '$(includedir)')
mandir_native = $(shell $(CYGPATH) '$(mandir)')
TCL_LIBRARY_NATIVE = $(shell $(CYGPATH) '$(TCL_LIBRARY)')
GENERIC_DIR_NATIVE = $(shell $(CYGPATH) '$(GENERIC_DIR)')
WIN_DIR_NATIVE = $(shell $(CYGPATH) '$(WIN_DIR)')
ROOT_DIR_NATIVE = $(shell $(CYGPATH) '$(ROOT_DIR)')
TOOL_DIR_NATIVE = $(shell $(CYGPATH) '$(TOOL_DIR)')
SCRIPT_INSTALL_DIR_NATIVE = $(shell $(CYGPATH) '$(SCRIPT_INSTALL_DIR)')
INCLUDE_INSTALL_DIR_NATIVE = $(shell $(CYGPATH) '$(INCLUDE_INSTALL_DIR)')
MAN_INSTALL_DIR_NATIVE = $(shell $(CYGPATH) '$(MAN_INSTALL_DIR)')
ROOT_DIR_WIN_NATIVE = $(shell cd '$(ROOT_DIR)' ; pwd -W 2>/dev/null || pwd -P)
ZLIB_DIR_NATIVE = $(shell $(CYGPATH) '$(ZLIB_DIR)')
MINIZIP_DIR_NATIVE = $(shell $(CYGPATH) '$(MINIZIP_DIR)')
TOMMATH_DIR_NATIVE = $(shell $(CYGPATH) '$(TOMMATH_DIR)')
DLLSUFFIX = @DLLSUFFIX@
LIBSUFFIX = @LIBSUFFIX@
EXESUFFIX = @EXESUFFIX@
VER = @TCL_MAJOR_VERSION@@TCL_MINOR_VERSION@
DOTVER = @TCL_MAJOR_VERSION@.@TCL_MINOR_VERSION@
DDEVER = @TCL_DDE_MAJOR_VERSION@@TCL_DDE_MINOR_VERSION@
DDEDOTVER = @TCL_DDE_MAJOR_VERSION@.@TCL_DDE_MINOR_VERSION@
REGVER = @TCL_REG_MAJOR_VERSION@@TCL_REG_MINOR_VERSION@
REGDOTVER = @TCL_REG_MAJOR_VERSION@.@TCL_REG_MINOR_VERSION@
TCL_ZIP_FILE = @TCL_ZIP_FILE@
TCL_VFS_PATH = libtcl.vfs/tcl_library
TCL_VFS_ROOT = libtcl.vfs
TCL_STUB_LIB_FILE = @TCL_STUB_LIB_FILE@
TCL_DLL_FILE = @TCL_DLL_FILE@
TCL_LIB_FILE = @TCL_LIB_FILE@
DDE_DLL_FILE = tcl9dde$(DDEVER)${DLLSUFFIX}
DDE_DLL_FILE8 = tcldde$(DDEVER)${DLLSUFFIX}
DDE_LIB_FILE = @LIBPREFIX@tcldde$(DDEVER)${DLLSUFFIX}${LIBSUFFIX}
REG_DLL_FILE = tcl9registry$(REGVER)${DLLSUFFIX}
REG_DLL_FILE8 = tclregistry$(REGVER)${DLLSUFFIX}
REG_LIB_FILE = @LIBPREFIX@tclregistry$(REGVER)${DLLSUFFIX}${LIBSUFFIX}
TEST_DLL_FILE = tcltest$(VER)${DLLSUFFIX}
TEST_EXE_FILE = tcltest${EXESUFFIX}
TEST_LIB_FILE = @LIBPREFIX@tcltest$(VER)${DLLSUFFIX}${LIBSUFFIX}
TEST_LOAD_PRMS = lappend ::auto_path {$(ROOT_DIR_WIN_NATIVE)/tests};\
package ifneeded dde 1.4.6 [list load ${DDE_DLL_FILE}];\
package ifneeded registry 1.3.7 [list load ${REG_DLL_FILE}]
TEST_LOAD_FACILITIES = package ifneeded tcl::test ${VERSION}@TCL_PATCH_LEVEL@ [list load ${TEST_DLL_FILE} Tcltest];\
$(TEST_LOAD_PRMS)
ZLIB_DLL_FILE = zlib1.dll
TOMMATH_DLL_FILE = libtommath.dll
SHARED_LIBRARIES = $(TCL_DLL_FILE) @ZLIB_DLL_FILE@ @TOMMATH_DLL_FILE@
STATIC_LIBRARIES = $(TCL_LIB_FILE)
TCLSH = tclsh$(VER)${EXESUFFIX}
|
| ︙ | ︙ | |||
322 323 324 325 326 327 328 | tclEnsemble.$(OBJEXT) \ tclEnv.$(OBJEXT) \ tclEvent.$(OBJEXT) \ tclExecute.$(OBJEXT) \ tclFCmd.$(OBJEXT) \ tclFileName.$(OBJEXT) \ tclGet.$(OBJEXT) \ | < < | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | tclEnsemble.$(OBJEXT) \ tclEnv.$(OBJEXT) \ tclEvent.$(OBJEXT) \ tclExecute.$(OBJEXT) \ tclFCmd.$(OBJEXT) \ tclFileName.$(OBJEXT) \ tclGet.$(OBJEXT) \ tclHash.$(OBJEXT) \ tclHistory.$(OBJEXT) \ tclIcu.$(OBJEXT) \ tclIndexObj.$(OBJEXT) \ tclInterp.$(OBJEXT) \ tclIO.$(OBJEXT) \ tclIOCmd.$(OBJEXT) \ tclIOGT.$(OBJEXT) \ tclIORChan.$(OBJEXT) \ tclIORTrans.$(OBJEXT) \ tclIOSock.$(OBJEXT) \ tclIOUtil.$(OBJEXT) \ tclLink.$(OBJEXT) \ tclLiteral.$(OBJEXT) \ tclListObj.$(OBJEXT) \ tclLoad.$(OBJEXT) \ tclMainW.$(OBJEXT) \ tclMain.$(OBJEXT) \ tclNamesp.$(OBJEXT) \ tclNotify.$(OBJEXT) \ tclOO.$(OBJEXT) \ tclOOBasic.$(OBJEXT) \ |
| ︙ | ︙ | |||
374 375 376 377 378 379 380 381 382 383 384 385 386 387 | tclScan.$(OBJEXT) \ tclStringObj.$(OBJEXT) \ tclStrIdxTree.$(OBJEXT) \ tclStrToD.$(OBJEXT) \ tclStubInit.$(OBJEXT) \ tclThread.$(OBJEXT) \ tclThreadAlloc.$(OBJEXT) \ tclThreadStorage.$(OBJEXT) \ tclTimer.$(OBJEXT) \ tclTomMathInterface.$(OBJEXT) \ tclTrace.$(OBJEXT) \ tclUtf.$(OBJEXT) \ tclUtil.$(OBJEXT) \ tclVar.$(OBJEXT) \ | > | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | tclScan.$(OBJEXT) \ tclStringObj.$(OBJEXT) \ tclStrIdxTree.$(OBJEXT) \ tclStrToD.$(OBJEXT) \ tclStubInit.$(OBJEXT) \ tclThread.$(OBJEXT) \ tclThreadAlloc.$(OBJEXT) \ tclThreadJoin.$(OBJEXT) \ tclThreadStorage.$(OBJEXT) \ tclTimer.$(OBJEXT) \ tclTomMathInterface.$(OBJEXT) \ tclTrace.$(OBJEXT) \ tclUtf.$(OBJEXT) \ tclUtil.$(OBJEXT) \ tclVar.$(OBJEXT) \ |
| ︙ | ︙ | |||
455 456 457 458 459 460 461 |
bn_s_mp_reverse.${OBJEXT} \
bn_s_mp_sqr_fast.${OBJEXT} \
bn_s_mp_sqr.${OBJEXT} \
bn_s_mp_sub.${OBJEXT} \
bn_s_mp_toom_mul.${OBJEXT} \
bn_s_mp_toom_sqr.${OBJEXT}
| < < < > > | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
bn_s_mp_reverse.${OBJEXT} \
bn_s_mp_sqr_fast.${OBJEXT} \
bn_s_mp_sqr.${OBJEXT} \
bn_s_mp_sub.${OBJEXT} \
bn_s_mp_toom_mul.${OBJEXT} \
bn_s_mp_toom_sqr.${OBJEXT}
WIN_OBJS = \
tclWin32Dll.$(OBJEXT) \
tclWinChan.$(OBJEXT) \
tclWinConsole.$(OBJEXT) \
tclWinSerial.$(OBJEXT) \
tclWinError.$(OBJEXT) \
tclWinFCmd.$(OBJEXT) \
tclWinFile.$(OBJEXT) \
tclWinInit.$(OBJEXT) \
tclWinLoad.$(OBJEXT) \
tclWinNotify.$(OBJEXT) \
tclWinPipe.$(OBJEXT) \
tclWinSock.$(OBJEXT) \
tclWinThrd.$(OBJEXT) \
tclWinTime.$(OBJEXT)
DDE_OBJS = tclWinDde.$(OBJEXT)
REG_OBJS = tclWinReg.$(OBJEXT)
STUB_OBJS = \
tclStubLib.$(OBJEXT) \
tclStubCall.$(OBJEXT) \
tclStubLibTbl.$(OBJEXT) \
tclTomMathStubLib.$(OBJEXT) \
tclOOStubLib.$(OBJEXT) \
|
| ︙ | ︙ | |||
500 501 502 503 504 505 506 | inffast.$(OBJEXT) \ inflate.$(OBJEXT) \ inftrees.$(OBJEXT) \ trees.$(OBJEXT) \ uncompr.$(OBJEXT) \ zutil.$(OBJEXT) | | | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
inffast.$(OBJEXT) \
inflate.$(OBJEXT) \
inftrees.$(OBJEXT) \
trees.$(OBJEXT) \
uncompr.$(OBJEXT) \
zutil.$(OBJEXT)
TCL_OBJS = ${GENERIC_OBJS} ${WIN_OBJS} @ZLIB_OBJS@ @TOMMATH_OBJS@
TCL_DOCS = "$(ROOT_DIR_NATIVE)"/doc/*.[13n]
all: binaries libraries doc packages
# Test-suite helper (can be used to test Tcl from build directory with all expected modules).
# To start from windows shell use:
|
| ︙ | ︙ | |||
537 538 539 540 541 542 543 | echo '"$$BDP/$(TEST_EXE_FILE)" "$(ROOT_DIR_WIN_NATIVE)/tests/all.tcl" $$TESTFLAGS -load "$(TEST_LOAD_PRMS)" "$$@"'; \ ) > tcltest.sh; tcltest.sh: tcltest.cmd tcltest: binaries $(TEST_EXE_FILE) $(TEST_DLL_FILE) $(CAT32) tcltest.cmd | < < < < < < < < | | > > > | | > > | | > > > > > > > > > > > > > > > | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
echo '"$$BDP/$(TEST_EXE_FILE)" "$(ROOT_DIR_WIN_NATIVE)/tests/all.tcl" $$TESTFLAGS -load "$(TEST_LOAD_PRMS)" "$$@"'; \
) > tcltest.sh;
tcltest.sh: tcltest.cmd
tcltest: binaries $(TEST_EXE_FILE) $(TEST_DLL_FILE) $(CAT32) tcltest.cmd
binaries: $(TCL_STUB_LIB_FILE) @LIBRARIES@ winextensions ${TCL_ZIP_FILE} $(TCLSH)
winextensions: ${DDE_DLL_FILE} ${REG_DLL_FILE} ${DDE_DLL_FILE8} ${REG_DLL_FILE8}
libraries:
doc:
tclzipfile: ${TCL_ZIP_FILE}
${TCL_ZIP_FILE}: ${ZIP_INSTALL_OBJS} ${DDE_DLL_FILE} ${REG_DLL_FILE}
@rm -rf ${TCL_VFS_ROOT}
@mkdir -p ${TCL_VFS_PATH}
@echo "creating ${TCL_VFS_PATH} (prepare compression)"
@( \
$(COPY) -a $(TOP_DIR)/library/* ${TCL_VFS_PATH}; \
$(COPY) -a ${TCL_VFS_PATH}/manifest.txt ${TCL_VFS_PATH}/pkgIndex.tcl; \
rm -rf ${TCL_VFS_PATH}/dde; \
rm -rf ${TCL_VFS_PATH}/registry; \
)
(zip=`(realpath '${NATIVE_ZIP}' || readlink -m '${NATIVE_ZIP}') 2>/dev/null || \
(echo '${NATIVE_ZIP}' | sed "s?^\./?$$(pwd)/?")`; \
cd '${TCL_VFS_ROOT}' && \
$$zip ${ZIP_PROG_OPTIONS} ../${TCL_ZIP_FILE} ${ZIP_PROG_VFSSEARCH} >/dev/null && \
echo "${TCL_ZIP_FILE} successful created with $$zip" && \
cd ..)
$(TCLSH): $(TCLSH_OBJS) @LIBRARIES@ $(TCL_STUB_LIB_FILE) tclsh.$(RES) ${TCL_ZIP_FILE}
$(CC) $(CFLAGS) $(TCLSH_OBJS) $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) $(LIBS) \
tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE)
$(COPY) tclsh.exe.manifest $(TCLSH).manifest
@VC_MANIFEST_EMBED_EXE@
@if test "${ZIPFS_BUILD}" = "2" ; then \
cat ${TCL_ZIP_FILE} >> ${TCLSH}; \
fi
cat32.$(OBJEXT): cat.c
$(CC) -c $(CC_SWITCHES) -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
$(CAT32): cat32.$(OBJEXT)
$(CC) $(CFLAGS) cat32.$(OBJEXT) $(CC_EXENAME) $(LIBS) $(LDFLAGS_CONSOLE)
# The following targets are configured by autoconf to generate either a shared
# library or static library
${TCL_STUB_LIB_FILE}: ${STUB_OBJS} ${DDE_OBJS} ${REG_OBJS}
@$(RM) ${TCL_STUB_LIB_FILE}
@MAKE_STUB_LIB@ ${STUB_OBJS} ${DDE_OBJS} ${REG_OBJS}
@POST_MAKE_LIB@
${TCL_DLL_FILE}: ${TCL_LIB_FILE} ${TCL_OBJS} tcl.$(RES) @ZLIB_DLL_FILE@ @TOMMATH_DLL_FILE@ ${TCL_ZIP_FILE}
@$(RM) ${TCL_DLL_FILE} $(TCL_LIB_FILE)
@MAKE_DLL@ ${TCL_OBJS} tcl.$(RES) $(SHLIB_LD_LIBS)
$(COPY) tclsh.exe.manifest ${TCL_DLL_FILE}.manifest
@VC_MANIFEST_EMBED_DLL@
@if test "${ZIPFS_BUILD}" = "1" ; then \
cat ${TCL_ZIP_FILE} >> ${TCL_DLL_FILE}; \
fi
ifeq (,$(findstring --disable-shared,$(PKG_CFG_ARGS)))
${TCL_LIB_FILE}:
@$(RM) ${TCL_DLL_FILE} $(TCL_LIB_FILE)
else
${TCL_LIB_FILE}: ${TCL_OBJS} tclWinPanic.$(OBJEXT) ${DDE_OBJS} ${REG_OBJS}
@$(RM) ${TCL_LIB_FILE}
@MAKE_LIB@ ${TCL_OBJS} tclWinPanic.$(OBJEXT) ${DDE_OBJS} ${REG_OBJS}
@POST_MAKE_LIB@
endif
${DDE_DLL_FILE}: ${TCL_STUB_LIB_FILE} ${DDE_OBJS}
@MAKE_DLL@ ${DDE_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
$(COPY) tclsh.exe.manifest ${DDE_DLL_FILE}.manifest
${REG_DLL_FILE}: ${TCL_STUB_LIB_FILE} ${REG_OBJS}
@MAKE_DLL@ ${REG_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
$(COPY) tclsh.exe.manifest ${REG_DLL_FILE}.manifest
${DDE_DLL_FILE8}: ${TCL_STUB_LIB_FILE} tcl8WinDde.$(OBJEXT)
@MAKE_DLL@ tcl8WinDde.$(OBJEXT) $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
$(COPY) tclsh.exe.manifest ${DDE_DLL_FILE8}.manifest
${REG_DLL_FILE8}: ${TCL_STUB_LIB_FILE} tcl8WinReg.$(OBJEXT)
@MAKE_DLL@ -DTCL_MAJOR_VERSION=8 tcl8WinReg.$(OBJEXT) $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
$(COPY) tclsh.exe.manifest ${REG_DLL_FILE8}.manifest
${TEST_DLL_FILE}: ${TCL_STUB_LIB_FILE} ${TCLTEST_OBJS}
@$(RM) ${TEST_DLL_FILE} ${TEST_LIB_FILE}
@MAKE_DLL@ ${TCLTEST_OBJS} $(TCL_STUB_LIB_FILE) $(SHLIB_LD_LIBS)
$(COPY) tclsh.exe.manifest ${TEST_DLL_FILE}.manifest
${TEST_EXE_FILE}: @LIBRARIES@ ${TCL_STUB_LIB_FILE} ${TCLTEST_OBJS} tclTestMain.${OBJEXT}
@$(RM) ${TEST_EXE_FILE}
$(CC) $(CFLAGS) $(TCLTEST_OBJS) tclTestMain.$(OBJEXT) $(TCL_LIB_FILE) $(TCL_STUB_LIB_FILE) $(LIBS) \
tclsh.$(RES) $(CC_EXENAME) $(LDFLAGS_CONSOLE)
$(COPY) tclsh.exe.manifest ${TEST_EXE_FILE}.manifest
# use prebuilt zlib1.dll
${ZLIB_DLL_FILE}: ${TCL_STUB_LIB_FILE}
@if test "@ZLIB_LIBS@set" = "${ZLIB_DIR_NATIVE}/win64-arm/zdll.libset" ; then \
$(COPY) $(ZLIB_DIR)/win64-arm/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
elif test "@ZLIB_LIBS@set" = "${ZLIB_DIR_NATIVE}/win64-arm/libz.dll.aset" ; then \
$(COPY) $(ZLIB_DIR)/win64-arm/${ZLIB_DLL_FILE} ${ZLIB_DLL_FILE}; \
|
| ︙ | ︙ | |||
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 |
tclWinInit.${OBJEXT}: tclWinInit.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinPipe.${OBJEXT}: tclWinPipe.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinDde.${OBJEXT}: tclWinDde.c
$(CC) -c $(CC_SWITCHES) $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tcl8WinDde.${OBJEXT}: tclWinDde.c
$(CC) -o $@ -c $(CC_SWITCHES) -DTCL_MAJOR_VERSION=8 $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclAppInit.${OBJEXT}: tclAppInit.c
$(CC) -c $(CC_SWITCHES) $(EXTFLAGS) -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
tclMainW.${OBJEXT}: tclMain.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
# TIP #430, ZipFS Support
tclZipfs.${OBJEXT}: $(GENERIC_DIR)/tclZipfs.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl \
$(ZLIB_INCLUDE) -I$(MINIZIP_DIR_NATIVE) @DEPARG@ $(CC_OBJNAME)
| > > > > > > < < | 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 |
tclWinInit.${OBJEXT}: tclWinInit.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinPipe.${OBJEXT}: tclWinPipe.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinReg.${OBJEXT}: tclWinReg.c
$(CC) -c $(CC_SWITCHES) $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tcl8WinReg.${OBJEXT}: tclWinReg.c
$(CC) -o $@ -c $(CC_SWITCHES) -DTCL_MAJOR_VERSION=8 $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclWinDde.${OBJEXT}: tclWinDde.c
$(CC) -c $(CC_SWITCHES) $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tcl8WinDde.${OBJEXT}: tclWinDde.c
$(CC) -o $@ -c $(CC_SWITCHES) -DTCL_MAJOR_VERSION=8 $(EXTFLAGS) @DEPARG@ $(CC_OBJNAME)
tclAppInit.${OBJEXT}: tclAppInit.c
$(CC) -c $(CC_SWITCHES) $(EXTFLAGS) -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
tclMainW.${OBJEXT}: tclMain.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl -DUNICODE -D_UNICODE @DEPARG@ $(CC_OBJNAME)
# TIP #430, ZipFS Support
tclZipfs.${OBJEXT}: $(GENERIC_DIR)/tclZipfs.c
$(CC) -c $(CC_SWITCHES) -DBUILD_tcl \
$(ZLIB_INCLUDE) -I$(MINIZIP_DIR_NATIVE) @DEPARG@ $(CC_OBJNAME)
# TIP #59, embedding of configuration information into the binary library.
#
# Part of Tcl's configuration information are the paths where it was installed
# and where it will look for its libraries (which can be different). We derive
# this information from the variables which can be overridden by the user. As
# every path can be configured separately we do not remember one general
|
| ︙ | ︙ | |||
706 707 708 709 710 711 712 | -DCFG_RUNTIME_LIBDIR="\"$(libdir_native)\"" \ -DCFG_RUNTIME_BINDIR="\"$(bindir_native)\"" \ -DCFG_RUNTIME_SCRDIR="\"$(TCL_LIBRARY_NATIVE)\"" \ -DCFG_RUNTIME_INCDIR="\"$(includedir_native)\"" \ -DCFG_RUNTIME_DOCDIR="\"$(mandir_native)\"" \ -DCFG_RUNTIME_DLLFILE="\"$(TCL_DLL_FILE)\"" \ -DBUILD_tcl \ | < < < < < < < < < < | 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
-DCFG_RUNTIME_LIBDIR="\"$(libdir_native)\"" \
-DCFG_RUNTIME_BINDIR="\"$(bindir_native)\"" \
-DCFG_RUNTIME_SCRDIR="\"$(TCL_LIBRARY_NATIVE)\"" \
-DCFG_RUNTIME_INCDIR="\"$(includedir_native)\"" \
-DCFG_RUNTIME_DOCDIR="\"$(mandir_native)\"" \
-DCFG_RUNTIME_DLLFILE="\"$(TCL_DLL_FILE)\"" \
-DBUILD_tcl \
@DEPARG@ $(CC_OBJNAME)
# tclDate.h dependencies:
tclClock.${OBJEXT}: tclClock.c tclDate.h
tclClockFmt.${OBJEXT}: tclClockFmt.c tclDate.h
tclDate.${OBJEXT}: tclDate.c tclDate.h
|
| ︙ | ︙ | |||
856 857 858 859 860 861 862 | if [ ! -d "$$i" ] ; then \ echo "Making directory $$i"; \ $(MKDIR) "$$i"; \ chmod 755 "$$i"; \ else true; \ fi; \ done; | | | 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 |
if [ ! -d "$$i" ] ; then \
echo "Making directory $$i"; \
$(MKDIR) "$$i"; \
chmod 755 "$$i"; \
else true; \
fi; \
done;
@for i in dde${DDEDOTVER} registry${REGDOTVER}; \
do \
if [ ! -d "$(LIB_INSTALL_DIR)/$$i" ] ; then \
echo "Making directory $(LIB_INSTALL_DIR)/$$i"; \
$(MKDIR) "$(LIB_INSTALL_DIR)/$$i"; \
else true; \
fi; \
done;
|
| ︙ | ︙ | |||
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 |
done
@if [ -f $(DDE_DLL_FILE) ]; then \
echo Installing $(DDE_DLL_FILE); \
$(COPY) $(DDE_DLL_FILE) "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
$(COPY) $(ROOT_DIR)/library/dde/pkgIndex.tcl \
"$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
fi
@if [ -f $(DDE_LIB_FILE) ]; then \
echo Installing $(DDE_LIB_FILE); \
$(COPY) $(DDE_LIB_FILE) "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
fi
@echo "Installing pkg-config file to $(LIB_INSTALL_DIR)/pkgconfig/"
@$(INSTALL_DATA_DIR) "$(LIB_INSTALL_DIR)/pkgconfig"
@$(INSTALL_DATA) tcl.pc "$(LIB_INSTALL_DIR)/pkgconfig/tcl.pc"
install-libraries: libraries
@for i in "$(prefix)/lib" "$(INCLUDE_INSTALL_DIR)" \
"$(SCRIPT_INSTALL_DIR)" "$(MODULE_INSTALL_DIR)"; \
| > > > > > > > > > > > > > > > > > > | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 |
done
@if [ -f $(DDE_DLL_FILE) ]; then \
echo Installing $(DDE_DLL_FILE); \
$(COPY) $(DDE_DLL_FILE) "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
$(COPY) $(ROOT_DIR)/library/dde/pkgIndex.tcl \
"$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
fi
@if [ -f $(DDE_DLL_FILE8) ]; then \
echo Installing $(DDE_DLL_FILE8); \
$(COPY) $(DDE_DLL_FILE8) "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
fi
@if [ -f $(DDE_LIB_FILE) ]; then \
echo Installing $(DDE_LIB_FILE); \
$(COPY) $(DDE_LIB_FILE) "$(LIB_INSTALL_DIR)/dde${DDEDOTVER}"; \
fi
@if [ -f $(REG_DLL_FILE) ]; then \
echo Installing $(REG_DLL_FILE); \
$(COPY) $(REG_DLL_FILE) "$(LIB_INSTALL_DIR)/registry${REGDOTVER}"; \
$(COPY) $(ROOT_DIR)/library/registry/pkgIndex.tcl \
"$(LIB_INSTALL_DIR)/registry${REGDOTVER}"; \
fi
@if [ -f $(REG_DLL_FILE8) ]; then \
echo Installing $(REG_DLL_FILE8); \
$(COPY) $(REG_DLL_FILE8) "$(LIB_INSTALL_DIR)/registry${REGDOTVER}"; \
fi
@if [ -f $(REG_LIB_FILE) ]; then \
echo Installing $(REG_LIB_FILE); \
$(COPY) $(REG_LIB_FILE) "$(LIB_INSTALL_DIR)/registry${REGDOTVER}"; \
fi
@echo "Installing pkg-config file to $(LIB_INSTALL_DIR)/pkgconfig/"
@$(INSTALL_DATA_DIR) "$(LIB_INSTALL_DIR)/pkgconfig"
@$(INSTALL_DATA) tcl.pc "$(LIB_INSTALL_DIR)/pkgconfig/tcl.pc"
install-libraries: libraries
@for i in "$(prefix)/lib" "$(INCLUDE_INSTALL_DIR)" \
"$(SCRIPT_INSTALL_DIR)" "$(MODULE_INSTALL_DIR)"; \
|
| ︙ | ︙ | |||
922 923 924 925 926 927 928 | else true; \ fi; \ done; @echo "Installing library files to $(SCRIPT_INSTALL_DIR)"; @for i in $(ROOT_DIR)/library/*.tcl $(ROOT_DIR)/library/tclIndex; do \ $(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)"; \ done; | < < < < < < < < < < < < | | | | | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | else true; \ fi; \ done; @echo "Installing library files to $(SCRIPT_INSTALL_DIR)"; @for i in $(ROOT_DIR)/library/*.tcl $(ROOT_DIR)/library/tclIndex; do \ $(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)"; \ done; @echo "Installing package cookiejar 0.2" @for j in $(ROOT_DIR)/library/cookiejar/*.tcl \ $(ROOT_DIR)/library/cookiejar/*.gz; do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/cookiejar0.2"; \ done; @echo "Installing package http 2.10.2 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/http/http.tcl "$(MODULE_INSTALL_DIR)/9.0/http-2.10.2.tm"; @echo "Installing package opt 0.4.10"; @for j in $(ROOT_DIR)/library/opt/*.tcl; do \ $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/opt0.4"; \ done; @echo "Installing package msgcat 1.7.1 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/msgcat/msgcat.tcl "$(MODULE_INSTALL_DIR)/9.0/msgcat-1.7.1.tm"; @echo "Installing package tcltest 2.5.11 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/tcltest/tcltest.tcl "$(MODULE_INSTALL_DIR)/9.0/tcltest-2.5.11.tm"; @echo "Installing package platform 1.1.1 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/platform/platform.tcl "$(MODULE_INSTALL_DIR)/9.0/platform-1.1.1.tm"; @echo "Installing package platform::shell 1.1.4 as a Tcl Module"; @$(COPY) $(ROOT_DIR)/library/platform/shell.tcl "$(MODULE_INSTALL_DIR)/9.0/platform/shell-1.1.4.tm"; @echo "Installing encodings"; @for i in $(ROOT_DIR)/library/encoding/*.enc ; do \ $(COPY) "$$i" "$(SCRIPT_INSTALL_DIR)/encoding"; \ done; |
| ︙ | ︙ |
Changes to win/README.
|
| | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | Tcl 9.0 for Windows 1. Introduction --------------- This is the directory where you configure and compile the Windows version of Tcl. This directory also contains source files for Tcl that are specific to Microsoft Windows. The information in this file is maintained on the web at: https://www.tcl-lang.org/doc/howto/compile.html#win 2. Compiling Tcl ---------------- In order to compile Tcl for Windows, you need the following: Tcl 9.0 Source Distribution (plus any patches) and Visual Studio 2015 or newer or |
| ︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | (win32 or win64) or LLVM MinGW [https://github.com/mstorsjo/llvm-mingw/] (win32 or win64, IX86, AMD64 or ARM64) If you are building with Visual C++, in the "win" subdirectory of the source release, you will find "makefile.vc". This is the makefile for the Visual C++ compiler and uses the stock NMAKE tool. Detailed directions for using it, are in the comments of "makefile.vc". A quick example would be: C:\tcl_source\win\>nmake -f makefile.vc If you are building with Linux, Cygwin or Msys, you can use the configure script that lives in the win subdirectory. The Linux/Cygwin/Msys based configure/build process works just like the UNIX one, so you will want to refer to ../unix/README for available configure options. If you want 64-bit executables (x86_64), you need to configure using the --enable-64bit (or --enable-64bit=arm64) option. Make sure that the x86_64-w64-mingw32 (or aarch64-w64-mingw32) compiler is present. For Cygwin the x86_64 compiler can be found in the "mingw64-x86_64-gcc-core" package, which can be installed through the normal Cygwin install process. If you only want 32-bit executables, the "mingw64-i686-gcc-core" package is what you need. For Linux, Darwin and Msys, you can download a suitable win32 or win64 compiler from [https://sourceforge.net/projects/mingw-w64/files/] Use the Makefile "install" target to install Tcl. It will install it according to the prefix options you provided in the correct directory structure. | > > > > > > | | | > > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
(win32 or win64)
or
LLVM MinGW [https://github.com/mstorsjo/llvm-mingw/]
(win32 or win64, IX86, AMD64 or ARM64)
In practice, this release is built with Visual C++ 6.0 and the TEA
Makefile.
If you are building with Visual C++, in the "win" subdirectory of the
source release, you will find "makefile.vc". This is the makefile for the
Visual C++ compiler and uses the stock NMAKE tool. Detailed directions for
using it, are in the comments of "makefile.vc". A quick example would be:
C:\tcl_source\win\>nmake -f makefile.vc
There is also a Developer Studio workspace and project file, too, if you
would like to use them.
If you are building with Linux, Cygwin or Msys, you can use the configure
script that lives in the win subdirectory. The Linux/Cygwin/Msys based
configure/build process works just like the UNIX one, so you will want
to refer to ../unix/README for available configure options.
If you want 64-bit executables (x86_64), you need to configure using
the --enable-64bit (or --enable-64bit=arm64) option. Make sure that
the x86_64-w64-mingw32 (or aarch64-w64-mingw32) compiler is present.
For Cygwin the x86_64 compiler can be found in the
"mingw64-x86_64-gcc-core" package, which can be installed through
the normal Cygwin install process. If you only want 32-bit executables,
the "mingw64-i686-gcc-core" package is what you need. For Linux, Darwin
and Msys, you can download a suitable win32 or win64 compiler from
[https://sourceforge.net/projects/mingw-w64/files/]
Use the Makefile "install" target to install Tcl. It will install it
according to the prefix options you provided in the correct directory
structure.
Note that in order to run tclsh90.exe, you must ensure that tcl90.dll,
libtommath.dll and zlib1.dll are on your path, in the system
directory, or in the directory containing tclsh90.exe.
Note: Tcl no longer provides support for systems earlier than Windows 7.
You will also need the Windows Universal C runtime (UCRT):
[https://support.microsoft.com/en-us/topic/update-for-universal-c-runtime-in-windows-c0514201-7fe6-95a3-b0a5-287930f3560c]
3. Test suite
-------------
This distribution contains an extensive test suite for Tcl. Some of the
tests are timing dependent and will fail from time to time. If a test is
failing consistently, please send us a bug report with as much detail as
you can manage to our tracker:
https://core.tcl-lang.org/tcl/reportlist
In order to run the test suite, you build the "test" target using the
appropriate makefile for your compiler.
|
Changes to win/cat.c.
1 2 3 4 5 | /* * cat.c -- * * Program used when testing tclWinPipe.c * | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * cat.c -- * * Program used when testing tclWinPipe.c * * Copyright (c) 1996 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include <stdio.h> #include <io.h> #include <string.h> #include <tchar.h> |
| ︙ | ︙ |
Changes to win/configure.
1 2 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | | 1 2 3 4 5 6 7 8 9 10 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.73 for tcl 9.0. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation |
| ︙ | ︙ | |||
180 181 182 183 184 185 186 | test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && | | > | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else case e in #( e) as_have_required=no ;; esac fi |
| ︙ | ︙ | |||
580 581 582 583 584 585 586 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tcl' PACKAGE_TARNAME='tcl' | | | > | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='tcl' PACKAGE_TARNAME='tcl' PACKAGE_VERSION='9.0' PACKAGE_STRING='tcl 9.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="../generic/tcl.h" ac_subst_vars='LTLIBOBJS LIBOBJS RES RC_DEFINES RC_DEFINE RC_INCLUDE RC_TYPE RC_OUT TCL_REG_MINOR_VERSION TCL_REG_MAJOR_VERSION TCL_REG_VERSION TCL_DDE_MINOR_VERSION TCL_DDE_MAJOR_VERSION TCL_DDE_VERSION TCL_PACKAGE_PATH TCL_BUILD_LIB_SPEC MAKE_EXE MAKE_DLL |
| ︙ | ︙ | |||
654 655 656 657 658 659 660 661 662 663 664 665 666 667 | PKG_CFG_ARGS TCL_PATCH_LEVEL TCL_MINOR_VERSION TCL_MAJOR_VERSION TCL_VERSION MACHINE TCL_WIN_VERSION LDFLAGS_DEFAULT CFLAGS_DEFAULT INSTALL_TZDATA INSTALL_MSGS INSTALL_LIBRARIES TCL_ZIP_FILE ZIPFS_BUILD | > > > | 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 | PKG_CFG_ARGS TCL_PATCH_LEVEL TCL_MINOR_VERSION TCL_MAJOR_VERSION TCL_VERSION MACHINE TCL_WIN_VERSION VC_MANIFEST_EMBED_EXE VC_MANIFEST_EMBED_DLL CPP LDFLAGS_DEFAULT CFLAGS_DEFAULT INSTALL_TZDATA INSTALL_MSGS INSTALL_LIBRARIES TCL_ZIP_FILE ZIPFS_BUILD |
| ︙ | ︙ | |||
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 |
enable_option_checking
with_encoding
enable_shared
enable_64bit
enable_zipfs
with_tzdata
enable_symbols
'
ac_precious_vars='build_alias
host_alias
target_alias
CC
CFLAGS
LDFLAGS
LIBS
| > | > | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 |
enable_option_checking
with_encoding
enable_shared
enable_64bit
enable_zipfs
with_tzdata
enable_symbols
enable_embedded_manifest
'
ac_precious_vars='build_alias
host_alias
target_alias
CC
CFLAGS
LDFLAGS
LIBS
CPPFLAGS
CPP'
# Initialize some variables set by options.
ac_init_help=
ac_init_version=false
ac_unrecognized_opts=
ac_unrecognized_sep=
|
| ︙ | ︙ | |||
1301 1302 1303 1304 1305 1306 1307 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF | | | 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF 'configure' configures tcl 9.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. |
| ︙ | ︙ | |||
1363 1364 1365 1366 1367 1368 1369 | cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in | | > > > | 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 |
cat <<\_ACEOF
_ACEOF
fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of tcl 9.0:";;
esac
cat <<\_ACEOF
Optional Features:
--disable-option-checking ignore unrecognized --enable/--with options
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-shared build and link with shared libraries (default: on)
--enable-64bit enable 64bit support (where applicable)
--enable-zipfs build with Zipfs support (default: on)
--enable-symbols build with debugging symbols (default: off)
--enable-embedded-manifest
embed manifest if possible (default: yes)
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-encoding encoding for configuration values
--with-tzdata install timezone data (default: yes)
Some influential environment variables:
CC C compiler command
CFLAGS C compiler flags
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
LIBS libraries to pass to the linker, e.g. -l<library>
CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
CPP C preprocessor
Use these variables to override the choices made by 'configure' or to help
it to find libraries and programs with nonstandard names/locations.
Report bugs to the package provider.
_ACEOF
ac_status=$?
|
| ︙ | ︙ | |||
1458 1459 1460 1461 1462 1463 1464 |
cd "$ac_pwd" || { ac_status=$?; break; }
done
fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
| | | 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 |
cd "$ac_pwd" || { ac_status=$?; break; }
done
fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
tcl configure 9.0
generated by GNU Autoconf 2.73
Copyright (C) 2026 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
exit
|
| ︙ | ︙ | |||
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 |
fi
eval ac_res=\$$3
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf '%s\n' "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_type
ac_configure_args_raw=
for ac_arg
do
case $ac_arg in
*\'*)
ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 |
fi
eval ac_res=\$$3
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf '%s\n' "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_type
# ac_fn_c_try_cpp LINENO
# ----------------------
# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
ac_fn_c_try_cpp ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if { { ac_try="$ac_cpp conftest.$ac_ext"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
printf '%s\n' "$ac_try_echo"; } >&5
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
grep -v '^ *+' conftest.err >conftest.er1
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } > conftest.i && {
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
test ! -s conftest.err
}
then :
ac_retval=0
else case e in #(
e) printf '%s\n' "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1 ;;
esac
fi
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
as_fn_set_status $ac_retval
} # ac_fn_c_try_cpp
ac_configure_args_raw=
for ac_arg
do
case $ac_arg in
*\'*)
ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
|
| ︙ | ︙ | |||
1642 1643 1644 1645 1646 1647 1648 |
ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
esac
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
| | | 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 |
ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
esac
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by tcl $as_me 9.0, which was
generated by GNU Autoconf 2.73. Invocation command line was
$ $0$ac_configure_args_raw
_ACEOF
exec 5>>config.log
{
|
| ︙ | ︙ | |||
2450 2451 2452 2453 2454 2455 2456 | # The following define is needed when building with Cygwin since newer # versions of autoconf incorrectly set SHELL to /bin/bash instead of # /bin/sh. The bash shell seems to suffer from some strange failures. SHELL=/bin/sh | | | | | | > | > | 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 | # The following define is needed when building with Cygwin since newer # versions of autoconf incorrectly set SHELL to /bin/bash instead of # /bin/sh. The bash shell seems to suffer from some strange failures. SHELL=/bin/sh TCL_VERSION=9.0 TCL_MAJOR_VERSION=9 TCL_MINOR_VERSION=0 TCL_PATCH_LEVEL=".5" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.4 TCL_DDE_MAJOR_VERSION=1 TCL_DDE_MINOR_VERSION=4 DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION TCL_REG_VERSION=1.3 TCL_REG_MAJOR_VERSION=1 TCL_REG_MINOR_VERSION=3 REGVER=$TCL_REG_MAJOR_VERSION$TCL_REG_MINOR_VERSION PKG_CFG_ARGS=$@ #------------------------------------------------------------------------ # Empty slate for bundled packages, to avoid stale configuration #------------------------------------------------------------------------ rm -Rf pkgs |
| ︙ | ︙ | |||
4461 4462 4463 4464 4465 4466 4467 |
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking compiler flags" >&5
printf %s "checking compiler flags... " >&6; }
if test "${GCC}" = "yes" ; then
SHLIB_LD=""
SHLIB_LD_LIBS='${LIBS}'
LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32"
# mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't
| | | 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 |
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking compiler flags" >&5
printf %s "checking compiler flags... " >&6; }
if test "${GCC}" = "yes" ; then
SHLIB_LD=""
SHLIB_LD_LIBS='${LIBS}'
LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32"
# mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't
LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32 -lwinspool"
STLIB_LD='${AR} cr'
RC_OUT=-o
RC_TYPE=
RC_INCLUDE=--include
RC_DEFINE=--define
RES=res.o
MAKE_LIB="\${STLIB_LD} \$@"
|
| ︙ | ︙ | |||
4675 4676 4677 4678 4679 4680 4681 |
CFLAGS_DEBUG="-nologo -Z7 -Od -WX ${runtime}d"
# -O2 - create fast code (/Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy)
CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}"
lflags="${lflags} -nologo"
LINKBIN="link"
fi
| | | 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 |
CFLAGS_DEBUG="-nologo -Z7 -Od -WX ${runtime}d"
# -O2 - create fast code (/Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy)
CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}"
lflags="${lflags} -nologo"
LINKBIN="link"
fi
LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib comctl32.lib shell32.lib uuid.lib winspool.lib"
SHLIB_LD="${LINKBIN} -dll -incremental:no ${lflags}"
SHLIB_LD_LIBS='${LIBS}'
# link -lib only works when -lib is the first arg
STLIB_LD="${LINKBIN} -lib ${lflags}"
RC_OUT=-fo
RC_TYPE=-r
|
| ︙ | ︙ | |||
4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 |
if test "$do64bit" != "no" ; then
printf '%s\n' "#define TCL_CFG_DO64BIT 1" >>confdefs.h
fi
if test "${GCC}" = "yes" ; then
#
# Check to see if the excpt.h include file provided contains the
# definition for EXCEPTION_DISPOSITION; if not, which is the case
# with Cygwin's version as of 2002-04-10, define it to be int,
# sufficient for getting the current code to work.
#
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for EXCEPTION_DISPOSITION support in include files" >&5
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 |
if test "$do64bit" != "no" ; then
printf '%s\n' "#define TCL_CFG_DO64BIT 1" >>confdefs.h
fi
if test "${GCC}" = "yes" ; then
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for SEH support in compiler" >&5
printf %s "checking for SEH support in compiler... " >&6; }
if test ${tcl_cv_seh+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) if test "$cross_compiling" = yes
then :
tcl_cv_seh=no
else case e in #(
e)
# ac_fn_c_try_run LINENO
# ----------------------
# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
# executables *can* be run.
ac_fn_c_try_run ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
printf '%s\n' "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
{ { case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
printf '%s\n' "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }
then :
ac_retval=0
else case e in #(
e) printf '%s\n' "$as_me: program exited with status $ac_status" >&5
printf '%s\n' "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=$ac_status ;;
esac
fi
rm -rf conftest.dSYM conftest_ipa8_conftest.oo
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
as_fn_set_status $ac_retval
} # ac_fn_c_try_run
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
int main(int argc, char** argv) {
int a, b = 0;
__try {
a = 666 / b;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return 0;
}
return 1;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"
then :
tcl_cv_seh=yes
else case e in #(
e) tcl_cv_seh=no ;;
esac
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
esac
fi
;;
esac
fi
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_seh" >&5
printf '%s\n' "$tcl_cv_seh" >&6; }
if test "$tcl_cv_seh" = "no" ; then
printf '%s\n' "#define HAVE_NO_SEH 1" >>confdefs.h
fi
#
# Check to see if the excpt.h include file provided contains the
# definition for EXCEPTION_DISPOSITION; if not, which is the case
# with Cygwin's version as of 2002-04-10, define it to be int,
# sufficient for getting the current code to work.
#
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for EXCEPTION_DISPOSITION support in include files" >&5
|
| ︙ | ︙ | |||
5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 |
printf '%s\n' "enabled symbols mem compile debugging" >&6; }
else
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5
printf '%s\n' "enabled $tcl_ok debugging" >&6; }
fi
fi
#------------------------------------------------------------------------
# tclConfig.sh refers to this by a different name
#------------------------------------------------------------------------
TCL_SHARED_BUILD=${SHARED_BUILD}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 |
printf '%s\n' "enabled symbols mem compile debugging" >&6; }
else
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: enabled $tcl_ok debugging" >&5
printf '%s\n' "enabled $tcl_ok debugging" >&6; }
fi
fi
#--------------------------------------------------------------------
# Embed the manifest if we can determine how
#--------------------------------------------------------------------
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
printf %s "checking how to run the C preprocessor... " >&6; }
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
if test ${ac_cv_prog_CPP+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) # Double quotes because $CC needs to be expanded
for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp
do
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <limits.h>
Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"
then :
else case e in #(
e) # Broken: fails on valid input.
continue ;;
esac
fi
rm -f conftest.err conftest.i conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"
then :
# Broken: success on invalid input.
continue
else case e in #(
e) # Passes both tests.
ac_preproc_ok=:
break ;;
esac
fi
rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
if $ac_preproc_ok
then :
break
fi
done
ac_cv_prog_CPP=$CPP
;;
esac
fi
CPP=$ac_cv_prog_CPP
else
ac_cv_prog_CPP=$CPP
fi
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
printf '%s\n' "$CPP" >&6; }
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <limits.h>
Syntax error
_ACEOF
if ac_fn_c_try_cpp "$LINENO"
then :
else case e in #(
e) # Broken: fails on valid input.
continue ;;
esac
fi
rm -f conftest.err conftest.i conftest.$ac_ext
# OK, works on sane cases. Now check whether nonexistent headers
# can be detected and how.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
if ac_fn_c_try_cpp "$LINENO"
then :
# Broken: success on invalid input.
continue
else case e in #(
e) # Passes both tests.
ac_preproc_ok=:
break ;;
esac
fi
rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
if $ac_preproc_ok
then :
else case e in #(
e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;}
as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
See 'config.log' for more details" "$LINENO" 5; } ;;
esac
fi
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep -e" >&5
printf %s "checking for egrep -e... " >&6; }
if test ${ac_cv_path_EGREP_TRADITIONAL+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) if test -z "$EGREP_TRADITIONAL"; then
ac_path_EGREP_TRADITIONAL_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
case $as_dir in #(((
'') as_dir=./ ;;
*/) ;;
*) as_dir=$as_dir/ ;;
esac
for ac_prog in grep ggrep
do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext"
as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue
# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found.
# Check for GNU $ac_path_EGREP_TRADITIONAL
case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #(
*GNU*)
ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;;
#(
*)
ac_count=0
printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
printf '%s\n' 'EGREP_TRADITIONAL' >> "conftest.nl"
"$ac_path_EGREP_TRADITIONAL" -E 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
as_fn_arith $ac_count + 1 && ac_count=$as_val
if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then
# Best one so far, save it but keep looking for a better one
ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL"
ac_path_EGREP_TRADITIONAL_max=$ac_count
fi
# 10*(2^10) chars as input seems more than enough
test $ac_count -gt 10 && break
done
rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac
$ac_path_EGREP_TRADITIONAL_found && break 3
done
done
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then
:
fi
else
ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL
fi
if test "$ac_cv_path_EGREP_TRADITIONAL"
then :
ac_cv_path_EGREP_TRADITIONAL="$ac_cv_path_EGREP_TRADITIONAL -E"
else case e in #(
e) if test -z "$EGREP_TRADITIONAL"; then
ac_path_EGREP_TRADITIONAL_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
do
IFS=$as_save_IFS
case $as_dir in #(((
'') as_dir=./ ;;
*/) ;;
*) as_dir=$as_dir/ ;;
esac
for ac_prog in egrep
do
for ac_exec_ext in '' $ac_executable_extensions; do
ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext"
as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue
# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found.
# Check for GNU $ac_path_EGREP_TRADITIONAL
case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #(
*GNU*)
ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;;
#(
*)
ac_count=0
printf %s 0123456789 >"conftest.in"
while :
do
cat "conftest.in" "conftest.in" >"conftest.tmp"
mv "conftest.tmp" "conftest.in"
cp "conftest.in" "conftest.nl"
printf '%s\n' 'EGREP_TRADITIONAL' >> "conftest.nl"
"$ac_path_EGREP_TRADITIONAL" 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
as_fn_arith $ac_count + 1 && ac_count=$as_val
if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then
# Best one so far, save it but keep looking for a better one
ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL"
ac_path_EGREP_TRADITIONAL_max=$ac_count
fi
# 10*(2^10) chars as input seems more than enough
test $ac_count -gt 10 && break
done
rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
esac
$ac_path_EGREP_TRADITIONAL_found && break 3
done
done
done
IFS=$as_save_IFS
if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then
as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
fi
else
ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL
fi
;;
esac
fi ;;
esac
fi
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP_TRADITIONAL" >&5
printf '%s\n' "$ac_cv_path_EGREP_TRADITIONAL" >&6; }
EGREP_TRADITIONAL=$ac_cv_path_EGREP_TRADITIONAL
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to embed manifest" >&5
printf %s "checking whether to embed manifest... " >&6; }
# Check whether --enable-embedded-manifest was given.
if test ${enable_embedded_manifest+y}
then :
enableval=$enable_embedded_manifest; embed_ok=$enableval
else case e in #(
e) embed_ok=yes ;;
esac
fi
VC_MANIFEST_EMBED_DLL=
VC_MANIFEST_EMBED_EXE=
result=no
if test "$embed_ok" = "yes" -a "${SHARED_BUILD}" = "1" \
-a "$GCC" != "yes" ; then
# Add the magic to embed the manifest into the dll/exe
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#if defined(_MSC_VER) && _MSC_VER >= 1400
print("manifest needed")
#endif
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP_TRADITIONAL "manifest needed" >/dev/null 2>&1
then :
# Could do a CHECK_PROG for mt, but should always be with MSVC8+
# Could add 'if test -f' check, but manifest should be created
# in this compiler case
# Add in a manifest argument that may be specified
# XXX Needs improvement so that the test for existence accounts
# XXX for a provided (known) manifest
VC_MANIFEST_EMBED_DLL="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;2 ; fi"
VC_MANIFEST_EMBED_EXE="if test -f \$@.manifest ; then mt.exe -nologo -manifest \$@.manifest -outputresource:\$@\;1 ; fi"
result=yes
if test "x" != x ; then
result="yes ()"
fi
fi
rm -rf conftest*
fi
{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $result" >&5
printf '%s\n' "$result" >&6; }
#------------------------------------------------------------------------
# tclConfig.sh refers to this by a different name
#------------------------------------------------------------------------
TCL_SHARED_BUILD=${SHARED_BUILD}
|
| ︙ | ︙ | |||
5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 | # win only | > | 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 | # win only |
| ︙ | ︙ | |||
6151 6152 6153 6154 6155 6156 6157 | test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" | | | 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 | test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by tcl $as_me 9.0, which was generated by GNU Autoconf 2.73. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ |
| ︙ | ︙ | |||
6206 6207 6208 6209 6210 6211 6212 | _ACEOF ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ | | | 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 | _ACEOF ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ tcl config.status 9.0 configured by $0, generated by GNU Autoconf 2.73, with options \\"\$ac_cs_config\\" Copyright (C) 2026 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." |
| ︙ | ︙ |
Changes to win/configure.ac.
1 2 3 4 5 | #! /bin/bash -norc # This file is an input file used by the GNU "autoconf" program to # generate the file "configure", which is run during Tcl installation # to configure the system for the local environment. | | | | | | | | > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #! /bin/bash -norc # This file is an input file used by the GNU "autoconf" program to # generate the file "configure", which is run during Tcl installation # to configure the system for the local environment. AC_INIT([tcl],[9.0]) AC_CONFIG_SRCDIR([../generic/tcl.h]) AC_PREREQ([2.69]) # The following define is needed when building with Cygwin since newer # versions of autoconf incorrectly set SHELL to /bin/bash instead of # /bin/sh. The bash shell seems to suffer from some strange failures. SHELL=/bin/sh TCL_VERSION=9.0 TCL_MAJOR_VERSION=9 TCL_MINOR_VERSION=0 TCL_PATCH_LEVEL=".5" VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION TCL_DDE_VERSION=1.4 TCL_DDE_MAJOR_VERSION=1 TCL_DDE_MINOR_VERSION=4 DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION TCL_REG_VERSION=1.3 TCL_REG_MAJOR_VERSION=1 TCL_REG_MINOR_VERSION=3 REGVER=$TCL_REG_MAJOR_VERSION$TCL_REG_MINOR_VERSION PKG_CFG_ARGS=$@ #------------------------------------------------------------------------ # Empty slate for bundled packages, to avoid stale configuration #------------------------------------------------------------------------ rm -Rf pkgs |
| ︙ | ︙ | |||
338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols
# option. This macro depends on C flags, and should be called
# after SC_CONFIG_CFLAGS macro is called.
#--------------------------------------------------------------------
SC_ENABLE_SYMBOLS
#------------------------------------------------------------------------
# tclConfig.sh refers to this by a different name
#------------------------------------------------------------------------
TCL_SHARED_BUILD=${SHARED_BUILD}
| > > > > > > | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols
# option. This macro depends on C flags, and should be called
# after SC_CONFIG_CFLAGS macro is called.
#--------------------------------------------------------------------
SC_ENABLE_SYMBOLS
#--------------------------------------------------------------------
# Embed the manifest if we can determine how
#--------------------------------------------------------------------
SC_EMBED_MANIFEST
#------------------------------------------------------------------------
# tclConfig.sh refers to this by a different name
#------------------------------------------------------------------------
TCL_SHARED_BUILD=${SHARED_BUILD}
|
| ︙ | ︙ | |||
491 492 493 494 495 496 497 498 499 500 501 502 503 504 | AC_SUBST(TCL_BUILD_LIB_SPEC) AC_SUBST(TCL_PACKAGE_PATH) # win only AC_SUBST(TCL_DDE_VERSION) AC_SUBST(TCL_DDE_MAJOR_VERSION) AC_SUBST(TCL_DDE_MINOR_VERSION) AC_SUBST(TCL_REG_MAJOR_VERSION) AC_SUBST(TCL_REG_MINOR_VERSION) AC_SUBST(RC) AC_SUBST(RC_OUT) AC_SUBST(RC_TYPE) AC_SUBST(RC_INCLUDE) | > | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | AC_SUBST(TCL_BUILD_LIB_SPEC) AC_SUBST(TCL_PACKAGE_PATH) # win only AC_SUBST(TCL_DDE_VERSION) AC_SUBST(TCL_DDE_MAJOR_VERSION) AC_SUBST(TCL_DDE_MINOR_VERSION) AC_SUBST(TCL_REG_VERSION) AC_SUBST(TCL_REG_MAJOR_VERSION) AC_SUBST(TCL_REG_MINOR_VERSION) AC_SUBST(RC) AC_SUBST(RC_OUT) AC_SUBST(RC_TYPE) AC_SUBST(RC_INCLUDE) |
| ︙ | ︙ |
Deleted win/execTestApp.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted win/find_nmakehlp.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to win/makefile.vc.
| ︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 | # to produce the .chm file. # # The steps to setup a Visual C++ environment depend on which # version of Visual Studio and/or the Windows SDK you are building # against and are not described here. The simplest method is generally # to start a command shell using one of the short cuts installed by # Visual Studio/Windows SDK for the appropriate target architecture. # # Basic macros and options usable on the commandline (see rules.vc for more info): # OPTS=nomsvcrt,noembed,nothreads,pdbs,profile,static,symbols,thrdalloc,unchecked,none # Sets special options for the core. The default is for none. # Any combination of the above may be used (comma separated). # 'none' will over-ride everything to nothing. # | > > > > > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | # to produce the .chm file. # # The steps to setup a Visual C++ environment depend on which # version of Visual Studio and/or the Windows SDK you are building # against and are not described here. The simplest method is generally # to start a command shell using one of the short cuts installed by # Visual Studio/Windows SDK for the appropriate target architecture. # # NOTE: For older (Visual C++ 6 or the 2003 SDK), to use the Platform # SDK (not expressly needed), run setenv.bat after vcvars32.bat # according to the instructions for it. This can also turn on the # 64-bit compiler, if your SDK has it. # # Basic macros and options usable on the commandline (see rules.vc for more info): # OPTS=nomsvcrt,noembed,nothreads,pdbs,profile,static,symbols,thrdalloc,unchecked,none # Sets special options for the core. The default is for none. # Any combination of the above may be used (comma separated). # 'none' will over-ride everything to nothing. # |
| ︙ | ︙ | |||
63 64 65 66 67 68 69 | # support. # none = Overrides all other options to nothing. # nothreads = Turns off full multithreading support (default on). # pdbs = Produce separate debug symbol files. # profile = Adds profiling hooks. Map file is assumed. # static = Builds a static library of the core instead of a # dll. The shell will be static (and large), and | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | # support. # none = Overrides all other options to nothing. # nothreads = Turns off full multithreading support (default on). # pdbs = Produce separate debug symbol files. # profile = Adds profiling hooks. Map file is assumed. # static = Builds a static library of the core instead of a # dll. The shell will be static (and large), and # have the dde and registry extensions linked inside. # symbols = Adds symbols for step debugging. # thrdalloc = Use the thread allocator (shared global free pool). # unchecked = Allows a symbols build to not use the debug # enabled runtime (msvcrt.dll not msvcrtd.dll # or libcmt.lib not libcmtd.lib). # # STATS=compdbg,memdbg,none |
| ︙ | ︙ | |||
156 157 158 159 160 161 162 | !if $(STATIC_BUILD) !message *** NOTE: The "staticpkg" option redundant in 9.0. !else !message *** NOTE: The "staticpkg" option ignored for shared library builds. !endif !endif | | > > | | | | | | | | > > > | | > > > < < < < | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | !if $(STATIC_BUILD) !message *** NOTE: The "staticpkg" option redundant in 9.0. !else !message *** NOTE: The "staticpkg" option ignored for shared library builds. !endif !endif !if [nmakehlp -f $(OPTS) "noembed"] !message *** Option noembed specified. Tcl script library will not be appended to the binary. TCL_EMBED_SCRIPTS = 0 TCL_TEST_LIBRARY=$(ROOT:\=/)/library !else !message *** Tcl script library will be appended to the binary. TCL_EMBED_SCRIPTS = 1 TCL_TEST_LIBRARY= !endif # We need versions of various core packages to generate appropriate # file names during installation. !if [echo REM = This file is generated from makefile.vc > versions.vc] !endif !if [echo PKG_HTTP_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\http\pkgIndex.tcl http >> versions.vc] !endif !if [echo PKG_OPT_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\opt\pkgIndex.tcl opt >> versions.vc] !endif !if [echo PKG_COOKIEJAR_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\cookiejar\pkgIndex.tcl cookiejar >> versions.vc] !endif !if [echo PKG_TCLTEST_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\tcltest\pkgIndex.tcl tcltest >> versions.vc] !endif !if [echo PKG_MSGCAT_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\msgcat\pkgIndex.tcl msgcat >> versions.vc] !endif !if [echo PKG_PLATFORM_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform " >> versions.vc] !endif !if [echo PKG_SHELL_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform::shell" >> versions.vc] !endif !if [echo PKG_DDE_VER = \>> versions.vc] \ && [nmakehlp -V ..\library\dde\pkgIndex.tcl "dde " >> versions.vc] !endif !if [echo PKG_REG_VER =\>> versions.vc] \ && [nmakehlp -V ..\library\registry\pkgIndex.tcl "registry " >> versions.vc] !endif !include versions.vc DDEDOTVERSION = 1.4 DDEVERSION = $(DDEDOTVERSION:.=) REGDOTVERSION = 1.3 REGVERSION = $(REGDOTVERSION:.=) TCLREGLIBNAME = $(PROJECT)9registry$(REGVERSION)$(SUFX:t=).$(EXT) TCLREGLIB = $(OUT_DIR)\$(TCLREGLIBNAME) TCLDDELIBNAME = $(PROJECT)9dde$(DDEVERSION)$(SUFX:t=).$(EXT) TCLDDELIB = $(OUT_DIR)\$(TCLDDELIBNAME) TCLTEST = $(OUT_DIR)\$(PROJECT)test$(VERSION)$(SUFX:t=).exe TCLTESTRAW = $(TCLTEST:.exe=-raw.exe) TCLSHOBJS = \ $(TMP_DIR)\tclAppInit.obj \ $(TMP_DIR)\tclsh.res TCLTESTOBJS = \ $(TMP_DIR)\tclTest.obj \ $(TMP_DIR)\tclTestObj.obj \ |
| ︙ | ︙ | |||
263 264 265 266 267 268 269 | $(TMP_DIR)\tclEnsemble.obj \ $(TMP_DIR)\tclEnv.obj \ $(TMP_DIR)\tclEvent.obj \ $(TMP_DIR)\tclExecute.obj \ $(TMP_DIR)\tclFCmd.obj \ $(TMP_DIR)\tclFileName.obj \ $(TMP_DIR)\tclGet.obj \ | < < | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 | $(TMP_DIR)\tclEnsemble.obj \ $(TMP_DIR)\tclEnv.obj \ $(TMP_DIR)\tclEvent.obj \ $(TMP_DIR)\tclExecute.obj \ $(TMP_DIR)\tclFCmd.obj \ $(TMP_DIR)\tclFileName.obj \ $(TMP_DIR)\tclGet.obj \ $(TMP_DIR)\tclHash.obj \ $(TMP_DIR)\tclHistory.obj \ $(TMP_DIR)\tclIcu.obj \ $(TMP_DIR)\tclIndexObj.obj \ $(TMP_DIR)\tclInterp.obj \ $(TMP_DIR)\tclIO.obj \ $(TMP_DIR)\tclIOCmd.obj \ $(TMP_DIR)\tclIOGT.obj \ $(TMP_DIR)\tclIOSock.obj \ $(TMP_DIR)\tclIOUtil.obj \ $(TMP_DIR)\tclIORChan.obj \ $(TMP_DIR)\tclIORTrans.obj \ $(TMP_DIR)\tclLink.obj \ $(TMP_DIR)\tclListObj.obj \ $(TMP_DIR)\tclLiteral.obj \ $(TMP_DIR)\tclLoad.obj \ $(TMP_DIR)\tclMainW.obj \ $(TMP_DIR)\tclMain.obj \ $(TMP_DIR)\tclNamesp.obj \ $(TMP_DIR)\tclNotify.obj \ $(TMP_DIR)\tclOO.obj \ |
| ︙ | ︙ | |||
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | $(TMP_DIR)\tclScan.obj \ $(TMP_DIR)\tclStringObj.obj \ $(TMP_DIR)\tclStrIdxTree.obj \ $(TMP_DIR)\tclStrToD.obj \ $(TMP_DIR)\tclStubInit.obj \ $(TMP_DIR)\tclThread.obj \ $(TMP_DIR)\tclThreadAlloc.obj \ $(TMP_DIR)\tclThreadStorage.obj \ $(TMP_DIR)\tclTimer.obj \ $(TMP_DIR)\tclTomMathInterface.obj \ $(TMP_DIR)\tclTrace.obj \ $(TMP_DIR)\tclUtf.obj \ $(TMP_DIR)\tclUtil.obj \ $(TMP_DIR)\tclVar.obj \ $(TMP_DIR)\tclZipfs.obj \ | > | < | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | $(TMP_DIR)\tclScan.obj \ $(TMP_DIR)\tclStringObj.obj \ $(TMP_DIR)\tclStrIdxTree.obj \ $(TMP_DIR)\tclStrToD.obj \ $(TMP_DIR)\tclStubInit.obj \ $(TMP_DIR)\tclThread.obj \ $(TMP_DIR)\tclThreadAlloc.obj \ $(TMP_DIR)\tclThreadJoin.obj \ $(TMP_DIR)\tclThreadStorage.obj \ $(TMP_DIR)\tclTimer.obj \ $(TMP_DIR)\tclTomMathInterface.obj \ $(TMP_DIR)\tclTrace.obj \ $(TMP_DIR)\tclUtf.obj \ $(TMP_DIR)\tclUtil.obj \ $(TMP_DIR)\tclVar.obj \ $(TMP_DIR)\tclZipfs.obj \ $(TMP_DIR)\tclZlib.obj !if $(STATIC_BUILD) ZLIBOBJS = \ $(TMP_DIR)\adler32.obj \ $(TMP_DIR)\compress.obj \ $(TMP_DIR)\crc32.obj \ $(TMP_DIR)\deflate.obj \ |
| ︙ | ︙ | |||
428 429 430 431 432 433 434 | $(TMP_DIR)\tclWinConsole.obj \ $(TMP_DIR)\tclWinError.obj \ $(TMP_DIR)\tclWinFCmd.obj \ $(TMP_DIR)\tclWinFile.obj \ $(TMP_DIR)\tclWinInit.obj \ $(TMP_DIR)\tclWinLoad.obj \ $(TMP_DIR)\tclWinNotify.obj \ | < < > | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | $(TMP_DIR)\tclWinConsole.obj \ $(TMP_DIR)\tclWinError.obj \ $(TMP_DIR)\tclWinFCmd.obj \ $(TMP_DIR)\tclWinFile.obj \ $(TMP_DIR)\tclWinInit.obj \ $(TMP_DIR)\tclWinLoad.obj \ $(TMP_DIR)\tclWinNotify.obj \ $(TMP_DIR)\tclWinPipe.obj \ $(TMP_DIR)\tclWinSerial.obj \ $(TMP_DIR)\tclWinSock.obj \ $(TMP_DIR)\tclWinThrd.obj \ $(TMP_DIR)\tclWinTime.obj \ !if $(STATIC_BUILD) $(TMP_DIR)\tclWinPanic.obj \ $(TMP_DIR)\tclWinReg.obj \ $(TMP_DIR)\tclWinDde.obj \ !else $(TMP_DIR)\tcl.res !endif TCLOBJS = $(COREOBJS) $(ZLIBOBJS) $(TOMMATHOBJS) $(PLATFORMOBJS) |
| ︙ | ︙ | |||
463 464 465 466 467 468 469 | LIBTCLVFSSUBDIR = libtcl.vfs LIBTCLVFS = $(OUT_DIR)\$(LIBTCLVFSSUBDIR) # Additional include and C macro definitions for the implicit rules # defined in rules.vc PRJ_INCLUDES = -I"$(TOMMATHDIR)" | | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | LIBTCLVFSSUBDIR = libtcl.vfs LIBTCLVFS = $(OUT_DIR)\$(LIBTCLVFSSUBDIR) # Additional include and C macro definitions for the implicit rules # defined in rules.vc PRJ_INCLUDES = -I"$(TOMMATHDIR)" PRJ_DEFINES = /DMP_PREC=4 /Dinline=__inline /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /DMP_FIXED_CUTOFFS !if $(STATIC_BUILD) PRJ_DEFINES = $(PRJ_DEFINES) /DTCL_WITH_INTERNAL_ZLIB !endif # Additional Link libraries needed beyond those in rules.vc PRJ_LIBS = netapi32.lib user32.lib userenv.lib ws2_32.lib |
| ︙ | ︙ | |||
490 491 492 493 494 495 496 | # There are 4 primary build configurations to consider from the combination # of static/shared and embed/noembed of the library zip. The targets are # done in the following order. # $(TCLLIB) - this is either the core static .lib or the .dll. The target # build does not embed the library zip in the DLL irrespective # of the noembed setting. A copy is made as $(TCLLIBRAW) # as the $(TCLLIB) binary is potentially modified later. | | | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | # There are 4 primary build configurations to consider from the combination # of static/shared and embed/noembed of the library zip. The targets are # done in the following order. # $(TCLLIB) - this is either the core static .lib or the .dll. The target # build does not embed the library zip in the DLL irrespective # of the noembed setting. A copy is made as $(TCLLIBRAW) # as the $(TCLLIB) binary is potentially modified later. # dlls - these are the registry and dde DLL's or static libraries # $(TCLSH) - the Tcl shell WITHOUT any embedded zip. This needs $(TCLLIB) # to be built first as it links against it. A copy is made # as $(TCLSHRAW) as $(TCLSH) binary may be modified later. # $(TCLSCRIPTZIP) - the zip file that is to be embedded. Note this also # ships separately and needs to be built irrespective of the # whether it is embedded or not. All above targets need to # be built prior as they are used to build the zip (unlike |
| ︙ | ︙ | |||
525 526 527 528 529 530 531 | shell: setup core $(TCLSH) !if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD) shell: libtclzip @$(COPY) /b "$(TCLSHRAW)"+"$(TCLSCRIPTZIP)" "$(TCLSH)" !endif | | | > | | > | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | shell: setup core $(TCLSH) !if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD) shell: libtclzip @$(COPY) /b "$(TCLSHRAW)"+"$(TCLSCRIPTZIP)" "$(TCLSH)" !endif dlls: setup $(TCLREGLIB) $(TCLDDELIB) $(OUT_DIR)\zlib1.dll $(OUT_DIR)\libtommath.dll libtclzip: $(TCLSCRIPTZIP) tcltest: setup core $(TCLTEST) dlls !if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD) tcltest: libtclzip @$(COPY) /b "$(TCLTESTRAW)"+"$(TCLSCRIPTZIP)" "$(TCLTEST)" !endif install: install-binaries install-libraries install-docs install-pkgs !if $(SYMBOLS) install: install-pdbs !endif setup: default-setup test: test-core test-pkgs test-core: tcltest set TCL_LIBRARY=$(TCL_TEST_LIBRARY) !if $(STATIC_BUILD) $(DEBUGGER) $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile << package require registry package require dde << !else $(DEBUGGER) $(TCLTEST) "$(ROOT:\=/)/tests/all.tcl" $(TESTFLAGS) -loadfile << package ifneeded dde 1.4.6 [list load "$(TCLDDELIB:\=/)"] package ifneeded registry 1.3.7 [list load "$(TCLREGLIB:\=/)"] << !endif runtest: setup $(TCLTEST) dlls set TCL_LIBRARY=$(TCL_TEST_LIBRARY) $(DEBUGGER) $(TCLTEST) $(SCRIPT) |
| ︙ | ︙ | |||
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | !else $(TCLLIB): $(TCLOBJS) $(DLLCMD) @<< $** << !if $(TCL_EMBED_SCRIPTS) && !$(STATIC_BUILD) $(COPY) $@ $(TCLLIBRAW) !endif $(TCLIMPLIB): $(TCLLIB) !endif # $(STATIC_BUILD) $(TCLSTUBLIB): $(TCLSTUBOBJS) $(LIBCMD) -nodefaultlib $(TCLSTUBOBJS) $(TCLSH): $(TCLSHOBJS) $(TCLSTUBLIB) $(TCLIMPLIB) $(CONEXECMD) -stack:2300000 $** !if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD) $(COPY) $@ $(TCLSHRAW) !endif $(TCLTEST): $(TCLTESTOBJS) $(TCLSTUBLIB) $(TCLIMPLIB) $(CONEXECMD) -stack:2300000 $** !if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD) $(COPY) $@ $(TCLTESTRAW) !endif !if $(STATIC_BUILD) $(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj $(LIBCMD) $** !else $(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj $(TCLSTUBLIB) $(DLLCMD) $** !endif | > > > > > > | > | > > | > > | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | !else $(TCLLIB): $(TCLOBJS) $(DLLCMD) @<< $** << $(_VC_MANIFEST_EMBED_DLL) !if $(TCL_EMBED_SCRIPTS) && !$(STATIC_BUILD) $(COPY) $@ $(TCLLIBRAW) !endif $(TCLIMPLIB): $(TCLLIB) !endif # $(STATIC_BUILD) $(TCLSTUBLIB): $(TCLSTUBOBJS) $(LIBCMD) -nodefaultlib $(TCLSTUBOBJS) $(TCLSH): $(TCLSHOBJS) $(TCLSTUBLIB) $(TCLIMPLIB) $(CONEXECMD) -stack:2300000 $** copy $(TMP_DIR)\tclsh.exe.manifest $(TCLSH).manifest $(_VC_MANIFEST_EMBED_EXE) !if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD) $(COPY) $@ $(TCLSHRAW) !endif $(TCLTEST): $(TCLTESTOBJS) $(TCLSTUBLIB) $(TCLIMPLIB) $(CONEXECMD) -stack:2300000 $** copy $(TMP_DIR)\tclsh.exe.manifest $(TCLTEST).manifest $(_VC_MANIFEST_EMBED_EXE) !if $(TCL_EMBED_SCRIPTS) && $(STATIC_BUILD) $(COPY) $@ $(TCLTESTRAW) !endif !if $(STATIC_BUILD) $(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj $(LIBCMD) $** !else $(TCLDDELIB): $(TMP_DIR)\tclWinDde.obj $(TCLSTUBLIB) $(DLLCMD) $** $(_VC_MANIFEST_EMBED_DLL) !endif !if $(STATIC_BUILD) $(TCLREGLIB): $(TMP_DIR)\tclWinReg.obj $(LIBCMD) $** !else $(TCLREGLIB): $(TMP_DIR)\tclWinReg.obj $(TCLSTUBLIB) $(DLLCMD) $** $(_VC_MANIFEST_EMBED_DLL) !endif !if "$(MACHINE)" == "ARM64" $(OUT_DIR)\zlib1.dll: $(COMPATDIR)\zlib\win64-arm\zlib1.dll $(COPY) $(COMPATDIR)\zlib\win64-arm\zlib1.dll $(OUT_DIR)\zlib1.dll $(OUT_DIR)\zdll.lib: $(COMPATDIR)\zlib\win64-arm\zdll.lib $(COPY) $(COMPATDIR)\zlib\win64-arm\zdll.lib $(OUT_DIR)\zdll.lib $(OUT_DIR)\libtommath.dll: $(TOMMATHDIR)\win64-arm\libtommath.dll |
| ︙ | ︙ | |||
640 641 642 643 644 645 646 | $(OUT_DIR)\libtommath.dll: $(TOMMATHDIR)\win64\libtommath.dll $(COPY) $(TOMMATHDIR)\win64\libtommath.dll $(OUT_DIR)\libtommath.dll $(OUT_DIR)\tommath.lib: $(TOMMATHDIR)\win64\tommath.lib $(COPY) $(TOMMATHDIR)\win64\tommath.lib $(OUT_DIR)\tommath.lib !endif $(TCLSCRIPTZIP): $(TCLLIB) $(TCLSH) dlls | | | > > | 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 |
$(OUT_DIR)\libtommath.dll: $(TOMMATHDIR)\win64\libtommath.dll
$(COPY) $(TOMMATHDIR)\win64\libtommath.dll $(OUT_DIR)\libtommath.dll
$(OUT_DIR)\tommath.lib: $(TOMMATHDIR)\win64\tommath.lib
$(COPY) $(TOMMATHDIR)\win64\tommath.lib $(OUT_DIR)\tommath.lib
!endif
$(TCLSCRIPTZIP): $(TCLLIB) $(TCLSH) dlls
@echo Building Tcl library zip file $(TCLSCRIPTZIP)
@set TCL_LIBRARY=$(ROOT:\=/)/library
@if exist "$(LIBTCLVFS)" $(RMDIR) "$(LIBTCLVFS)"
@$(MKDIR) "$(LIBTCLVFS)"
@$(CPYDIR) $(LIBDIR) "$(LIBTCLVFS)\tcl_library"
@move /y "$(LIBTCLVFS)\tcl_library\manifest.txt" "$(LIBTCLVFS)\tcl_library\pkgIndex.tcl" > NUL
# Remove the registry and dde directories as the DLLS are still external
@del "$(LIBTCLVFS)\tcl_library\registry\pkgIndex.tcl"
@rmdir "$(LIBTCLVFS)\tcl_library\registry"
@del "$(LIBTCLVFS)\tcl_library\dde\pkgIndex.tcl"
@rmdir "$(LIBTCLVFS)\tcl_library\dde"
@echo cd {$(OUT_DIR)} > "$(OUT_DIR)\zipper.tcl"
@echo file delete -force {$(@F)} >> "$(OUT_DIR)\zipper.tcl"
@echo zipfs mkzip {$(@F)} {$(LIBTCLVFSSUBDIR)} {$(LIBTCLVFSSUBDIR)} >> "$(OUT_DIR)\zipper.tcl"
@$(TCLSH_NATIVE) "$(OUT_DIR)/zipper.tcl"
|
| ︙ | ︙ | |||
730 731 732 733 734 735 736 | htmlhelp: $(CHMFILE) htmldocs: $(DOCDIR)\* @$(TCLSH) $(TOOLSDIR)\tcltk-man2html.tcl "--htmldir=$(HTMLDIR)" $(CHMFILE): htmldocs chmsetup | | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 | htmlhelp: $(CHMFILE) htmldocs: $(DOCDIR)\* @$(TCLSH) $(TOOLSDIR)\tcltk-man2html.tcl "--htmldir=$(HTMLDIR)" $(CHMFILE): htmldocs chmsetup @echo Compiling HTML help project -"$(HHC)" <<$(HHPFILE) >NUL [OPTIONS] Compatibility=1.1 or later Compiled file=$(HTMLBASE).chm Default topic=index.html Display compile progress=no Error log file=$(HTMLBASE).log |
| ︙ | ︙ | |||
757 758 759 760 761 762 763 |
<<
chmsetup:
@if not exist $(HTMLDIR)\nul mkdir $(HTMLDIR)
install-docs:
!if exist("$(CHMFILE)")
| | | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 |
<<
chmsetup:
@if not exist $(HTMLDIR)\nul mkdir $(HTMLDIR)
install-docs:
!if exist("$(CHMFILE)")
@echo Installing compiled HTML help
@$(CPY) "$(CHMFILE)" "$(DOC_INSTALL_DIR)\"
!endif
# "emacs font-lock highlighting fix
#---------------------------------------------------------------------
# Generate the tcl.nmake file which contains the options used to build
|
| ︙ | ︙ | |||
783 784 785 786 787 788 789 | # Build tclConfig.sh for the TEA build system. #--------------------------------------------------------------------- tclConfig: $(OUT_DIR)\tclConfig.sh # TBD - is this tclConfig.sh file ever used? The values are incorrect! $(OUT_DIR)\tclConfig.sh: $(WIN_DIR)\tclConfig.sh.in | | | | 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | # Build tclConfig.sh for the TEA build system. #--------------------------------------------------------------------- tclConfig: $(OUT_DIR)\tclConfig.sh # TBD - is this tclConfig.sh file ever used? The values are incorrect! $(OUT_DIR)\tclConfig.sh: $(WIN_DIR)\tclConfig.sh.in @echo Creating tclConfig.sh @nmakehlp -s << $** >$@ @TCL_DLL_FILE@ $(TCLLIBNAME) @TCL_VERSION@ $(DOTVERSION) @TCL_MAJOR_VERSION@ $(TCL_MAJOR_VERSION) @TCL_MINOR_VERSION@ $(TCL_MINOR_VERSION) @TCL_PATCH_LEVEL@ $(TCL_PATCH_LEVEL) @CC@ $(CC) @DEFS@ $(pkgcflags) |
| ︙ | ︙ | |||
920 921 922 923 924 925 926 | /DCFG_RUNTIME_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_DLLFILE="\"$(TCL_LIB_FILE)\"" \ -Fo$@ $? | < < < < < < < < < > > > > | 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 | /DCFG_RUNTIME_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\"" \ /DCFG_RUNTIME_DLLFILE="\"$(TCL_LIB_FILE)\"" \ -Fo$@ $? $(TMP_DIR)\tclAppInit.obj: $(WIN_DIR)\tclAppInit.c $(cc32) $(appcflags) /DUNICODE /D_UNICODE \ -Fo$@ $? ### The following objects should be built using the stub interfaces $(TMP_DIR)\tclWinReg.obj: $(WIN_DIR)\tclWinReg.c $(cc32) $(appcflags_nostubs) /DUSE_TCL_STUBS=1 -Fo$@ $? $(TMP_DIR)\tclWinDde.obj: $(WIN_DIR)\tclWinDde.c $(cc32) $(appcflags_nostubs) /DUSE_TCL_STUBS=1 -Fo$@ $? ### The following objects are part of the stub library and should not ### be built as DLL objects. -Zl is used to avoid a dependency on any |
| ︙ | ︙ | |||
965 966 967 968 969 970 971 | $(TMP_DIR)\tclOOStubLib.obj: $(GENERICDIR)\tclOOStubLib.c $(cc32) $(stubscflags) -Fo$@ $? $(TMP_DIR)\tclWinPanic.obj: $(WIN_DIR)\tclWinPanic.c $(cc32) $(stubscflags) -Fo$@ $? $(TMP_DIR)\tclsh.exe.manifest: $(WIN_DIR)\tclsh.exe.manifest.in | | | 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 | $(TMP_DIR)\tclOOStubLib.obj: $(GENERICDIR)\tclOOStubLib.c $(cc32) $(stubscflags) -Fo$@ $? $(TMP_DIR)\tclWinPanic.obj: $(WIN_DIR)\tclWinPanic.c $(cc32) $(stubscflags) -Fo$@ $? $(TMP_DIR)\tclsh.exe.manifest: $(WIN_DIR)\tclsh.exe.manifest.in @nmakehlp -s << $** >$@ @MACHINE@ $(MACHINE:IX86=X86) @TCL_WIN_VERSION@ $(DOTVERSION).0.0 << #--------------------------------------------------------------------- # Generate the source dependencies. Having dependency rules will # improve incremental build accuracy without having to resort to a |
| ︙ | ︙ | |||
995 996 997 998 999 1000 1001 |
#---------------------------------------------------------------------
# Dependency rules
#---------------------------------------------------------------------
!if exist("$(OUT_DIR)\depend.mk")
!include "$(OUT_DIR)\depend.mk"
| < < < < < < < < < | | | | | | | | | | | | | | < | > > | | | | | | | | | > > | 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 |
#---------------------------------------------------------------------
# Dependency rules
#---------------------------------------------------------------------
!if exist("$(OUT_DIR)\depend.mk")
!include "$(OUT_DIR)\depend.mk"
!message *** Dependency rules in use.
!else
!message *** Dependency rules are not being used.
!endif
### add a spacer in the output
!message
#---------------------------------------------------------------------
# Implicit rules that are not covered by the common ones defined in
# rules.vc. A limitation exists with nmake that requires that
# source directory can not contain spaces in the path. This an
# absolute.
#---------------------------------------------------------------------
{$(TOMMATHDIR)}.c{$(TMP_DIR)}.obj::
$(cc32) $(pkgcflags) -Fo$(TMP_DIR)\ @<<
$<
<<
{$(COMPATDIR)\zlib}.c{$(TMP_DIR)}.obj::
$(cc32) $(pkgcflags) -Fo$(TMP_DIR)\ @<<
$<
<<
$(TMP_DIR)\tclsh.res: $(TMP_DIR)\tclsh.exe.manifest $(WIN_DIR)\tclsh.rc
$(TMP_DIR)\tcltest.res: $(TMP_DIR)\tclsh.exe.manifest $(WIN_DIR)\tcltest.rc
#---------------------------------------------------------------------
# Installation.
#---------------------------------------------------------------------
install-binaries:
@echo Installing to '$(_INSTALLDIR)'
@echo Installing $(TCLLIBNAME)
!if "$(TCLLIB)" != "$(TCLIMPLIB)"
@$(CPY) "$(TCLLIB)" "$(BIN_INSTALL_DIR)\"
!endif
@$(CPY) "$(TCLIMPLIB)" "$(LIB_INSTALL_DIR)\"
@$(CPY) "$(OUT_DIR)\zlib1.dll" "$(BIN_INSTALL_DIR)\"
@$(CPY) "$(OUT_DIR)\libtommath.dll" "$(BIN_INSTALL_DIR)\"
!if !$(STATIC_BUILD)
@$(CPY) "$(OUT_DIR)\zdll.lib" "$(LIB_INSTALL_DIR)\"
@$(CPY) "$(OUT_DIR)\tommath.lib" "$(LIB_INSTALL_DIR)\"
!endif
@echo Installing $(TCLSHNAME)
@$(CPY) "$(TCLSH)" "$(BIN_INSTALL_DIR)\"
@echo Installing $(TCLSTUBLIBNAME)
@$(CPY) "$(TCLSTUBLIB)" "$(LIB_INSTALL_DIR)\"
install-libraries: tclConfig tcl-nmake install-msgs install-tzdata
@if not exist "$(LIB_INSTALL_DIR)\nmake" \
$(MKDIR) "$(LIB_INSTALL_DIR)\nmake"
@echo Installing header files
@$(CPY) "$(GENERICDIR)\tcl.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclDecls.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclOO.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclOODecls.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclPlatDecls.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclTomMath.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(GENERICDIR)\tclTomMathDecls.h" "$(INCLUDE_INSTALL_DIR)\"
@$(CPY) "$(TOMMATHDIR)\tommath.h" "$(INCLUDE_INSTALL_DIR)\"
!if !$(TCL_EMBED_SCRIPTS)
@echo Installing library files to $(SCRIPT_INSTALL_DIR)
@if not exist "$(SCRIPT_INSTALL_DIR)" \
$(MKDIR) "$(SCRIPT_INSTALL_DIR)"
@$(CPY) "$(ROOT)\library\*.tcl" "$(SCRIPT_INSTALL_DIR)\"
@$(CPY) "$(ROOT)\library\tclIndex" "$(SCRIPT_INSTALL_DIR)\"
!endif
@$(CPY) "$(OUT_DIR)\tclConfig.sh" "$(LIB_INSTALL_DIR)\"
@$(CPY) "$(WIN_DIR)\tclooConfig.sh" "$(LIB_INSTALL_DIR)\"
@$(CPY) "$(TCLSCRIPTZIP)" "$(LIB_INSTALL_DIR)\"
@$(CPY) "$(WIN_DIR)\rules.vc" "$(LIB_INSTALL_DIR)\nmake\"
@$(CPY) "$(WIN_DIR)\targets.vc" "$(LIB_INSTALL_DIR)\nmake\"
@$(CPY) "$(WIN_DIR)\nmakehlp.c" "$(LIB_INSTALL_DIR)\nmake\"
@$(CPY) "$(WIN_DIR)\x86_64-w64-mingw32-nmakehlp.exe" "$(LIB_INSTALL_DIR)\nmake\"
@$(CPY) "$(OUT_DIR)\tcl.nmake" "$(LIB_INSTALL_DIR)\nmake\"
!if !$(TCL_EMBED_SCRIPTS)
@echo Installing package cookiejar $(PKG_COOKIEJAR_VER)
@if not exist "$(SCRIPT_INSTALL_DIR)\cookiejar0.2" \
$(MKDIR) "$(SCRIPT_INSTALL_DIR)\cookiejar0.2"
@$(CPY) "$(ROOT)\library\cookiejar\*.tcl" \
"$(SCRIPT_INSTALL_DIR)\cookiejar0.2\"
@$(CPY) "$(ROOT)\library\cookiejar\*.gz" \
"$(SCRIPT_INSTALL_DIR)\cookiejar0.2\"
@echo Installing package opt $(PKG_OPT_VER)
@if not exist "$(SCRIPT_INSTALL_DIR)\opt0.4" \
$(MKDIR) "$(SCRIPT_INSTALL_DIR)\opt0.4"
@$(CPY) "$(ROOT)\library\opt\*.tcl" \
"$(SCRIPT_INSTALL_DIR)\opt0.4\"
@if not exist "$(MODULE_INSTALL_DIR)" \
$(MKDIR) "$(MODULE_INSTALL_DIR)"
@echo Installing package http $(PKG_HTTP_VER) as a Tcl Module
@if not exist "$(MODULE_INSTALL_DIR)\9.0" \
$(MKDIR) "$(MODULE_INSTALL_DIR)\9.0"
@$(COPY) "$(ROOT)\library\http\http.tcl" \
"$(MODULE_INSTALL_DIR)\9.0\http-$(PKG_HTTP_VER).tm"
@echo Installing package msgcat $(PKG_MSGCAT_VER) as a Tcl Module
@$(COPY) "$(ROOT)\library\msgcat\msgcat.tcl" \
"$(MODULE_INSTALL_DIR)\9.0\msgcat-$(PKG_MSGCAT_VER).tm"
@echo Installing package tcltest $(PKG_TCLTEST_VER) as a Tcl Module
@$(COPY) "$(ROOT)\library\tcltest\tcltest.tcl" \
"$(MODULE_INSTALL_DIR)\9.0\tcltest-$(PKG_TCLTEST_VER).tm"
@echo Installing package platform $(PKG_PLATFORM_VER) as a Tcl Module
@if not exist "$(MODULE_INSTALL_DIR)\9.0\platform" \
$(MKDIR) "$(MODULE_INSTALL_DIR)\9.0\platform"
@$(COPY) "$(ROOT)\library\platform\platform.tcl" \
"$(MODULE_INSTALL_DIR)\9.0\platform-$(PKG_PLATFORM_VER).tm"
@echo Installing package platform::shell $(PKG_SHELL_VER) as a Tcl Module
@$(COPY) "$(ROOT)\library\platform\shell.tcl" \
"$(MODULE_INSTALL_DIR)\9.0\platform\shell-$(PKG_SHELL_VER).tm"
!endif
@echo Installing $(TCLDDELIBNAME)
@$(CPY) "$(TCLDDELIB)" "$(LIB_INSTALL_DIR)\dde$(DDEDOTVERSION)\"
@$(CPY) "$(ROOT)\library\dde\pkgIndex.tcl" \
"$(LIB_INSTALL_DIR)\dde$(DDEDOTVERSION)\"
@echo Installing $(TCLREGLIBNAME)
@$(CPY) "$(TCLREGLIB)" "$(LIB_INSTALL_DIR)\registry$(REGDOTVERSION)\"
@$(CPY) "$(ROOT)\library\registry\pkgIndex.tcl" \
"$(LIB_INSTALL_DIR)\registry$(REGDOTVERSION)\"
!if !$(TCL_EMBED_SCRIPTS)
@echo Installing encodings
@$(CPY) "$(ROOT)\library\encoding\*.enc" \
"$(SCRIPT_INSTALL_DIR)\encoding\"
!endif
# "emacs font-lock highlighting fix
install-tzdata:
!if !$(TCL_EMBED_SCRIPTS)
@echo Installing time zone data
@set TCL_LIBRARY=$(ROOT:\=/)/library
@$(TCLSH_NATIVE) "$(ROOT:\=/)/tools/installData.tcl" \
"$(ROOT:\=/)/library/tzdata" "$(SCRIPT_INSTALL_DIR)/tzdata"
!endif
install-msgs:
!if !$(TCL_EMBED_SCRIPTS)
@echo Installing message catalogs
@set TCL_LIBRARY=$(ROOT:\=/)/library
@$(TCLSH_NATIVE) "$(ROOT:\=/)/tools/installData.tcl" \
"$(ROOT:\=/)/library/msgs" "$(SCRIPT_INSTALL_DIR)/msgs"
!endif
install-pdbs:
@echo Installing debug symbols
@$(CPY) "$(OUT_DIR)\*.pdb" "$(BIN_INSTALL_DIR)\"
# "emacs font-lock highlighting fix
#---------------------------------------------------------------------
# Clean up
#---------------------------------------------------------------------
tidy:
!if "$(TCLLIB)" != "$(TCLIMPLIB)"
@echo Removing $(TCLLIB) ...
@if exist $(TCLLIB) del $(TCLLIB)
!endif
@echo Removing $(TCLIMPLIB) ...
@if exist $(TCLIMPLIB) del $(TCLIMPLIB)
@echo Removing $(TCLSH) ...
@if exist $(TCLSH) del $(TCLSH)
@echo Removing $(TCLTEST) ...
@if exist $(TCLTEST) del $(TCLTEST)
@echo Removing $(TCLDDELIB) ...
@if exist $(TCLDDELIB) del $(TCLDDELIB)
@echo Removing $(TCLREGLIB) ...
@if exist $(TCLREGLIB) del $(TCLREGLIB)
clean: default-clean clean-pkgs
hose: default-hose hose-pkgs
realclean: hose
.PHONY:
# Local Variables:
# mode: makefile
# End:
|
Changes to win/nmakehlp.c.
1 2 3 4 5 6 | /* * ---------------------------------------------------------------------------- * nmakehlp.c -- * * This is used to fix limitations within nmake and the environment. * | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * ---------------------------------------------------------------------------- * nmakehlp.c -- * * This is used to fix limitations within nmake and the environment. * * Copyright (c) 2002 David Gravereaux. * Copyright (c) 2006 Pat Thoyts * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE |
| ︙ | ︙ |
Changes to win/rules-ext.vc.
| ︙ | ︙ | |||
27 28 29 30 31 32 33 34 35 | !if "$(PROJECT)" == "tcl" !error The rules-ext.vc file is not intended for Tcl itself. !endif # We extract version numbers using the nmakehlp program. For now use # the local copy of nmakehlp. Once we locate Tcl, we will use that # one if it is newer. !if [$(CC) -nologo -DNDEBUG "nmakehlp.c" -link -subsystem:console > nul] !endif | > < < < < < < < < | < < < < < | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | !if "$(PROJECT)" == "tcl" !error The rules-ext.vc file is not intended for Tcl itself. !endif # We extract version numbers using the nmakehlp program. For now use # the local copy of nmakehlp. Once we locate Tcl, we will use that # one if it is newer. !if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" !if [$(CC) -nologo -DNDEBUG "nmakehlp.c" -link -subsystem:console > nul] !endif !else !if [copy x86_64-w64-mingw32-nmakehlp.exe nmakehlp.exe >NUL] !endif !endif # First locate the Tcl directory that we are working with. !if "$(TCLDIR)" != "" _RULESDIR = $(TCLDIR:/=\) !else # If an installation path is specified, that is also the Tcl directory. # Also Tk never builds against an installed Tcl, it needs Tcl sources !if defined(INSTALLDIR) && "$(PROJECT)" != "tk" _RULESDIR=$(INSTALLDIR:/=\) !else # Locate Tcl sources !if [echo _RULESDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] _RULESDIR = ..\..\tcl !else !include nmakehlp.out !endif !endif # defined(INSTALLDIR).... |
| ︙ | ︙ | |||
90 91 92 93 94 95 96 |
!if "$(_RULESDIR)" != "."
# Potentially using Tcl's support files. If this extension has its own
# nmake support files, need to compare the versions and pick newer.
!if exist("rules.vc") # The extension has its own copy
!if [echo TCL_RULES_MAJOR = \> versions.vc] \
| | | | | | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
!if "$(_RULESDIR)" != "."
# Potentially using Tcl's support files. If this extension has its own
# nmake support files, need to compare the versions and pick newer.
!if exist("rules.vc") # The extension has its own copy
!if [echo TCL_RULES_MAJOR = \> versions.vc] \
&& [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MAJOR >> versions.vc]
!endif
!if [echo TCL_RULES_MINOR = \>> versions.vc] \
&& [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MINOR >> versions.vc]
!endif
!if [echo OUR_RULES_MAJOR = \>> versions.vc] \
&& [nmakehlp -V "rules.vc" RULES_VERSION_MAJOR >> versions.vc]
!endif
!if [echo OUR_RULES_MINOR = \>> versions.vc] \
&& [nmakehlp -V "rules.vc" RULES_VERSION_MINOR >> versions.vc]
!endif
!include versions.vc
# We have a newer version of the support files, use them
!if ($(TCL_RULES_MAJOR) != $(OUR_RULES_MAJOR)) || ($(TCL_RULES_MINOR) < $(OUR_RULES_MINOR))
_RULESDIR = .
!endif
|
| ︙ | ︙ | |||
122 123 124 125 126 127 128 |
# Get rid of our internal defines before calling rules.vc
!undef TCL_RULES_MAJOR
!undef TCL_RULES_MINOR
!undef OUR_RULES_MAJOR
!undef OUR_RULES_MINOR
!if exist("$(_RULESDIR)\rules.vc")
| | < < < < < | < | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# Get rid of our internal defines before calling rules.vc
!undef TCL_RULES_MAJOR
!undef TCL_RULES_MINOR
!undef OUR_RULES_MAJOR
!undef OUR_RULES_MINOR
!if exist("$(_RULESDIR)\rules.vc")
!message *** Using $(_RULESDIR)\rules.vc
!include "$(_RULESDIR)\rules.vc"
!else
!error *** Could not locate rules.vc in $(_RULESDIR)
!endif
!endif # _RULES_EXT_VC
|
Changes to win/rules.vc.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 | # Copyright (c) 2003-2008 Patrick Thoyts # Copyright (c) 2017 Ashok P. Nadkarni #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 | < < < < < < < < < < < < < < < < < < | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # Copyright (c) 2003-2008 Patrick Thoyts # Copyright (c) 2017 Ashok P. Nadkarni #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 # The following macros define the version of the rules.vc nmake build system # For modifications that are not backward-compatible, you *must* change # the major version. RULES_VERSION_MAJOR = 1 RULES_VERSION_MINOR = 16 # The PROJECT macro must be defined by parent makefile. !if "$(PROJECT)" == "" !error *** Error: Macro PROJECT not defined! Please define it before including rules.vc !endif !if "$(PRJ_PACKAGE_TCLNAME)" == "" |
| ︙ | ︙ | |||
164 165 166 167 168 169 170 | #---------------------------------------------------------- RMDIR = rd /S /Q CPY = xcopy /i /y >NUL CPYDIR = xcopy /e /i /y >NUL COPY = copy /y >NUL MKDIR = md | < | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | #---------------------------------------------------------- RMDIR = rd /S /Q CPY = xcopy /i /y >NUL CPYDIR = xcopy /e /i /y >NUL COPY = copy /y >NUL MKDIR = md ###################################################################### # 2. Figure out our build environment in terms of what we're building. # # (a) Tcl itself # (b) Tk # (c) a Tcl extension using libraries/includes from an *installed* Tcl |
| ︙ | ︙ | |||
275 276 277 278 279 280 281 | !elseif $(DOING_TK) # BEGIN Case 2(b) - Building Tk TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl !if "$(TCLDIR)" == "" !if [echo TCLDIR = \> nmakehlp.out] \ | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | !elseif $(DOING_TK) # BEGIN Case 2(b) - Building Tk TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl !if "$(TCLDIR)" == "" !if [echo TCLDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] !error *** Could not locate Tcl source directory. !endif !include nmakehlp.out !endif # TCLDIR == "" _TCLDIR = $(TCLDIR:/=\) _TCL_H = $(_TCLDIR)\generic\tcl.h |
| ︙ | ︙ | |||
325 326 327 328 329 330 331 | # later so the \.. accounts for the /lib _TCLDIR = $(_INSTALLDIR)\.. _TCL_H = $(_TCLDIR)\include\tcl.h !else # exist(...) && !$(NEED_TCL_SOURCE) !if [echo _TCLDIR = \> nmakehlp.out] \ | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | # later so the \.. accounts for the /lib _TCLDIR = $(_INSTALLDIR)\.. _TCL_H = $(_TCLDIR)\include\tcl.h !else # exist(...) && !$(NEED_TCL_SOURCE) !if [echo _TCLDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] !error *** Could not locate Tcl source directory. !endif !include nmakehlp.out TCLINSTALL = 0 TCLDIR = $(_TCLDIR) _TCL_H = $(_TCLDIR)\generic\tcl.h |
| ︙ | ︙ | |||
374 375 376 377 378 379 380 |
_TKDIR = $(_INSTALLDIR)\..
_TK_H = $(_TKDIR)\include\tk.h
TKDIR = $(_TKDIR)
!else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
!if [echo _TKDIR = \> nmakehlp.out] \
| | | 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
_TKDIR = $(_INSTALLDIR)\..
_TK_H = $(_TKDIR)\include\tk.h
TKDIR = $(_TKDIR)
!else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
!if [echo _TKDIR = \> nmakehlp.out] \
|| [nmakehlp -L generic\tk.h >> nmakehlp.out]
!error *** Could not locate Tk source directory.
!endif
!include nmakehlp.out
TKINSTALL = 0
TKDIR = $(_TKDIR)
_TK_H = $(_TKDIR)\generic\tk.h
|
| ︙ | ︙ | |||
570 571 572 573 574 575 576 | !endif # $(TCLINSTALL) !endif # !$(DOING_TCL) !endif # NMAKEHLPC # We always build nmakehlp even if it exists since we do not know # what source it was built from. | > | > > > > | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 | !endif # $(TCLINSTALL) !endif # !$(DOING_TCL) !endif # NMAKEHLPC # We always build nmakehlp even if it exists since we do not know # what source it was built from. !if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" !if [$(cc32) -nologo "$(NMAKEHLPC)" -link -subsystem:console > nul] !endif !else !if [copy $(NMAKEHLPC:nmakehlp.c=x86_64-w64-mingw32-nmakehlp.exe) nmakehlp.exe >NUL] !endif !endif ################################################################ # 5. Test for compiler features # Visual C++ compiler options have changed over the years. Check # which options are supported by the compiler in use. # |
| ︙ | ︙ | |||
593 594 595 596 597 598 599 | # # Also note that some of the flags in OPTIMIZATIONS are not really # related to optimization. They are placed there only for legacy reasons # as some extensions expect them to be included in that macro. # -Op improves float consistency. Note only needed for older compilers # Newer compilers do not need or support this option. | | | | | | | | | | | | | 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 | # # Also note that some of the flags in OPTIMIZATIONS are not really # related to optimization. They are placed there only for legacy reasons # as some extensions expect them to be included in that macro. # -Op improves float consistency. Note only needed for older compilers # Newer compilers do not need or support this option. !if [nmakehlp -c -Op] FPOPTS = -Op !endif # Strict floating point semantics - present in newer compilers in lieu of -Op !if [nmakehlp -c -fp:strict] FPOPTS = $(FPOPTS) -fp:strict !endif !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' FPOPTS = $(FPOPTS) -QI0f !else !message *** Compiler does not have 'Pentium 0x0f fix' !endif !endif ### test for optimizations # /O2 optimization includes /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy as per # documentation. Note we do NOT want /Gs as that inserts a _chkstk # stack probe at *every* function entry, not just those with more than # a page of stack allocation resulting in a performance hit. However, # /O2 documentation is misleading as its stack probes are simply the # default page size locals allocation probes and not what is implied # by an explicit /Gs option. OPTIMIZATIONS = $(FPOPTS) !if [nmakehlp -c -O2] OPTIMIZING = 1 OPTIMIZATIONS = $(OPTIMIZATIONS) -O2 !else # Legacy, really. All modern compilers support this !message *** Compiler does not have 'Optimizations' OPTIMIZING = 0 !endif # Checks for buffer overflows in local arrays !if [nmakehlp -c -GS] OPTIMIZATIONS = $(OPTIMIZATIONS) -GS !endif # Link time optimization. Note that this option (potentially) makes # generated libraries only usable by the specific VC++ version that # created it. Requires /LTCG linker option !if [nmakehlp -c -GL] OPTIMIZATIONS = $(OPTIMIZATIONS) -GL CC_GL_OPT_ENABLED = 1 !else # In newer compilers -GL and -YX are incompatible. !if [nmakehlp -c -YX] OPTIMIZATIONS = $(OPTIMIZATIONS) -YX !endif !endif # [nmakehlp -c -GL] DEBUGFLAGS = $(FPOPTS) # Run time error checks. Not available or valid in a release, non-debug build # RTC is for modern compilers, -GZ is legacy !if [nmakehlp -c -RTC1] DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 !elseif [nmakehlp -c -GZ] DEBUGFLAGS = $(DEBUGFLAGS) -GZ !endif #---------------------------------------------------------------- # Linker flags # LINKER_TESTFLAGS are for internal use when we call nmakehlp to test # if the linker supports a specific option. Without these flags link will # return "LNK1561: entry point must be defined" error compiling from VS-IDE: # They are not passed through to the actual application / extension # link rules. !ifndef LINKER_TESTFLAGS LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmakehlp.out !endif LINKERFLAGS = # If compiler has enabled link time optimization, linker must too with -ltcg !ifdef CC_GL_OPT_ENABLED !if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS) -ltcg !endif !endif ################################################################ # 6. Extract various version numbers from headers |
| ︙ | ︙ | |||
708 709 710 711 712 713 714 | # DOTVERSION - set as (for example) 2.5 # VERSION - set as (for example 25) #-------------------------------------------------------------- !if [echo REM = This file is generated from rules.vc > versions.vc] !endif !if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ | | | | | | | | | | | | | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | # DOTVERSION - set as (for example) 2.5 # VERSION - set as (for example 25) #-------------------------------------------------------------- !if [echo REM = This file is generated from rules.vc > versions.vc] !endif !if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" "define TCL_MAJOR_VERSION" >> versions.vc] !endif !if [echo TCL_MINOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" "define TCL_MINOR_VERSION" >> versions.vc] !endif !if [echo TCL_RELEASE_SERIAL = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_RELEASE_SERIAL >> versions.vc] !endif !if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] !endif !if defined(_TK_H) !if [echo TK_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) "define TK_MAJOR_VERSION" >> versions.vc] !endif !if [echo TK_MINOR_VERSION = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc] !endif !if [echo TK_RELEASE_SERIAL = \>> versions.vc] \ && [nmakehlp -V "$(_TK_H)" TK_RELEASE_SERIAL >> versions.vc] !endif !if [echo TK_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] !endif !endif # _TK_H !include versions.vc TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) TCL_DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) !if [nmakehlp -f $(TCL_PATCH_LEVEL) "a"] TCL_PATCH_LETTER = a !elseif [nmakehlp -f $(TCL_PATCH_LEVEL) "b"] TCL_PATCH_LETTER = b !else TCL_PATCH_LETTER = . !endif !if defined(_TK_H) TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) !if [nmakehlp -f $(TK_PATCH_LEVEL) "a"] TK_PATCH_LETTER = a !elseif [nmakehlp -f $(TK_PATCH_LEVEL) "b"] TK_PATCH_LETTER = b !else TK_PATCH_LETTER = . !endif !endif |
| ︙ | ︙ | |||
778 779 780 781 782 783 784 | !else # Doing a non-Tk extension # If parent makefile has not defined DOTVERSION, try to get it from TEA # first from a configure.in file, and then from configure.ac !ifndef DOTVERSION !if [echo DOTVERSION = \> versions.vc] \ | | | | | 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 |
!else # Doing a non-Tk extension
# If parent makefile has not defined DOTVERSION, try to get it from TEA
# first from a configure.in file, and then from configure.ac
!ifndef DOTVERSION
!if [echo DOTVERSION = \> versions.vc] \
|| [nmakehlp -V $(ROOT)\configure.in ^[$(PROJECT)^] >> versions.vc]
!if [echo DOTVERSION = \> versions.vc] \
|| [nmakehlp -V $(ROOT)\configure.ac ^[$(PROJECT)^] >> versions.vc]
!error *** Could not figure out extension version. Please define DOTVERSION in parent makefile before including rules.vc.
!endif
!endif
!include versions.vc
!endif # DOTVERSION
VERSION = $(DOTVERSION:.=)
!endif # $(DOING_TCL) ... etc.
# Windows RC files have 3 version components. Ensure this irrespective
# of how many components the package has specified. Basically, ensure
# minimum 4 components by appending 4 0's and then pick out the first 4.
# Also take care of the fact that DOTVERSION may have "a" or "b" instead
# of "." separating the version components.
DOTSEPARATED=$(DOTVERSION:a=.)
DOTSEPARATED=$(DOTSEPARATED:b=.)
!if [echo RCCOMMAVERSION = \> versions.vc] \
|| [for /f "tokens=1,2,3,4,5* delims=." %a in ("$(DOTSEPARATED).0.0.0.0") do echo %a,%b,%c,%d >> versions.vc]
!error *** Could not generate RCCOMMAVERSION ***
!endif
!include versions.vc
########################################################################
# 7. Parse the OPTS macro to work out the requested build configuration.
# Based on this, we will construct the actual switches to be passed to the
|
| ︙ | ︙ | |||
850 851 852 853 854 855 856 | UNCHECKED = 0 CONFIG_CHECK = 1 !if $(DOING_TCL) USE_STUBS = 0 !else USE_STUBS = 1 !endif | < | | > | > | > | > | | > | > | > | > | > | > | > | > | > | | > | | > | < < < < < < < < < < | | | | | < < < | > | | > | > | | > | 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 | UNCHECKED = 0 CONFIG_CHECK = 1 !if $(DOING_TCL) USE_STUBS = 0 !else USE_STUBS = 1 !endif # If OPTS is not empty AND does not contain "none" which turns off all OPTS # set the above macros based on OPTS content !if "$(OPTS)" != "" && ![nmakehlp -f "$(OPTS)" "none"] # OPTS are specified, parse them !if [nmakehlp -f $(OPTS) "static"] !message *** Doing static STATIC_BUILD = 1 !endif !if [nmakehlp -f $(OPTS) "nostubs"] !message *** Not using stubs USE_STUBS = 0 !endif !if [nmakehlp -f $(OPTS) "nomsvcrt"] !message *** Doing nomsvcrt MSVCRT = 0 !else !if [nmakehlp -f $(OPTS) "msvcrt"] !message *** Doing msvcrt !else !if $(TCL_MAJOR_VERSION) == 8 && $(TCL_MINOR_VERSION) < 7 && $(STATIC_BUILD) MSVCRT = 0 !endif !endif !endif # [nmakehlp -f $(OPTS) "nomsvcrt"] !if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !endif !if [nmakehlp -f $(OPTS) "nothreads"] !message *** Compile explicitly for non-threaded tcl TCL_THREADS = 0 USE_THREAD_ALLOC= 0 !endif !if [nmakehlp -f $(OPTS) "tcl8"] !message *** Build for Tcl8 TCL_BUILD_FOR = 8 !endif !if $(TCL_MAJOR_VERSION) == 8 !if [nmakehlp -f $(OPTS) "time64bit"] !message *** Force 64-bit time_t _USE_64BIT_TIME_T = 1 !endif !endif # Yes, it's weird that the "symbols" option controls DEBUG and # the "pdbs" option controls SYMBOLS. That's historical. !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif !if [nmakehlp -f $(OPTS) "pdbs"] !message *** Doing pdbs SYMBOLS = 1 !else SYMBOLS = 0 !endif !if [nmakehlp -f $(OPTS) "profile"] !message *** Doing profile PROFILE = 1 !else PROFILE = 0 !endif !if [nmakehlp -f $(OPTS) "pgi"] !message *** Doing profile guided optimization instrumentation PGO = 1 !elseif [nmakehlp -f $(OPTS) "pgo"] !message *** Doing profile guided optimization PGO = 2 !else PGO = 0 !endif !if [nmakehlp -f $(OPTS) "loimpact"] !message *** Warning: ignoring option "loimpact" - deprecated on modern Windows. !endif # TBD - should get rid of this option !if [nmakehlp -f $(OPTS) "thrdalloc"] !message *** Doing thrdalloc USE_THREAD_ALLOC = 1 !endif !if [nmakehlp -f $(OPTS) "tclalloc"] USE_THREAD_ALLOC = 0 !endif !if [nmakehlp -f $(OPTS) "unchecked"] !message *** Doing unchecked UNCHECKED = 1 !else UNCHECKED = 0 !endif !if [nmakehlp -f $(OPTS) "noconfigcheck"] CONFIG_CHECK = 1 !else CONFIG_CHECK = 0 !endif !endif # "$(OPTS)" != "" && ... parsing of OPTS # Set linker flags based on above !if $(PGO) > 1 !if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize !else MSG=^ This compiler does not support profile guided optimization. !error $(MSG) !endif !elseif $(PGO) > 0 !if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument !else MSG=^ This compiler does not support profile guided optimization. !error $(MSG) !endif !endif ################################################################ # 8. Parse the STATS macro to configure code instrumentation # The following macros are set by this section: # TCL_MEM_DEBUG - 1 -> enables memory allocation instrumentation # 0 -> disables # TCL_COMPILE_DEBUG - 1 -> enables byte compiler logging # 0 -> disables # Default both are off TCL_MEM_DEBUG = 0 TCL_COMPILE_DEBUG = 0 !if "$(STATS)" != "" && ![nmakehlp -f "$(STATS)" "none"] !if [nmakehlp -f $(STATS) "memdbg"] !message *** Doing memdbg TCL_MEM_DEBUG = 1 !else TCL_MEM_DEBUG = 0 !endif !if [nmakehlp -f $(STATS) "compdbg"] !message *** Doing compdbg TCL_COMPILE_DEBUG = 1 !else TCL_COMPILE_DEBUG = 0 !endif !endif #################################################################### # 9. Parse the CHECKS macro to configure additional compiler checks # The following macros are set by this section: # WARNINGS - compiler switches that control the warnings level # TCL_NO_DEPRECATED - 1 -> disable support for deprecated functions # 0 -> enable deprecated functions # Defaults - Permit deprecated functions and warning level 3 TCL_NO_DEPRECATED = 0 WARNINGS = -W3 !if "$(CHECKS)" != "" && ![nmakehlp -f "$(CHECKS)" "none"] !if [nmakehlp -f $(CHECKS) "nodep"] !message *** Doing nodep check TCL_NO_DEPRECATED = 1 !endif !if [nmakehlp -f $(CHECKS) "fullwarn"] !message *** Doing full warnings check WARNINGS = -W4 !if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS) -warn:3 !endif !endif !if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] !message *** Doing 64bit portability warnings WARNINGS = $(WARNINGS) -Wp64 !endif !endif ################################################################ |
| ︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 |
# g = linked to the debug enabled C run-time.
# x = special static build when it links to the dynamic C run-time.
#
# The following macros are set in this section:
# SUFX - the suffix to use for binaries based on above naming convention
# BUILDDIRTOP - the toplevel default output directory
# is of the form {Release,Debug}[_AMD64][_COMPILERVERSION]
| < < < < < < < < < < < < < < < < < < < < < < < < < | 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
# g = linked to the debug enabled C run-time.
# x = special static build when it links to the dynamic C run-time.
#
# The following macros are set in this section:
# SUFX - the suffix to use for binaries based on above naming convention
# BUILDDIRTOP - the toplevel default output directory
# is of the form {Release,Debug}[_AMD64][_COMPILERVERSION]
# TMP_DIR - directory where object files are created
# OUT_DIR - directory where output executables are created
# Both TMP_DIR and OUT_DIR are defaulted only if not defined by the
# parent makefile (or command line). The default values are
# based on BUILDDIRTOP.
# STUBPREFIX - name of the stubs library for this project
# PRJIMPLIB - output path of the generated project import library
# PRJLIBNAME - name of generated project library
# PRJLIB - output path of generated project library
# PRJSTUBLIBNAME - name of the generated project stubs library
# PRJSTUBLIB - output path of the generated project stubs library
# RESFILE - output resource file (only if not static build)
SUFX = tsgx
!if $(DEBUG)
BUILDDIRTOP = Debug
!else
BUILDDIRTOP = Release
!endif
!if "$(MACHINE)" != "IX86"
BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE)
!endif
!if $(VCVER) > 6
BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER)
!endif
!if !$(DEBUG) || $(TCL_VERSION) > 86 || $(DEBUG) && $(UNCHECKED)
SUFX = $(SUFX:g=)
!endif
TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX
|
| ︙ | ︙ | |||
1152 1153 1154 1155 1156 1157 1158 | !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif # Relative paths -> absolute !if [echo OUT_DIR = \> nmakehlp.out] \ | | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 | !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif # Relative paths -> absolute !if [echo OUT_DIR = \> nmakehlp.out] \ || [nmakehlp -Q "$(OUT_DIR)" >> nmakehlp.out] !error *** Could not fully qualify path OUT_DIR=$(OUT_DIR) !endif !if [echo TMP_DIR = \>> nmakehlp.out] \ || [nmakehlp -Q "$(TMP_DIR)" >> nmakehlp.out] !error *** Could not fully qualify path TMP_DIR=$(TMP_DIR) !endif !include nmakehlp.out # The name of the stubs library for the project being built STUBPREFIX = $(PROJECT)stub |
| ︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 | DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include !else # extension other than Tk PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) !if $(MULTIPLATFORM_INSTALL) | | < | < < < < | > | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 | DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include !else # extension other than Tk PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) !if $(MULTIPLATFORM_INSTALL) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY) !else LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) !endif DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include !endif |
| ︙ | ︙ | |||
1698 1699 1700 1701 1702 1703 1704 |
@echo } else { >> $(OUT_DIR)\pkgIndex.tcl
@echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
[list load [file join $$dir $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl
@echo } >> $(OUT_DIR)\pkgIndex.tcl
!endif
default-pkgindex-tea:
| | | | > | < | < | | | | | | | | | | 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 |
@echo } else { >> $(OUT_DIR)\pkgIndex.tcl
@echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
[list load [file join $$dir $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl
@echo } >> $(OUT_DIR)\pkgIndex.tcl
!endif
default-pkgindex-tea:
@if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl
@PACKAGE_VERSION@ $(DOTVERSION)
@PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME)
@PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME)
@PKG_LIB_FILE@ $(PRJLIBNAME)
@PKG_LIB_FILE8@ $(PRJLIBNAME8)
@PKG_LIB_FILE9@ $(PRJLIBNAME9)
<<
default-install: default-install-binaries default-install-libraries
!if $(SYMBOLS)
default-install: default-install-pdbs
!endif
# Again to deal with historical brokenness, there is some confusion
# in terminlogy. For extensions, the "install-binaries" was used to
# locate target directory for *binary shared libraries* and thus
# the appropriate macro is LIB_INSTALL_DIR since BIN_INSTALL_DIR is
# for executables (exes). On the other hand the "install-libraries"
# target is for *scripts* and should have been called "install-scripts".
default-install-binaries: $(PRJLIB)
@echo Installing binaries to '$(LIB_INSTALL_DIR)'
@if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
@$(CPY) $(PRJLIB) "$(LIB_INSTALL_DIR)" >NUL
# Alias for default-install-scripts
default-install-libraries: default-install-scripts
default-install-scripts: $(OUT_DIR)\pkgIndex.tcl
@echo Installing libraries to '$(SCRIPT_INSTALL_DIR)'
@if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
@if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)"
@echo Installing package index in '$(SCRIPT_INSTALL_DIR)'
@$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR)
default-install-stubs:
@echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)'
@if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
@$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL
default-install-pdbs:
@echo Installing PDBs to '$(LIB_INSTALL_DIR)'
@if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
@$(CPY) "$(OUT_DIR)\*.pdb" "$(LIB_INSTALL_DIR)\"
# "emacs font-lock highlighting fix
default-install-docs-html:
@echo Installing documentation files to '$(DOC_INSTALL_DIR)'
@if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)"
@if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)"
default-install-docs-n:
@echo Installing documentation files to '$(DOC_INSTALL_DIR)'
@if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)"
@if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.n") do @$(COPY) %f "$(DOC_INSTALL_DIR)"
default-install-demos:
@echo Installing demos to '$(DEMO_INSTALL_DIR)'
@if not exist "$(DEMO_INSTALL_DIR)" mkdir "$(DEMO_INSTALL_DIR)"
@if exist $(DEMODIR) $(CPYDIR) "$(DEMODIR)" "$(DEMO_INSTALL_DIR)"
default-clean:
@echo Cleaning $(TMP_DIR)\* ...
@if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR)
@echo Cleaning $(WIN_DIR)\nmakehlp.obj, nmakehlp.exe ...
@if exist $(WIN_DIR)\nmakehlp.obj del $(WIN_DIR)\nmakehlp.obj
@if exist $(WIN_DIR)\nmakehlp.exe del $(WIN_DIR)\nmakehlp.exe
@if exist $(WIN_DIR)\nmakehlp.out del $(WIN_DIR)\nmakehlp.out
@echo Cleaning $(WIN_DIR)\nmhlp-out.txt ...
@if exist $(WIN_DIR)\nmhlp-out.txt del $(WIN_DIR)\nmhlp-out.txt
@echo Cleaning $(WIN_DIR)\_junk.pch ...
@if exist $(WIN_DIR)\_junk.pch del $(WIN_DIR)\_junk.pch
@echo Cleaning $(WIN_DIR)\vercl.x, vercl.i ...
@if exist $(WIN_DIR)\vercl.x del $(WIN_DIR)\vercl.x
@if exist $(WIN_DIR)\vercl.i del $(WIN_DIR)\vercl.i
@echo Cleaning $(WIN_DIR)\versions.vc, version.vc ...
@if exist $(WIN_DIR)\versions.vc del $(WIN_DIR)\versions.vc
@if exist $(WIN_DIR)\version.vc del $(WIN_DIR)\version.vc
default-hose: default-clean
@echo Hosing $(OUT_DIR)\* ...
@if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR)
|
| ︙ | ︙ | |||
1939 1940 1941 1942 1943 1944 1945 | !endif # !$(DOING_TCL) #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- | < < | 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 | !endif # !$(DOING_TCL) #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- !if !$(DOING_TCL) !message *** Building against Tcl at '$(_TCLDIR)' !endif !if !$(DOING_TK) && $(NEED_TK) !message *** Building against Tk at '$(_TKDIR)' !endif !message *** Intermediate directory will be '$(TMP_DIR)' !message *** Output directory will be '$(OUT_DIR)' !message *** Installation, if selected, will be in '$(_INSTALLDIR)' !message *** Suffix for binaries will be '$(SUFX)' !message *** Compiler version $(VCVER). Target $(MACHINE), host $(NATIVE_ARCH). !endif # ifdef _RULES_VC |
Changes to win/targets.vc.
| ︙ | ︙ | |||
48 49 50 51 52 53 54 | # Unlike the other default targets, these cannot be in rules.vc because # the executed command depends on existence of macro PRJ_HEADERS_PUBLIC # that the parent makefile will not define until after including rules-ext.vc !if "$(PRJ_HEADERS_PUBLIC)" != "" default-install: default-install-headers default-install-headers: | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | # Unlike the other default targets, these cannot be in rules.vc because # the executed command depends on existence of macro PRJ_HEADERS_PUBLIC # that the parent makefile will not define until after including rules-ext.vc !if "$(PRJ_HEADERS_PUBLIC)" != "" default-install: default-install-headers default-install-headers: @echo Installing headers to '$(INCLUDE_INSTALL_DIR)' @if not exist "$(INCLUDE_INSTALL_DIR)" $(MKDIR) "$(INCLUDE_INSTALL_DIR)" @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)" !endif !if "$(DISABLE_STANDARD_TARGETS)" == "" DISABLE_STANDARD_TARGETS = 0 !endif |
| ︙ | ︙ |
Changes to win/tcl.dsp.
| ︙ | ︙ | |||
1268 1269 1270 1271 1272 1273 1274 | # End Source File # Begin Source File SOURCE=..\generic\tclThread.c # End Source File # Begin Source File | | > > > > | 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | # End Source File # Begin Source File SOURCE=..\generic\tclThread.c # End Source File # Begin Source File SOURCE=..\generic\tclThreadJoin.c # End Source File # Begin Source File SOURCE=..\generic\tclThreadTest.c # End Source File # Begin Source File SOURCE=..\generic\tclTimer.c # End Source File # Begin Source File SOURCE=..\generic\tclUniData.c # End Source File # Begin Source File SOURCE=..\generic\tclUtf.c # End Source File # Begin Source File SOURCE=..\generic\tclUtil.c # End Source File |
| ︙ | ︙ |
Changes to win/tcl.m4.
| ︙ | ︙ | |||
644 645 646 647 648 649 650 |
AC_MSG_CHECKING([compiler flags])
if test "${GCC}" = "yes" ; then
SHLIB_LD=""
SHLIB_LD_LIBS='${LIBS}'
LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32"
# mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't
| | | 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
AC_MSG_CHECKING([compiler flags])
if test "${GCC}" = "yes" ; then
SHLIB_LD=""
SHLIB_LD_LIBS='${LIBS}'
LIBS="-lnetapi32 -lkernel32 -luser32 -ladvapi32 -luserenv -lws2_32"
# mingw needs to link ole32 and oleaut32 for [send], but MSVC doesn't
LIBS_GUI="-lgdi32 -lcomdlg32 -limm32 -lcomctl32 -lshell32 -luuid -lole32 -loleaut32 -lwinspool"
STLIB_LD='${AR} cr'
RC_OUT=-o
RC_TYPE=
RC_INCLUDE=--include
RC_DEFINE=--define
RES=res.o
MAKE_LIB="\${STLIB_LD} \[$]@"
|
| ︙ | ︙ | |||
833 834 835 836 837 838 839 |
CFLAGS_DEBUG="-nologo -Z7 -Od -WX ${runtime}d"
# -O2 - create fast code (/Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy)
CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}"
lflags="${lflags} -nologo"
LINKBIN="link"
fi
| | | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 |
CFLAGS_DEBUG="-nologo -Z7 -Od -WX ${runtime}d"
# -O2 - create fast code (/Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy)
CFLAGS_OPTIMIZE="-nologo -O2 ${runtime}"
lflags="${lflags} -nologo"
LINKBIN="link"
fi
LIBS_GUI="gdi32.lib comdlg32.lib imm32.lib comctl32.lib shell32.lib uuid.lib winspool.lib"
SHLIB_LD="${LINKBIN} -dll -incremental:no ${lflags}"
SHLIB_LD_LIBS='${LIBS}'
# link -lib only works when -lib is the first arg
STLIB_LD="${LINKBIN} -lib ${lflags}"
RC_OUT=-fo
RC_TYPE=-r
|
| ︙ | ︙ | |||
878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
fi
if test "$do64bit" != "no" ; then
AC_DEFINE(TCL_CFG_DO64BIT)
fi
if test "${GCC}" = "yes" ; then
#
# Check to see if the excpt.h include file provided contains the
# definition for EXCEPTION_DISPOSITION; if not, which is the case
# with Cygwin's version as of 2002-04-10, define it to be int,
# sufficient for getting the current code to work.
#
AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files,
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 |
fi
if test "$do64bit" != "no" ; then
AC_DEFINE(TCL_CFG_DO64BIT)
fi
if test "${GCC}" = "yes" ; then
AC_CACHE_CHECK(for SEH support in compiler,
tcl_cv_seh,
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
int main(int argc, char** argv) {
int a, b = 0;
__try {
a = 666 / b;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
return 0;
}
return 1;
}
]])],
[tcl_cv_seh=yes],
[tcl_cv_seh=no],
[tcl_cv_seh=no])
)
if test "$tcl_cv_seh" = "no" ; then
AC_DEFINE(HAVE_NO_SEH, 1,
[Defined when mingw does not support SEH])
fi
#
# Check to see if the excpt.h include file provided contains the
# definition for EXCEPTION_DISPOSITION; if not, which is the case
# with Cygwin's version as of 2002-04-10, define it to be int,
# sufficient for getting the current code to work.
#
AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files,
|
| ︙ | ︙ | |||
946 947 948 949 950 951 952 | # --with-tcl=... # # Defines the following vars: # TCL_BIN_DIR Full path to the tcl build dir. #------------------------------------------------------------------------ AC_DEFUN([SC_WITH_TCL], [ | | | | | 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 |
# --with-tcl=...
#
# Defines the following vars:
# TCL_BIN_DIR Full path to the tcl build dir.
#------------------------------------------------------------------------
AC_DEFUN([SC_WITH_TCL], [
if test -d ../../tcl9.0$1/win; then
TCL_BIN_DEFAULT=../../tcl9.0$1/win
else
TCL_BIN_DEFAULT=../../tcl9.0/win
fi
AC_ARG_WITH(tcl, [ --with-tcl=DIR use Tcl 9.x binaries from DIR],
TCL_BIN_DIR=$withval, TCL_BIN_DIR=`cd $TCL_BIN_DEFAULT; pwd`)
if test ! -d $TCL_BIN_DIR; then
AC_MSG_ERROR(Tcl directory $TCL_BIN_DIR does not exist)
fi
|
| ︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 |
if test x"${with_tcencoding}" != x ; then
AC_DEFINE_UNQUOTED(TCL_CFGVAL_ENCODING,"${with_tcencoding}")
else
AC_DEFINE(TCL_CFGVAL_ENCODING,"utf-8")
fi
])
#------------------------------------------------------------------------
# SC_CC_FOR_BUILD
# For cross compiles, locate a C compiler that can generate native binaries.
#
# Arguments:
# none
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 |
if test x"${with_tcencoding}" != x ; then
AC_DEFINE_UNQUOTED(TCL_CFGVAL_ENCODING,"${with_tcencoding}")
else
AC_DEFINE(TCL_CFGVAL_ENCODING,"utf-8")
fi
])
#--------------------------------------------------------------------
# SC_EMBED_MANIFEST
#
# Figure out if we can embed the manifest where necessary
#
# Arguments:
# An optional manifest to merge into DLL/EXE.
#
# Results:
# Will define the following vars:
# VC_MANIFEST_EMBED_DLL
# VC_MANIFEST_EMBED_EXE
#
#--------------------------------------------------------------------
AC_DEFUN([SC_EMBED_MANIFEST], [
AC_MSG_CHECKING(whether to embed manifest)
AC_ARG_ENABLE(embedded-manifest,
AS_HELP_STRING([--enable-embedded-manifest],
[embed manifest if possible (default: yes)]),
[embed_ok=$enableval], [embed_ok=yes])
VC_MANIFEST_EMBED_DLL=
VC_MANIFEST_EMBED_EXE=
result=no
if test "$embed_ok" = "yes" -a "${SHARED_BUILD}" = "1" \
-a "$GCC" != "yes" ; then
# Add the magic to embed the manifest into the dll/exe
AC_EGREP_CPP([manifest needed], [
#if defined(_MSC_VER) && _MSC_VER >= 1400
print("manifest needed")
#endif
], [
# Could do a CHECK_PROG for mt, but should always be with MSVC8+
# Could add 'if test -f' check, but manifest should be created
# in this compiler case
# Add in a manifest argument that may be specified
# XXX Needs improvement so that the test for existence accounts
# XXX for a provided (known) manifest
VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest $1 -outputresource:\[$]@\;2 ; fi"
VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest $1 -outputresource:\[$]@\;1 ; fi"
result=yes
if test "x$1" != x ; then
result="yes ($1)"
fi
])
fi
AC_MSG_RESULT([$result])
AC_SUBST(VC_MANIFEST_EMBED_DLL)
AC_SUBST(VC_MANIFEST_EMBED_EXE)
])
#------------------------------------------------------------------------
# SC_CC_FOR_BUILD
# For cross compiles, locate a C compiler that can generate native binaries.
#
# Arguments:
# none
|
| ︙ | ︙ |
Changes to win/tcl.rc.
1 2 3 4 5 6 | // // Version Resource Script // #include <winver.h> #include <tcl.h> | < < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
//
// Version Resource Script
//
#include <winver.h>
#include <tcl.h>
//
// build-up the name suffix that defines the type of build this is.
//
#if DEBUG && !UNCHECKED
#define SUFFIX_DEBUG "g"
#else
#define SUFFIX_DEBUG ""
#endif
#define SUFFIX SUFFIX_DEBUG
LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */
VS_VERSION_INFO VERSIONINFO
FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL
PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL
FILEFLAGSMASK 0x3fL
#ifdef DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
BEGIN
VALUE "FileDescription", "Tcl DLL\0"
VALUE "OriginalFilename", "tcl" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) SUFFIX ".dll\0"
VALUE "FileVersion", TCL_PATCH_LEVEL
VALUE "LegalCopyright", "Copyright \251 1987-2022 Regents of the University of California and other parties\0"
VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
VALUE "ProductVersion", TCL_PATCH_LEVEL
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
|
Changes to win/tclAppInit.c.
1 2 3 4 5 6 7 8 | /* * tclAppInit.c -- * * Provides a default version of the main program and Tcl_AppInit * procedure for tclsh and other Tcl-based applications (without Tk). * Note that this program must be built in Win32 console mode to work * properly. * | | | | < > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/*
* tclAppInit.c --
*
* Provides a default version of the main program and Tcl_AppInit
* procedure for tclsh and other Tcl-based applications (without Tk).
* Note that this program must be built in Win32 console mode to work
* properly.
*
* Copyright (c) 1993 The Regents of the University of California.
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
* Copyright (c) 1998-1999 Scriptics Corporation.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tcl.h"
#if TCL_MAJOR_VERSION < 9
# if defined(USE_TCL_STUBS)
# error "Don't build with USE_TCL_STUBS!"
# endif
# define Tcl_LibraryInitProc Tcl_PackageInitProc
# define Tcl_StaticLibrary Tcl_StaticPackage
#endif
#ifdef TCL_TEST
#ifdef __cplusplus
extern "C" {
#endif
extern Tcl_LibraryInitProc Tcltest_Init;
extern Tcl_LibraryInitProc Tcltest_SafeInit;
#ifdef __cplusplus
}
#endif
#endif /* TCL_TEST */
#if defined(STATIC_BUILD)
extern Tcl_LibraryInitProc Registry_Init;
extern Tcl_LibraryInitProc Dde_Init;
extern Tcl_LibraryInitProc Dde_SafeInit;
#endif
#define WIN32_LEAN_AND_MEAN
#define STRICT /* See MSDN Article Q83456 */
#include <windows.h>
#undef STRICT
#undef WIN32_LEAN_AND_MEAN
#include <locale.h>
|
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | #define TCL_LOCAL_APPINIT Tcl_AppInit #endif #ifndef MODULE_SCOPE # define MODULE_SCOPE extern #endif MODULE_SCOPE int TCL_LOCAL_APPINIT(Tcl_Interp *); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | #define TCL_LOCAL_APPINIT Tcl_AppInit #endif #ifndef MODULE_SCOPE # define MODULE_SCOPE extern #endif MODULE_SCOPE int TCL_LOCAL_APPINIT(Tcl_Interp *); /* * The following #if block allows you to change how Tcl finds the startup * script, prime the library or encoding paths, fiddle with the argv, etc., * without needing to rewrite Tcl_Main() */ #ifdef TCL_LOCAL_MAIN_HOOK MODULE_SCOPE int TCL_LOCAL_MAIN_HOOK(int *argc, TCHAR ***argv); #endif /* *---------------------------------------------------------------------- * * main -- * * This is the main program for the application. |
| ︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
int
_tmain(
int argc, /* Number of command-line arguments. */
TCHAR *argv[]) /* Values of command-line arguments. */
{
TCHAR *p;
/*
* Forward slashes substituted for backslashes.
*/
for (p = argv[0]; *p != '\0'; p++) {
if (*p == '\\') {
*p = '/';
}
}
#ifdef TCL_LOCAL_MAIN_HOOK
TCL_LOCAL_MAIN_HOOK(&argc, &argv);
#elif TCL_MAJOR_VERSION > 8 && (!defined(_WIN32) || defined(UNICODE))
/* New in Tcl 9.0. This doesn't work on Windows without UNICODE */
TclZipfs_AppHook(&argc, &argv);
#endif
| > > > > > > > < < < < | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
int
_tmain(
int argc, /* Number of command-line arguments. */
TCHAR *argv[]) /* Values of command-line arguments. */
{
TCHAR *p;
/*
* Set up the default locale to be standard "C" locale so parsing is
* performed correctly.
*/
setlocale(LC_ALL, "C");
/*
* Forward slashes substituted for backslashes.
*/
for (p = argv[0]; *p != '\0'; p++) {
if (*p == '\\') {
*p = '/';
}
}
#ifdef TCL_LOCAL_MAIN_HOOK
TCL_LOCAL_MAIN_HOOK(&argc, &argv);
#elif TCL_MAJOR_VERSION > 8 && (!defined(_WIN32) || defined(UNICODE))
/* New in Tcl 9.0. This doesn't work on Windows without UNICODE */
TclZipfs_AppHook(&argc, &argv);
#endif
Tcl_Main(argc, argv, TCL_LOCAL_APPINIT);
return 0; /* Needed only to prevent compiler warning. */
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
Tcl_AppInit(
Tcl_Interp *interp) /* Interpreter for application. */
{
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
/*
* Call the init procedures for included packages. Each call should look
* like this:
*
* if (Mod_Init(interp) == TCL_ERROR) {
* return TCL_ERROR;
* }
| > > > > > > > > > > > > > | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
Tcl_AppInit(
Tcl_Interp *interp) /* Interpreter for application. */
{
if (Tcl_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
#if defined(STATIC_BUILD)
Tcl_StaticLibrary(NULL, "Registry", Registry_Init, NULL);
Tcl_StaticLibrary(NULL, "Dde", Dde_Init, Dde_SafeInit);
#endif
#ifdef TCL_TEST
if (Tcltest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
Tcl_StaticLibrary(interp, "Tcltest", Tcltest_Init, Tcltest_SafeInit);
#endif /* TCL_TEST */
/*
* Call the init procedures for included packages. Each call should look
* like this:
*
* if (Mod_Init(interp) == TCL_ERROR) {
* return TCL_ERROR;
* }
|
| ︙ | ︙ | |||
210 211 212 213 214 215 216 |
*/
/*
* Specify a user-specific startup file to invoke if the application is
* run interactively. Typically the startup file is "~/.apprc" where "app"
* is the name of the application. If this line is deleted then no
* user-specific startup file will be run under any conditions.
| < < | > > > | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
*/
/*
* Specify a user-specific startup file to invoke if the application is
* run interactively. Typically the startup file is "~/.apprc" where "app"
* is the name of the application. If this line is deleted then no
* user-specific startup file will be run under any conditions.
*/
(void)Tcl_EvalEx(interp,
"set tcl_rcFileName [file tildeexpand ~/tclshrc.tcl]",
TCL_AUTO_LENGTH, TCL_EVAL_GLOBAL);
return TCL_OK;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to win/tclWin32Dll.c.
| ︙ | ︙ | |||
445 446 447 448 449 450 451 | * instruction in the four integers designated by 'regsPtr' * *---------------------------------------------------------------------- */ int TclWinCPUID( | | | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
* instruction in the four integers designated by 'regsPtr'
*
*----------------------------------------------------------------------
*/
int
TclWinCPUID(
int index, /* Which CPUID value to retrieve. */
int *regsPtr) /* Registers after the CPUID. */
{
int status = TCL_ERROR;
#if defined(HAVE_CPUID_H)
unsigned int *regs = (unsigned int *)regsPtr;
__get_cpuid(index, ®s[0], ®s[1], ®s[2], ®s[3]);
|
| ︙ | ︙ |
Changes to win/tclWinChan.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | #include "tclWinInt.h" #include "tclFileSystem.h" #include "tclIO.h" /* * State flags used in the info structures below. */ | | | | | < < | | < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include "tclWinInt.h"
#include "tclFileSystem.h"
#include "tclIO.h"
/*
* State flags used in the info structures below.
*/
#define FILE_PENDING (1<<0) /* Message is pending in the queue. */
#define FILE_ASYNC (1<<1) /* Channel is non-blocking. */
#define FILE_APPEND (1<<2) /* File is in append mode. */
#define FILE_TYPE_SERIAL (FILE_TYPE_PIPE+1)
#define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2)
/*
* The following structure contains per-instance data for a file based
* channel.
*/
typedef struct FileInfo {
|
| ︙ | ︙ | |||
240 241 242 243 244 245 246 | * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ | | > | | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
*
* Side effects:
* Adjusts the block time if needed.
*
*----------------------------------------------------------------------
*/
void
FileSetupProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
FileInfo *infoPtr;
Tcl_Time blockTime = { 0, 0 };
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!TEST_FLAG(flags, TCL_FILE_EVENTS)) {
return;
}
/*
* Check to see if there is a ready file. If so, poll.
*/
for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
infoPtr = infoPtr->nextPtr) {
if (infoPtr->watchMask) {
Tcl_SetMaxBlockTime(&blockTime);
break;
}
}
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
383 384 385 386 387 388 389 | * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ static int FileBlockProc( | | | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
* Sets the device into blocking or non-blocking mode.
*
*----------------------------------------------------------------------
*/
static int
FileBlockProc(
void *instanceData, /* Instance data for channel. */
int mode) /* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
/*
* Files on Windows can not be switched between blocking and nonblocking,
|
| ︙ | ︙ | |||
422 423 424 425 426 427 428 | * Closes the physical channel * *---------------------------------------------------------------------- */ static int FileCloseProc( | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
* Closes the physical channel
*
*----------------------------------------------------------------------
*/
static int
FileCloseProc(
void *instanceData, /* Pointer to FileInfo structure. */
TCL_UNUSED(Tcl_Interp *),
int flags)
{
FileInfo *fileInfoPtr = (FileInfo *)instanceData;
FileInfo *infoPtr;
ThreadSpecificData *tsdPtr;
int errorCode = 0;
|
| ︙ | ︙ | |||
500 501 502 503 504 505 506 | * operations. * *---------------------------------------------------------------------- */ static long long FileWideSeekProc( | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
* operations.
*
*----------------------------------------------------------------------
*/
static long long
FileWideSeekProc(
void *instanceData, /* File state. */
long long offset, /* Offset to seek to. */
int mode, /* Relative to where should we seek? */
int *errorCodePtr) /* To store error code. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
DWORD moveMethod;
LONG newPos, newPosHigh;
|
| ︙ | ︙ | |||
552 553 554 555 556 557 558 | * Truncates the file, may move file pointers too. * *---------------------------------------------------------------------- */ static int FileTruncateProc( | | | 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
* Truncates the file, may move file pointers too.
*
*----------------------------------------------------------------------
*/
static int
FileTruncateProc(
void *instanceData, /* File state. */
long long length) /* Length to truncate at. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
LONG newPos, newPosHigh, oldPos, oldPosHigh;
/*
* Save where we were...
|
| ︙ | ︙ | |||
628 629 630 631 632 633 634 | * Reads input from the actual channel. * *---------------------------------------------------------------------- */ static int FileInputProc( | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 |
* Reads input from the actual channel.
*
*----------------------------------------------------------------------
*/
static int
FileInputProc(
void *instanceData, /* File state. */
char *buf, /* Where to store data read. */
int bufSize, /* Num bytes available in buffer. */
int *errorCode) /* Where to store error code. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
DWORD bytesRead;
|
| ︙ | ︙ | |||
683 684 685 686 687 688 689 | * Writes output on the actual channel. * *---------------------------------------------------------------------- */ static int FileOutputProc( | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 |
* Writes output on the actual channel.
*
*----------------------------------------------------------------------
*/
static int
FileOutputProc(
void *instanceData, /* File state. */
const char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
DWORD bytesWritten;
|
| ︙ | ︙ | |||
730 731 732 733 734 735 736 | * None. * *---------------------------------------------------------------------- */ static void FileWatchProc( | | > | | 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 |
* None.
*
*----------------------------------------------------------------------
*/
static void
FileWatchProc(
void *instanceData, /* File state. */
int mask) /* What events to watch for; OR-ed combination
* of TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
Tcl_Time blockTime = { 0, 0 };
/*
* Since the file is always ready for events, we set the block time to
* zero so we will poll.
*/
infoPtr->watchMask = mask & infoPtr->validMask;
if (infoPtr->watchMask) {
Tcl_SetMaxBlockTime(&blockTime);
}
}
/*
*----------------------------------------------------------------------
*
* FileGetHandleProc --
|
| ︙ | ︙ | |||
768 769 770 771 772 773 774 | * None. * *---------------------------------------------------------------------- */ static int FileGetHandleProc( | | | | 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 |
* None.
*
*----------------------------------------------------------------------
*/
static int
FileGetHandleProc(
void *instanceData, /* The file state. */
int direction, /* TCL_READABLE or TCL_WRITABLE */
void **handlePtr) /* Where to store the handle. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
if (!TEST_FLAG(direction, infoPtr->validMask)) {
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
831 832 833 834 835 836 837 |
static Tcl_Obj *
StatOpenFile(
FileInfo *infoPtr)
{
DWORD attr;
int dev, nlink = 1;
| | | 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
static Tcl_Obj *
StatOpenFile(
FileInfo *infoPtr)
{
DWORD attr;
int dev, nlink = 1;
unsigned short mode;
unsigned long long size, inode;
long long atime, ctime, mtime;
BY_HANDLE_FILE_INFORMATION data;
Tcl_Obj *dictObj;
if (GetFileInformationByHandle(infoPtr->handle, &data) != TRUE) {
Tcl_SetErrno(ENOENT);
|
| ︙ | ︙ | |||
865 866 867 868 869 870 871 |
dev = data.dwVolumeSerialNumber;
/*
* Note that this code has no idea whether the file can be executed.
*/
mode = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR|S_IEXEC : S_IFREG;
| | | | | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 |
dev = data.dwVolumeSerialNumber;
/*
* Note that this code has no idea whether the file can be executed.
*/
mode = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR|S_IEXEC : S_IFREG;
mode |= (attr & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE;
mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 3;
mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 6;
/*
* We don't construct a Tcl_StatBuf; we're using the info immediately.
*/
TclNewObj(dictObj);
#define STORE_ELEM(name, value) TclDictPut(NULL, dictObj, name, value)
|
| ︙ | ︙ | |||
903 904 905 906 907 908 909 |
#undef STORE_ELEM
return dictObj;
}
static int
FileGetOptionProc(
| | | | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 |
#undef STORE_ELEM
return dictObj;
}
static int
FileGetOptionProc(
void *instanceData, /* The file state. */
Tcl_Interp *interp, /* For error reporting. */
const char *optionName, /* What option to read, or NULL for all. */
Tcl_DString *dsPtr) /* Where to write the value read. */
{
FileInfo *infoPtr = (FileInfo *)instanceData;
int valid = 0; /* Flag if valid option parsed. */
int len;
if (optionName == NULL) {
len = 0;
valid = 1;
} else {
len = strlen(optionName);
}
|
| ︙ | ︙ | |||
952 953 954 955 956 957 958 |
Tcl_DecrRefCount(dictObj);
return TCL_OK;
}
if (valid) {
return TCL_OK;
}
| | > | 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 |
Tcl_DecrRefCount(dictObj);
return TCL_OK;
}
if (valid) {
return TCL_OK;
}
return Tcl_BadChannelOption(interp, optionName,
"stat");
}
/*
*----------------------------------------------------------------------
*
* TclpOpenFileChannel --
*
|
| ︙ | ︙ | |||
1000 1001 1002 1003 1004 1005 1006 | /* * We need this just to ensure we return the correct error messages under * some circumstances (relative paths only), so because the normalization * is very expensive, don't invoke it for native or absolute paths. * Note: since paths starting with ~ are relative in 9.0 for windows, * it doesn't need to consider tilde expansion (in opposite to 8.x). */ | > > | | > | > | 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 |
/*
* We need this just to ensure we return the correct error messages under
* some circumstances (relative paths only), so because the normalization
* is very expensive, don't invoke it for native or absolute paths.
* Note: since paths starting with ~ are relative in 9.0 for windows,
* it doesn't need to consider tilde expansion (in opposite to 8.x).
*/
if (
(
!TclFSCwdIsNative() &&
(Tcl_FSGetPathType(pathPtr) != TCL_PATH_ABSOLUTE)
) &&
Tcl_FSGetNormalizedPath(interp, pathPtr) == NULL
) {
return NULL;
}
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't open \"%s\": filename is invalid on this platform",
TclGetString(pathPtr)));
}
|
| ︙ | ︙ | |||
1213 1214 1215 1216 1217 1218 1219 | * None. * *---------------------------------------------------------------------- */ Tcl_Channel Tcl_MakeFileChannel( | | > > > | 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 |
* None.
*
*----------------------------------------------------------------------
*/
Tcl_Channel
Tcl_MakeFileChannel(
void *rawHandle, /* OS level handle */
int mode) /* OR'ed combination of TCL_READABLE and
* TCL_WRITABLE to indicate file mode. */
{
#if defined(HAVE_NO_SEH) && !defined(_WIN64) && !defined(__clang__)
TCLEXCEPTION_REGISTRATION registration;
#endif
char channelName[16 + TCL_INTEGER_SPACE];
Tcl_Channel channel = NULL;
HANDLE handle = (HANDLE) rawHandle;
HANDLE dupedHandle;
TclFile readFile = NULL, writeFile = NULL;
BOOL result;
|
| ︙ | ︙ | |||
1280 1281 1282 1283 1284 1285 1286 | /* * Use structured exception handling (Win32 SEH) to protect the close * of this duped handle which might throw EXCEPTION_INVALID_HANDLE. */ result = 0; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 |
/*
* Use structured exception handling (Win32 SEH) to protect the close
* of this duped handle which might throw EXCEPTION_INVALID_HANDLE.
*/
result = 0;
#if defined(HAVE_NO_SEH) && !defined(_WIN64) && !defined(__clang__)
/*
* Don't have SEH available, do things the hard way. Note that this
* needs to be one block of asm, to avoid stack imbalance; also, it is
* illegal for one asm block to contain a jump to another.
*/
__asm__ __volatile__ (
/*
* Pick up parameters before messing with the stack
*/
"movl %[dupedHandle], %%ebx" "\n\t"
/*
* Construct an TCLEXCEPTION_REGISTRATION to protect the call to
* CloseHandle.
*/
"leal %[registration], %%edx" "\n\t"
"movl %%fs:0, %%eax" "\n\t"
"movl %%eax, 0x0(%%edx)" "\n\t" /* link */
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
"movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
"movl $0, 0x10(%%edx)" "\n\t" /* status */
/*
* Link the TCLEXCEPTION_REGISTRATION on the chain.
*/
"movl %%edx, %%fs:0" "\n\t"
/*
* Call CloseHandle(dupedHandle).
*/
"pushl %%ebx" "\n\t"
"call _CloseHandle@4" "\n\t"
/*
* Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION
* and put a TRUE status return into it.
*/
"movl %%fs:0, %%edx" "\n\t"
"movl $1, %%eax" "\n\t"
"movl %%eax, 0x10(%%edx)" "\n\t"
"jmp 2f" "\n"
/*
* Come here on an exception. Recover the TCLEXCEPTION_REGISTRATION
*/
"1:" "\t"
"movl %%fs:0, %%edx" "\n\t"
"movl 0x8(%%edx), %%edx" "\n\t"
/*
* Come here however we exited. Restore context from the
* TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
*/
"2:" "\t"
"movl 0xC(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
:
/* No outputs */
:
[registration] "m" (registration),
[dupedHandle] "m" (dupedHandle)
:
"%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
);
result = registration.status;
#else
#ifndef HAVE_NO_SEH
__try {
#endif
CloseHandle(dupedHandle);
result = 1;
#ifndef HAVE_NO_SEH
} __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif
#endif
if (result == FALSE) {
return NULL;
}
/*
* Fall through, the handle is valid.
*
|
| ︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 | * Side effects: * May open the channel and may cause creation of a file on the file * system. * *---------------------------------------------------------------------- */ | | | 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 |
* Side effects:
* May open the channel and may cause creation of a file on the file
* system.
*
*----------------------------------------------------------------------
*/
Tcl_Channel
OpenFileChannel(
HANDLE handle, /* Win32 HANDLE to swallow */
char *channelName, /* Buffer to receive channel name */
int permissions, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION, indicating
* which operations are valid on the file. */
int appendMode) /* OR'ed combination of bits indicating what
|
| ︙ | ︙ | |||
1558 1559 1560 1561 1562 1563 1564 | * * Side effects: * None. * *---------------------------------------------------------------------- */ | | | 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 |
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
DWORD
FileGetType(
HANDLE handle) /* Opened file handle */
{
DWORD type;
type = GetFileType(handle);
|
| ︙ | ︙ | |||
1591 1592 1593 1594 1595 1596 1597 |
}
}
}
return type;
}
| | | 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 |
}
}
}
return type;
}
/*
*----------------------------------------------------------------------
*
* NativeIsComPort --
*
* Determines if a path refers to a Windows serial port. A simple and
* efficient solution is to use a "name hint" to detect COM ports by
* their filename instead of resorting to a syscall to detect serialness
|
| ︙ | ︙ |
Changes to win/tclWinConsole.c.
| ︙ | ︙ | |||
271 272 273 274 275 276 277 |
/*
* Static data.
*/
typedef struct {
/* Currently this struct is only used to detect thread initialization */
| | | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
/*
* Static data.
*/
typedef struct {
/* Currently this struct is only used to detect thread initialization */
int notUsed; /* Dummy field */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
* All access to static data is controlled through a single process-wide
* lock. A process can have only a single console at a time, with three
* handles for stdin, stdout and stderr. Creation/destruction of consoles is
|
| ︙ | ︙ | |||
324 325 326 327 328 329 330 |
ConsoleBlockModeProc,
NULL, /* Flush proc. */
NULL, /* Bubbled event handler proc. */
NULL, /* Seek proc. */
ConsoleThreadActionProc,
NULL /* Truncation proc. */
};
| | | | | | 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
ConsoleBlockModeProc,
NULL, /* Flush proc. */
NULL, /* Bubbled event handler proc. */
NULL, /* Seek proc. */
ConsoleThreadActionProc,
NULL /* Truncation proc. */
};
/*
*------------------------------------------------------------------------
*
* RingBufferInit --
*
* Initializes the ring buffer to a given size.
*
* Results:
* None.
*
* Side effects:
* Panics on allocation failure.
*
*------------------------------------------------------------------------
*/
static void
RingBufferInit(
RingBuffer *ringPtr,
Tcl_Size capacity)
|
| ︙ | ︙ | |||
359 360 361 362 363 364 365 | } /* *------------------------------------------------------------------------ * * RingBufferClear * | | | | | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
}
/*
*------------------------------------------------------------------------
*
* RingBufferClear
*
* Clears the contents of a ring buffer.
*
* Results:
* None.
*
* Side effects:
* The allocated internal buffer is freed.
*
*------------------------------------------------------------------------
*/
static void
RingBufferClear(
RingBuffer *ringPtr)
{
|
| ︙ | ︙ | |||
387 388 389 390 391 392 393 | } /* *------------------------------------------------------------------------ * * RingBufferIn -- * | | | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
}
/*
*------------------------------------------------------------------------
*
* RingBufferIn --
*
* Appends data to the ring buffer.
*
* Results:
* Returns number of bytes copied.
*
* Side effects:
* Internal buffer is updated.
*
*------------------------------------------------------------------------
*/
static Tcl_Size
RingBufferIn(
RingBuffer *ringPtr,
const char *srcPtr, /* Source to be copied */
|
| ︙ | ︙ | |||
448 449 450 451 452 453 454 | } /* *------------------------------------------------------------------------ * * RingBufferOut -- * | | | | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 |
}
/*
*------------------------------------------------------------------------
*
* RingBufferOut --
*
* Moves data out of the ring buffer. If dstPtr is NULL, the data
* is simply removed.
*
* Results:
* Returns number of bytes copied or removed.
*
* Side effects:
* Internal buffer is updated.
*
*------------------------------------------------------------------------
*/
static Tcl_Size
RingBufferOut(
RingBuffer *ringPtr,
char *dstPtr, /* Buffer for output data. May be NULL */
|
| ︙ | ︙ | |||
524 525 526 527 528 529 530 | #endif /* *------------------------------------------------------------------------ * * ReadConsoleChars -- * | | | | | | | 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
#endif
/*
*------------------------------------------------------------------------
*
* ReadConsoleChars --
*
* Wrapper for ReadConsoleW.
*
* Results:
* Returns 0 on success, else Windows error code.
*
* Side effects:
* On success the number of characters (not bytes) read is stored in
* *nCharsReadPtr. This will be 0 if the operation was interrupted by
* a Ctrl-C or a CancelIo call.
*
*------------------------------------------------------------------------
*/
static DWORD
ReadConsoleChars(
HANDLE hConsole,
WCHAR *lpBuffer,
|
| ︙ | ︙ | |||
565 566 567 568 569 570 571 |
* In both cases above we will return success but with nbytesread as 0.
* This allows caller to check for thread termination etc.
*
* See https://bugs.python.org/issue30237
* or https://github.com/microsoft/terminal/issues/12143
*/
nRead = (DWORD)-1;
| | | | | | | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
* In both cases above we will return success but with nbytesread as 0.
* This allows caller to check for thread termination etc.
*
* See https://bugs.python.org/issue30237
* or https://github.com/microsoft/terminal/issues/12143
*/
nRead = (DWORD)-1;
if (!ReadConsoleW(hConsole, lpBuffer, nChars, &nRead, NULL)) {
return GetLastError();
}
if ((nRead == 0 || nRead == (DWORD)-1)
&& GetLastError() == ERROR_OPERATION_ABORTED) {
nRead = 0;
}
*nCharsReadPtr = nRead;
return 0;
}
/*
*------------------------------------------------------------------------
*
* WriteConsoleChars --
*
* Wrapper for WriteConsoleW.
*
* Results:
* Returns 0 on success, Windows error code on failure.
*
* Side effects:
* On success the number of characters (not bytes) written is stored in
* *nCharsWrittenPtr. This will be 0 if the operation was interrupted by
* a Ctrl-C or a CancelIo call.
*
*------------------------------------------------------------------------
*/
static DWORD
WriteConsoleChars(
HANDLE hConsole,
const WCHAR *lpBuffer,
Tcl_Size nChars,
Tcl_Size *nCharsWrittenPtr)
{
DWORD nCharsWritten;
/* See comments in ReadConsoleChars, not sure that applies here */
nCharsWritten = (DWORD)-1;
if (!WriteConsoleW(hConsole, lpBuffer, nChars, &nCharsWritten, NULL)) {
return GetLastError();
}
if (nCharsWritten == (DWORD) -1) {
nCharsWritten = 0;
}
*nCharsWrittenPtr = nCharsWritten;
return 0;
|
| ︙ | ︙ | |||
712 713 714 715 716 717 718 | } /* *------------------------------------------------------------------------ * * NudgeWatchers -- * | | | | | | | < | 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 |
}
/*
*------------------------------------------------------------------------
*
* NudgeWatchers --
*
* Wakes up all threads which have file event watchers on the passed
* console handle.
*
* The function locks and releases gConsoleLock.
* Caller must not be holding locks that will violate lock hierarchy.
*
* Results:
* None.
*
* Side effects:
* As above.
*------------------------------------------------------------------------
*/
static void
NudgeWatchers(
HANDLE consoleHandle)
{
ConsoleChannelInfo *chanInfoPtr;
|
| ︙ | ︙ | |||
754 755 756 757 758 759 760 | /* *---------------------------------------------------------------------- * * ConsoleSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting for an * event. It walks the channel list and if any input channel has data | | | | > | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 |
/*
*----------------------------------------------------------------------
*
* ConsoleSetupProc --
*
* This procedure is invoked before Tcl_DoOneEvent blocks waiting for an
* event. It walks the channel list and if any input channel has data
* available or output channel has space for data, sets the event loop
* blocking time to 0 so that it will poll immediately.
*
* Results:
* None.
*
* Side effects:
* Adjusts the block time if needed.
*
*----------------------------------------------------------------------
*/
void
ConsoleSetupProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
ConsoleChannelInfo *chanInfoPtr;
Tcl_Time blockTime = { 0, 0 };
int block = 1;
if (!(flags & TCL_FILE_EVENTS)) {
return;
}
/*
|
| ︙ | ︙ | |||
808 809 810 811 812 813 814 |
ReleaseSRWLockShared(&handleInfoPtr->lock);
}
}
ReleaseSRWLockShared(&gConsoleLock);
if (!block) {
/* At least one channel is readable/writable. Set block time to 0 */
| | | 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 |
ReleaseSRWLockShared(&handleInfoPtr->lock);
}
}
ReleaseSRWLockShared(&gConsoleLock);
if (!block) {
/* At least one channel is readable/writable. Set block time to 0 */
Tcl_SetMaxBlockTime(&blockTime);
}
}
/*
*----------------------------------------------------------------------
*
* ConsoleCheckProc --
|
| ︙ | ︙ | |||
911 912 913 914 915 916 917 |
evPtr->chanInfoPtr = chanInfoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
}
}
ReleaseSRWLockShared(&gConsoleLock);
}
| | | 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 |
evPtr->chanInfoPtr = chanInfoPtr;
Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
}
}
ReleaseSRWLockShared(&gConsoleLock);
}
/*
*----------------------------------------------------------------------
*
* ConsoleBlockModeProc --
*
* Set blocking or non-blocking mode on channel.
*
|
| ︙ | ︙ | |||
1185 1186 1187 1188 1189 1190 1191 |
/* NOTE lock released so DON'T break. Return instead */
if (lastError != ERROR_SUCCESS) {
Tcl_WinConvertError(lastError);
*errorCode = Tcl_GetErrno();
return -1;
} else if (numChars > 0) {
/* Successfully read something. */
| | | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 |
/* NOTE lock released so DON'T break. Return instead */
if (lastError != ERROR_SUCCESS) {
Tcl_WinConvertError(lastError);
*errorCode = Tcl_GetErrno();
return -1;
} else if (numChars > 0) {
/* Successfully read something. */
return numChars * sizeof(WCHAR);
} else {
/*
* Ctrl-C/Ctrl-Brk interrupt. Loop around to retry.
* We have to reacquire the lock. No worried about handleInfoPtr
* having gone away since the channel holds a reference.
*/
AcquireSRWLockExclusive(&handleInfoPtr->lock);
|
| ︙ | ︙ | |||
1223 1224 1225 1226 1227 1228 1229 |
if ((chanInfoPtr->flags & CONSOLE_ASYNC)
|| (chanInfoPtr->watchMask & TCL_READABLE)) {
handleInfoPtr->flags |= CONSOLE_DATA_AWAITED;
WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
}
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
| | | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 |
if ((chanInfoPtr->flags & CONSOLE_ASYNC)
|| (chanInfoPtr->watchMask & TCL_READABLE)) {
handleInfoPtr->flags |= CONSOLE_DATA_AWAITED;
WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
}
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
return numRead;
}
/*
*----------------------------------------------------------------------
*
* ConsoleOutputProc --
*
|
| ︙ | ︙ | |||
1337 1338 1339 1340 1341 1342 1343 |
/* Unlock before blocking in WriteConsole */
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
/* UNLOCKED so return, DON'T break out of loop as it will unlock
* again! */
winStatus = WriteConsoleChars(consoleHandle,
(WCHAR *)buf, toWrite / sizeof(WCHAR), &numWritten);
if (winStatus == ERROR_SUCCESS) {
| | | | 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 |
/* Unlock before blocking in WriteConsole */
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
/* UNLOCKED so return, DON'T break out of loop as it will unlock
* again! */
winStatus = WriteConsoleChars(consoleHandle,
(WCHAR *)buf, toWrite / sizeof(WCHAR), &numWritten);
if (winStatus == ERROR_SUCCESS) {
return numWritten * sizeof(WCHAR);
} else {
Tcl_WinConvertError(winStatus);
*errorCode = Tcl_GetErrno();
return -1;
}
}
/* Lock must have been reacquired before continuing loop */
}
WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
return numWritten;
}
/*
*----------------------------------------------------------------------
*
* ConsoleEventProc --
*
|
| ︙ | ︙ | |||
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 |
/*
* Since most of the work is handled by the background threads, we just
* need to update the watchMask and then force the notifier to poll once.
*/
chanInfoPtr->watchMask = newMask & chanInfoPtr->permissions;
if (chanInfoPtr->watchMask) {
if (!oldMask) {
AcquireSRWLockExclusive(&gConsoleLock);
/* Add to list of watched channels */
chanInfoPtr->nextWatchingChannelPtr = gWatchingChannelList;
gWatchingChannelList = chanInfoPtr;
| > | 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 |
/*
* Since most of the work is handled by the background threads, we just
* need to update the watchMask and then force the notifier to poll once.
*/
chanInfoPtr->watchMask = newMask & chanInfoPtr->permissions;
if (chanInfoPtr->watchMask) {
Tcl_Time blockTime = { 0, 0 };
if (!oldMask) {
AcquireSRWLockExclusive(&gConsoleLock);
/* Add to list of watched channels */
chanInfoPtr->nextWatchingChannelPtr = gWatchingChannelList;
gWatchingChannelList = chanInfoPtr;
|
| ︙ | ︙ | |||
1516 1517 1518 1519 1520 1521 1522 | AcquireSRWLockExclusive(&handleInfoPtr->lock); handleInfoPtr->flags |= CONSOLE_DATA_AWAITED; WakeConditionVariable(&handleInfoPtr->consoleThreadCV); ReleaseSRWLockExclusive(&handleInfoPtr->lock); } ReleaseSRWLockExclusive(&gConsoleLock); } | | | 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 |
AcquireSRWLockExclusive(&handleInfoPtr->lock);
handleInfoPtr->flags |= CONSOLE_DATA_AWAITED;
WakeConditionVariable(&handleInfoPtr->consoleThreadCV);
ReleaseSRWLockExclusive(&handleInfoPtr->lock);
}
ReleaseSRWLockExclusive(&gConsoleLock);
}
Tcl_SetMaxBlockTime(&blockTime);
} else if (oldMask) {
/* Remove from list of watched channels */
AcquireSRWLockExclusive(&gConsoleLock);
for (nextPtrPtr = &gWatchingChannelList, ptr = *nextPtrPtr;
ptr != NULL;
nextPtrPtr = &ptr->nextWatchingChannelPtr, ptr = *nextPtrPtr) {
|
| ︙ | ︙ | |||
1571 1572 1573 1574 1575 1576 1577 | } /* *------------------------------------------------------------------------ * * ConsoleDataAvailable -- * | | | | | 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 |
}
/*
*------------------------------------------------------------------------
*
* ConsoleDataAvailable --
*
* Checks if there is data in the console input queue.
*
* Results:
* Returns 1 if the input queue has data, -1 on error else 0 if empty.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static int
ConsoleDataAvailable(
HANDLE consoleHandle)
{
|
| ︙ | ︙ | |||
1872 1873 1874 1875 1876 1877 1878 |
*/
/* This thread is holding a reference so pointer is safe */
AcquireSRWLockExclusive(&handleInfoPtr->lock);
while (1) {
/* handleInfoPtr->lock must be held on entry to loop */
| | | 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 |
*/
/* This thread is holding a reference so pointer is safe */
AcquireSRWLockExclusive(&handleInfoPtr->lock);
while (1) {
/* handleInfoPtr->lock must be held on entry to loop */
int offset;
HANDLE consoleHandle;
/*
* Sadly, we need to do another copy because do not want to hold
* a lock on handleInfoPtr->buffer while calling WriteConsole as that
* might block. Also, we only want to copy an integral number of
* WCHAR's, i.e. even number of chars so do some length checks up
|
| ︙ | ︙ | |||
1984 1985 1986 1987 1988 1989 1990 | } /* *------------------------------------------------------------------------ * * AllocateConsoleHandleInfo -- * | | | | | | | | | | | | | 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 |
}
/*
*------------------------------------------------------------------------
*
* AllocateConsoleHandleInfo --
*
* Allocates a ConsoleHandleInfo for the passed console handle. As
* a side effect starts a console thread to handle i/o on the handle.
*
* Important: Caller must be holding an EXCLUSIVE lock on gConsoleLock
* when calling this function. The lock continues to be held on return.
*
* Results:
* Pointer to an unlocked ConsoleHandleInfo structure. The reference
* count on the structure is 1. This corresponds to the common reference
* from the console thread and the gConsoleHandleInfoList. Returns NULL
* on error.
*
* Side effects:
* A console reader or writer thread is started. The returned structure
* is placed on the active console handler list gConsoleHandleInfoList.
*
*------------------------------------------------------------------------
*/
static ConsoleHandleInfo *
AllocateConsoleHandleInfo(
HANDLE consoleHandle,
int permissions) /* TCL_READABLE or TCL_WRITABLE */
{
ConsoleHandleInfo *handleInfoPtr;
DWORD consoleMode;
handleInfoPtr = (ConsoleHandleInfo *)Tcl_Alloc(sizeof(*handleInfoPtr));
memset(handleInfoPtr, 0, sizeof(*handleInfoPtr));
handleInfoPtr->console = consoleHandle;
|
| ︙ | ︙ | |||
2028 2029 2030 2031 2032 2033 2034 |
GetConsoleMode(consoleHandle, &handleInfoPtr->initMode);
consoleMode = handleInfoPtr->initMode;
consoleMode &= ~(ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
consoleMode |= ENABLE_LINE_INPUT;
SetConsoleMode(consoleHandle, consoleMode);
}
handleInfoPtr->consoleThread = CreateThread(
| | | | | | | | | | | | | | | | 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 |
GetConsoleMode(consoleHandle, &handleInfoPtr->initMode);
consoleMode = handleInfoPtr->initMode;
consoleMode &= ~(ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT);
consoleMode |= ENABLE_LINE_INPUT;
SetConsoleMode(consoleHandle, consoleMode);
}
handleInfoPtr->consoleThread = CreateThread(
NULL, /* default security descriptor */
2*CONSOLE_BUFFER_SIZE, /* Stack size - gets rounded up to granularity */
permissions == TCL_READABLE ? ConsoleReaderThread : ConsoleWriterThread,
handleInfoPtr, /* Pass to thread */
0, /* Flags - no special cases */
NULL); /* Don't care about thread id */
if (handleInfoPtr->consoleThread == NULL) {
/* Note - SRWLock and condition variables do not need finalization */
RingBufferClear(&handleInfoPtr->buffer);
Tcl_Free(handleInfoPtr);
return NULL;
}
/* Chain onto global list */
handleInfoPtr->nextPtr = gConsoleHandleInfoList;
gConsoleHandleInfoList = handleInfoPtr;
return handleInfoPtr;
}
/*
*------------------------------------------------------------------------
*
* FindConsoleInfo --
*
* Finds the ConsoleHandleInfo record for a given ConsoleChannelInfo.
* The found record must match the console handle. It is the caller's
* responsibility to check the permissions (read/write) in the returned
* ConsoleHandleInfo match permissions in chanInfoPtr. This function does
* not check that.
*
* Important: Caller must be holding an shared or exclusive lock on
* gConsoleMutex. That ensures the returned pointer stays valid on
* return without risk of deallocation by other threads.
*
* Results:
* Pointer to the found ConsoleHandleInfo or NULL if not found
*
* Side effects:
* None.
*
*------------------------------------------------------------------------
*/
static ConsoleHandleInfo *
FindConsoleInfo(
const ConsoleChannelInfo *chanInfoPtr)
{
|
| ︙ | ︙ | |||
2270 2271 2272 2273 2274 2275 2276 |
ConsoleSetOptionProc(
void *instanceData, /* File state. */
Tcl_Interp *interp, /* For error reporting - can be NULL. */
const char *optionName, /* Which option to set? */
const char *value) /* New value for option. */
{
ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
| | | | 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 |
ConsoleSetOptionProc(
void *instanceData, /* File state. */
Tcl_Interp *interp, /* For error reporting - can be NULL. */
const char *optionName, /* Which option to set? */
const char *value) /* New value for option. */
{
ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
int len = strlen(optionName);
int vlen = strlen(value);
/*
* Option -inputmode normal|password|raw
*/
if ((chanInfoPtr->flags & CONSOLE_READ_OPS) && (len > 1) &&
(strncmp(optionName, "-inputmode", len) == 0)) {
|
| ︙ | ︙ | |||
2360 2361 2362 2363 2364 2365 2366 |
void *instanceData, /* File state. */
Tcl_Interp *interp, /* For error reporting - can be NULL. */
const char *optionName, /* Option to get. */
Tcl_DString *dsPtr) /* Where to store value(s). */
{
ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
int valid = 0; /* Flag if valid option parsed. */
| | | 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 |
void *instanceData, /* File state. */
Tcl_Interp *interp, /* For error reporting - can be NULL. */
const char *optionName, /* Option to get. */
Tcl_DString *dsPtr) /* Where to store value(s). */
{
ConsoleChannelInfo *chanInfoPtr = (ConsoleChannelInfo *)instanceData;
int valid = 0; /* Flag if valid option parsed. */
unsigned int len;
char buf[TCL_INTEGER_SPACE];
if (optionName == NULL) {
len = 0;
} else {
len = strlen(optionName);
}
|
| ︙ | ︙ |
Changes to win/tclWinDde.c.
1 2 3 4 5 6 | /* * tclWinDde.c -- * * This file provides functions that implement the "send" command, * allowing commands to be passed from interpreter to interpreter. * | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * tclWinDde.c -- * * This file provides functions that implement the "send" command, * allowing commands to be passed from interpreter to interpreter. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #ifndef USE_TCL_STUBS |
| ︙ | ︙ | |||
79 80 81 82 83 84 85 | */ static HSZ ddeServiceGlobal = 0; static DWORD ddeInstance; /* The application instance handle given to us * by DdeInitialize. */ static int ddeIsServer = 0; | | < | | | < > > > > > > > > > > > > > > > > > > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | */ static HSZ ddeServiceGlobal = 0; static DWORD ddeInstance; /* The application instance handle given to us * by DdeInitialize. */ static int ddeIsServer = 0; #define TCL_DDE_VERSION "1.4.6" #define TCL_DDE_PACKAGE_NAME "dde" #define TCL_DDE_SERVICE_NAME L"TclEval" #define TCL_DDE_EXECUTE_RESULT L"$TCLEVAL$EXECUTE$RESULT" #define DDE_FLAG_ASYNC 1 #define DDE_FLAG_BINARY 2 #define DDE_FLAG_FORCE 4 TCL_DECLARE_MUTEX(ddeMutex) #if TCL_MAJOR_VERSION < 9 # if TCL_UTF_MAX > 3 # define Tcl_WCharToUtfDString(a,b,c) Tcl_WinTCharToUtf((TCHAR *)(a),(b)*sizeof(WCHAR),c) # define Tcl_UtfToWCharDString(a,b,c) (WCHAR *)Tcl_WinUtfToTChar(a,b,c) # else # define Tcl_WCharToUtfDString(a,b,c) Tcl_UniCharToUtfDString((Tcl_UniChar *)(a),b,c) # define Tcl_UtfToWCharDString(a,b,c) (WCHAR *)Tcl_UtfToUniCharDString(a,b,c) # endif # ifndef Tcl_Size # define Tcl_Size int # endif # ifndef Tcl_ObjCmdProc2 # define Tcl_ObjCmdProc2 Tcl_ObjCmdProc # endif # ifndef Tcl_CreateObjCommand2 # define Tcl_CreateObjCommand2 Tcl_CreateObjCommand # endif #endif /* * Declarations for functions defined in this file. */ static LRESULT CALLBACK DdeClientWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); |
| ︙ | ︙ | |||
117 118 119 120 121 122 123 | static Tcl_Obj * ExecuteRemoteObject(RegisteredInterp *riPtr, Tcl_Obj *ddeObjectPtr); static int MakeDdeConnection(Tcl_Interp *interp, const WCHAR *name, HCONV *ddeConvPtr); static void SetDdeError(Tcl_Interp *interp); static int DdeObjCmd(void *clientData, Tcl_Interp *interp, Tcl_Size objc, | | > > > > > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
static Tcl_Obj * ExecuteRemoteObject(RegisteredInterp *riPtr,
Tcl_Obj *ddeObjectPtr);
static int MakeDdeConnection(Tcl_Interp *interp,
const WCHAR *name, HCONV *ddeConvPtr);
static void SetDdeError(Tcl_Interp *interp);
static int DdeObjCmd(void *clientData,
Tcl_Interp *interp, Tcl_Size objc,
Tcl_Obj *const objv[]);
#ifdef __cplusplus
extern "C" {
#endif
DLLEXPORT int Dde_Init(Tcl_Interp *interp);
DLLEXPORT int Dde_SafeInit(Tcl_Interp *interp);
#if TCL_MAJOR_VERSION < 9
/* With those additional entries, "load tcldde14.dll" works without 3th argument */
DLLEXPORT int Tcldde_Init(Tcl_Interp *interp);
DLLEXPORT int Tcldde_SafeInit(Tcl_Interp *interp);
#endif
#ifdef __cplusplus
}
#endif
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
return TCL_ERROR;
}
Tcl_CreateObjCommand2(interp, "dde", DdeObjCmd, NULL, NULL);
Tcl_CreateExitHandler(DdeExitProc, NULL);
return Tcl_PkgProvideEx(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION, NULL);
}
/*
*----------------------------------------------------------------------
*
* Dde_SafeInit --
*
* This function initializes the dde command within a safe interp
| > > > > > > > > | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
return TCL_ERROR;
}
Tcl_CreateObjCommand2(interp, "dde", DdeObjCmd, NULL, NULL);
Tcl_CreateExitHandler(DdeExitProc, NULL);
return Tcl_PkgProvideEx(interp, TCL_DDE_PACKAGE_NAME, TCL_DDE_VERSION, NULL);
}
#if TCL_MAJOR_VERSION < 9
int
Tcldde_Init(
Tcl_Interp *interp)
{
return Dde_Init(interp);
}
#endif
/*
*----------------------------------------------------------------------
*
* Dde_SafeInit --
*
* This function initializes the dde command within a safe interp
|
| ︙ | ︙ | |||
183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
{
int result = Dde_Init(interp);
if (result == TCL_OK) {
Tcl_HideCommand(interp, "dde", "dde");
}
return result;
}
/*
*----------------------------------------------------------------------
*
* Initialize --
*
* Initialize the global DDE instance.
| > > > > > > > > | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
{
int result = Dde_Init(interp);
if (result == TCL_OK) {
Tcl_HideCommand(interp, "dde", "dde");
}
return result;
}
#if TCL_MAJOR_VERSION < 9
int
Tcldde_SafeInit(
Tcl_Interp *interp)
{
return Dde_SafeInit(interp);
}
#endif
/*
*----------------------------------------------------------------------
*
* Initialize --
*
* Initialize the global DDE instance.
|
| ︙ | ︙ | |||
346 347 348 349 350 351 352 |
}
if (r == TCL_OK) {
r = Tcl_ListObjGetElements(interp, srvListPtr, &srvCount,
&srvPtrPtr);
}
if (r != TCL_OK) {
Tcl_DStringInit(&dString);
| | < | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
}
if (r == TCL_OK) {
r = Tcl_ListObjGetElements(interp, srvListPtr, &srvCount,
&srvPtrPtr);
}
if (r != TCL_OK) {
Tcl_DStringInit(&dString);
OutputDebugStringW(Tcl_UtfToWCharDString(Tcl_GetString(Tcl_GetObjResult(interp)), -1, &dString));
Tcl_DStringFree(&dString);
return NULL;
}
/*
* Pick a name to use for the application. Use "name" if it's not
* already in use. Otherwise add a suffix such as " #2", trying larger
|
| ︙ | ︙ | |||
380 381 382 383 384 385 386 |
}
/*
* See if the name is already in use, if so increment suffix.
*/
for (n = 0; n < srvCount; ++n) {
| | | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
}
/*
* See if the name is already in use, if so increment suffix.
*/
for (n = 0; n < srvCount; ++n) {
Tcl_Obj* namePtr;
Tcl_DString ds;
Tcl_ListObjIndex(interp, srvPtrPtr[n], 1, &namePtr);
Tcl_DStringInit(&ds);
Tcl_UtfToWCharDString(Tcl_GetString(namePtr), -1, &ds);
if (wcscmp(actualName, (WCHAR *)Tcl_DStringValue(&ds)) == 0) {
suffix++;
|
| ︙ | ︙ | |||
1531 1532 1533 1534 1535 1536 1537 |
Tcl_DStringInit(&dsBuf);
dataString =
Tcl_UtfToWCharDString(src, dataLength, &dsBuf);
dataLength = Tcl_DStringLength(&dsBuf) + sizeof(WCHAR);
}
if (dataLength + 1 < 2) {
| | | | 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 |
Tcl_DStringInit(&dsBuf);
dataString =
Tcl_UtfToWCharDString(src, dataLength, &dsBuf);
dataLength = Tcl_DStringLength(&dsBuf) + sizeof(WCHAR);
}
if (dataLength + 1 < 2) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("cannot execute null data", -1));
Tcl_DStringFree(&dsBuf);
Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", (char *)NULL);
result = TCL_ERROR;
break;
}
hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
DdeFreeStringHandle(ddeInstance, ddeService);
|
| ︙ | ︙ | |||
1582 1583 1584 1585 1586 1587 1588 |
src = Tcl_GetStringFromObj(objv[firstArg + 2], &length);
Tcl_DStringInit(&itemBuf);
itemString = Tcl_UtfToWCharDString(src, length, &itemBuf);
length = Tcl_DStringLength(&itemBuf) / sizeof(WCHAR);
if (length == 0) {
| | | | 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 |
src = Tcl_GetStringFromObj(objv[firstArg + 2], &length);
Tcl_DStringInit(&itemBuf);
itemString = Tcl_UtfToWCharDString(src, length, &itemBuf);
length = Tcl_DStringLength(&itemBuf) / sizeof(WCHAR);
if (length == 0) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("cannot request value of null data", -1));
Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", (char *)NULL);
result = TCL_ERROR;
goto cleanup;
}
hConv = DdeConnect(ddeInstance, ddeService, ddeTopic, NULL);
DdeFreeStringHandle(ddeInstance, ddeService);
DdeFreeStringHandle(ddeInstance, ddeTopic);
|
| ︙ | ︙ | |||
1621 1622 1623 1624 1625 1626 1627 |
if ((tmp >= sizeof(WCHAR))
&& !dataString[tmp / sizeof(WCHAR) - 1]) {
tmp -= (DWORD)sizeof(WCHAR);
}
Tcl_DStringInit(&dsBuf);
Tcl_WCharToUtfDString(dataString, tmp>>1, &dsBuf);
| | | | | 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 |
if ((tmp >= sizeof(WCHAR))
&& !dataString[tmp / sizeof(WCHAR) - 1]) {
tmp -= (DWORD)sizeof(WCHAR);
}
Tcl_DStringInit(&dsBuf);
Tcl_WCharToUtfDString(dataString, tmp>>1, &dsBuf);
returnObjPtr =
Tcl_NewStringObj(Tcl_DStringValue(&dsBuf),
Tcl_DStringLength(&dsBuf));
Tcl_DStringFree(&dsBuf);
}
DdeUnaccessData(ddeData);
DdeFreeDataHandle(ddeData);
Tcl_SetObjResult(interp, returnObjPtr);
}
} else {
|
| ︙ | ︙ | |||
1648 1649 1650 1651 1652 1653 1654 |
const char *src;
src = Tcl_GetStringFromObj(objv[firstArg + 2], &length);
Tcl_DStringInit(&itemBuf);
itemString = Tcl_UtfToWCharDString(src, length, &itemBuf);
length = Tcl_DStringLength(&itemBuf) / sizeof(WCHAR);
if (length == 0) {
| | | | 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 |
const char *src;
src = Tcl_GetStringFromObj(objv[firstArg + 2], &length);
Tcl_DStringInit(&itemBuf);
itemString = Tcl_UtfToWCharDString(src, length, &itemBuf);
length = Tcl_DStringLength(&itemBuf) / sizeof(WCHAR);
if (length == 0) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("cannot have a null item", -1));
Tcl_SetErrorCode(interp, "TCL", "DDE", "NULL", (char *)NULL);
result = TCL_ERROR;
goto cleanup;
}
Tcl_DStringInit(&dsBuf);
if (flags & DDE_FLAG_BINARY) {
dataString = (BYTE *)
|
| ︙ | ︙ | |||
1702 1703 1704 1705 1706 1707 1708 |
break;
case DDE_EVAL: {
RegisteredInterp *riPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (serviceName == NULL) {
| | | | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 |
break;
case DDE_EVAL: {
RegisteredInterp *riPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (serviceName == NULL) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("invalid service name \"\"", -1));
Tcl_SetErrorCode(interp, "TCL", "DDE", "NO_SERVER", (char *)NULL);
result = TCL_ERROR;
goto cleanup;
}
objc -= firstArg + 1;
objv += firstArg + 1;
|
| ︙ | ︙ | |||
1816 1817 1818 1819 1820 1821 1822 |
/*
* This is a non-local request. Send the script to the server and
* poll it for a result.
*/
if (MakeDdeConnection(interp, serviceName, &hConv) != TCL_OK) {
invalidServerResponse:
| | | | 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 |
/*
* This is a non-local request. Send the script to the server and
* poll it for a result.
*/
if (MakeDdeConnection(interp, serviceName, &hConv) != TCL_OK) {
invalidServerResponse:
Tcl_SetObjResult(interp,
Tcl_NewStringObj("invalid data returned from server", -1));
Tcl_SetErrorCode(interp, "TCL", "DDE", "BAD_RESPONSE", (char *)NULL);
result = TCL_ERROR;
goto cleanup;
}
objPtr = Tcl_ConcatObj(objc, objv);
string = Tcl_GetStringFromObj(objPtr, &length);
|
| ︙ | ︙ |
Changes to win/tclWinError.c.
| ︙ | ︙ | |||
173 174 175 176 177 178 179 |
EINVAL, /* 154 */
EINVAL, /* 155 */
EINVAL, /* 156 */
EINVAL, /* 157 */
EACCES, /* ERROR_NOT_LOCKED 158 */
EINVAL, /* 159 */
EINVAL, /* 160 */
| | | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
EINVAL, /* 154 */
EINVAL, /* 155 */
EINVAL, /* 156 */
EINVAL, /* 157 */
EACCES, /* ERROR_NOT_LOCKED 158 */
EINVAL, /* 159 */
EINVAL, /* 160 */
ENOENT, /* ERROR_BAD_PATHNAME 161 */
EINVAL, /* 162 */
EINVAL, /* 163 */
EINVAL, /* 164 */
EINVAL, /* 165 */
EINVAL, /* 166 */
EACCES, /* ERROR_LOCK_FAILED 167 */
EINVAL, /* 168 */
|
| ︙ | ︙ | |||
410 411 412 413 414 415 416 |
fprintf(stderr, "\xEF\xBB\xBF");
}
vfprintf(stderr, format, argList);
fprintf(stderr, "\n");
fflush(stderr);
}
}
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
fprintf(stderr, "\xEF\xBB\xBF");
}
vfprintf(stderr, format, argList);
fprintf(stderr, "\n");
fflush(stderr);
}
}
#endif
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
* End:
*/
|
Changes to win/tclWinFCmd.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * tclWinFCmd.c * * This file implements the Windows specific portion of file manipulation * subcommands of the "file" command. * * Copyright © 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * tclWinFCmd.c * * This file implements the Windows specific portion of file manipulation * subcommands of the "file" command. * * Copyright © 1996-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #if defined (__clang__) && (__clang_major__ > 20) #pragma clang diagnostic ignored "-Wc++-keyword" #endif /* * The following constants specify the type of callback when * TraverseWinTree() calls the traverseProc() |
| ︙ | ︙ | |||
38 39 40 41 42 43 44 | Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr); static int GetWinFileShortName(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr); static int SetWinFileAttributes(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr); static int CannotSetAttribute(Tcl_Interp *interp, int objIndex, Tcl_Obj *fileName, Tcl_Obj *attributePtr); | < | | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr);
static int GetWinFileShortName(Tcl_Interp *interp, int objIndex,
Tcl_Obj *fileName, Tcl_Obj **attributePtrPtr);
static int SetWinFileAttributes(Tcl_Interp *interp, int objIndex,
Tcl_Obj *fileName, Tcl_Obj *attributePtr);
static int CannotSetAttribute(Tcl_Interp *interp, int objIndex,
Tcl_Obj *fileName, Tcl_Obj *attributePtr);
/*
* Constants and variables necessary for file attributes subcommand.
*/
enum {
WIN_ARCHIVE_ATTRIBUTE,
WIN_HIDDEN_ATTRIBUTE,
WIN_LONGNAME_ATTRIBUTE,
WIN_READONLY_ATTRIBUTE,
WIN_SHORTNAME_ATTRIBUTE,
WIN_SYSTEM_ATTRIBUTE
};
|
| ︙ | ︙ | |||
136 137 138 139 140 141 142 | * the error. Some possible values for errno are: * * ENAMETOOLONG: src or dst names are too long. * EACCES: src or dst parent directory can't be read and/or written. * EEXIST: dst is a non-empty directory. * EINVAL: src is a root directory or dst is a subdirectory of src. * EISDIR: dst is a directory, but src is not. | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | * the error. Some possible values for errno are: * * ENAMETOOLONG: src or dst names are too long. * EACCES: src or dst parent directory can't be read and/or written. * EEXIST: dst is a non-empty directory. * EINVAL: src is a root directory or dst is a subdirectory of src. * EISDIR: dst is a directory, but src is not. * ENOENT: src doesn't exist. src or dst is "". * ENOTDIR: src is a directory, but dst is not. * EXDEV: src and dst are on different filesystems. * * EACCES: exists an open file already referring to src or dst. * EACCES: src or dst specify the current working directory (NT). * EACCES: src specifies a char device (nul:, com1:, etc.) * EEXIST: dst specifies a char device (nul:, com1:, etc.) (NT) |
| ︙ | ︙ | |||
170 171 172 173 174 175 176 177 |
static int
DoRenameFile(
const WCHAR *nativeSrc, /* Pathname of file or dir to be renamed
* (native). */
const WCHAR *nativeDst) /* New pathname for file or directory
* (native). */
{
DWORD srcAttr, dstAttr;
| > > > > | > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > | | > > > > > | > > > > > | < > > > > > > > > > > > > | > > > | > > > > > > > > | > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < < | | < < < < < < < < < < < < < < | < < > > > | < < > | < > | > | | < < < | | | < < < < < | < < < < < | | | < < > > | < > > > > > < < < < < < < < < < < | < < | > | | | | | | | < < | < < < < < < > > > | < < < | > > > | | | | | > > > | > > > | | < < < < < < < < < < | | | | > | < < | < < < < < < > | < | < < < < < < | | | < | > > | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
static int
DoRenameFile(
const WCHAR *nativeSrc, /* Pathname of file or dir to be renamed
* (native). */
const WCHAR *nativeDst) /* New pathname for file or directory
* (native). */
{
#if defined(HAVE_NO_SEH) && !defined(_WIN64)
TCLEXCEPTION_REGISTRATION registration;
#endif
DWORD srcAttr, dstAttr;
int retval = -1;
/*
* The MoveFile API acts differently under Win95/98 and NT WRT NULL and
* "". Avoid passing these values.
*/
if (nativeSrc == NULL || nativeSrc[0] == '\0' ||
nativeDst == NULL || nativeDst[0] == '\0') {
Tcl_SetErrno(ENOENT);
return TCL_ERROR;
}
/*
* The MoveFile API would throw an exception under NT if one of the
* arguments is a char block device.
*/
#if defined(HAVE_NO_SEH) && !defined(_WIN64)
/*
* Don't have SEH available, do things the hard way. Note that this needs
* to be one block of asm, to avoid stack imbalance; also, it is illegal
* for one asm block to contain a jump to another.
*/
__asm__ __volatile__ (
/*
* Pick up params before messing with the stack.
*/
"movl %[nativeDst], %%ebx" "\n\t"
"movl %[nativeSrc], %%ecx" "\n\t"
/*
* Construct an TCLEXCEPTION_REGISTRATION to protect the call to
* MoveFile.
*/
"leal %[registration], %%edx" "\n\t"
"movl %%fs:0, %%eax" "\n\t"
"movl %%eax, 0x0(%%edx)" "\n\t" /* link */
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
"movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
"movl $0, 0x10(%%edx)" "\n\t" /* status */
/*
* Link the TCLEXCEPTION_REGISTRATION on the chain.
*/
"movl %%edx, %%fs:0" "\n\t"
/*
* Call MoveFileW(nativeSrc, nativeDst)
*/
"pushl %%ebx" "\n\t"
"pushl %%ecx" "\n\t"
"movl %[moveFileW], %%eax" "\n\t"
"call *%%eax" "\n\t"
/*
* Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION and
* put the status return from MoveFile into it.
*/
"movl %%fs:0, %%edx" "\n\t"
"movl %%eax, 0x10(%%edx)" "\n\t"
"jmp 2f" "\n"
/*
* Come here on an exception. Recover the TCLEXCEPTION_REGISTRATION
*/
"1:" "\t"
"movl %%fs:0, %%edx" "\n\t"
"movl 0x8(%%edx), %%edx" "\n\t"
/*
* Come here however we exited. Restore context from the
* TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
*/
"2:" "\t"
"movl 0xC(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
:
/* No outputs */
:
[registration] "m" (registration),
[nativeDst] "m" (nativeDst),
[nativeSrc] "m" (nativeSrc),
[moveFileW] "r" (MoveFileW)
:
"%eax", "%ebx", "%ecx", "%edx", "memory"
);
if (registration.status != FALSE) {
retval = TCL_OK;
}
#else
#ifndef HAVE_NO_SEH
__try {
#endif
if (MoveFileW(nativeSrc, nativeDst) != FALSE) {
retval = TCL_OK;
}
#ifndef HAVE_NO_SEH
} __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif
#endif
if (retval != -1) {
return retval;
}
Tcl_WinConvertError(GetLastError());
srcAttr = GetFileAttributesW(nativeSrc);
dstAttr = GetFileAttributesW(nativeDst);
if (srcAttr == 0xFFFFFFFF) {
if (GetFullPathNameW(nativeSrc, 0, NULL,
NULL) >= MAX_PATH) {
errno = ENAMETOOLONG;
return TCL_ERROR;
}
srcAttr = 0;
}
if (dstAttr == 0xFFFFFFFF) {
if (GetFullPathNameW(nativeDst, 0, NULL,
NULL) >= MAX_PATH) {
errno = ENAMETOOLONG;
return TCL_ERROR;
}
dstAttr = 0;
}
if (errno == EBADF) {
errno = EACCES;
return TCL_ERROR;
}
if (errno == EACCES) {
decode:
if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
WCHAR *nativeSrcRest, *nativeDstRest;
const char **srcArgv, **dstArgv;
size_t size;
Tcl_Size srcArgc, dstArgc;
WCHAR nativeSrcPath[MAX_PATH];
WCHAR nativeDstPath[MAX_PATH];
Tcl_DString srcString, dstString;
const char *src, *dst;
size = GetFullPathNameW(nativeSrc, MAX_PATH,
nativeSrcPath, &nativeSrcRest);
if ((size == 0) || (size > MAX_PATH)) {
return TCL_ERROR;
}
size = GetFullPathNameW(nativeDst, MAX_PATH,
nativeDstPath, &nativeDstRest);
if ((size == 0) || (size > MAX_PATH)) {
return TCL_ERROR;
}
CharLowerW(nativeSrcPath);
CharLowerW(nativeDstPath);
Tcl_DStringInit(&srcString);
Tcl_DStringInit(&dstString);
src = Tcl_WCharToUtfDString(nativeSrcPath, TCL_INDEX_NONE, &srcString);
dst = Tcl_WCharToUtfDString(nativeDstPath, TCL_INDEX_NONE, &dstString);
/*
* Check whether the destination path is actually inside the
* source path. This is true if the prefix matches, and the next
* character is either end-of-string or a directory separator
*/
if ((strncmp(src, dst, Tcl_DStringLength(&srcString))==0)
&& (dst[Tcl_DStringLength(&srcString)] == '\\'
|| dst[Tcl_DStringLength(&srcString)] == '/'
|| dst[Tcl_DStringLength(&srcString)] == '\0')) {
/*
* Trying to move a directory into itself.
*/
errno = EINVAL;
Tcl_DStringFree(&srcString);
Tcl_DStringFree(&dstString);
return TCL_ERROR;
}
Tcl_SplitPath(src, &srcArgc, &srcArgv);
Tcl_SplitPath(dst, &dstArgc, &dstArgv);
Tcl_DStringFree(&srcString);
Tcl_DStringFree(&dstString);
if (srcArgc == 1) {
/*
* They are trying to move a root directory. Whether or not it
* is across filesystems, this cannot be done.
*/
Tcl_SetErrno(EINVAL);
} else if ((srcArgc > 0) && (dstArgc > 0) &&
(strcmp(srcArgv[0], dstArgv[0]) != 0)) {
/*
* If src is a directory and dst filesystem != src filesystem,
* errno should be EXDEV. It is very important to get this
* behavior, so that the caller can respond to a cross
* filesystem rename by simulating it with copy and delete.
* The MoveFile system call already handles the case of moving
* a file between filesystems.
*/
Tcl_SetErrno(EXDEV);
}
Tcl_Free((void *)srcArgv);
Tcl_Free((void *)dstArgv);
}
/*
* Other types of access failure is that dst is a read-only
* filesystem, that an open file referred to src or dest, or that src
* or dest specified the current working directory on the current
* filesystem. EACCES is returned for those cases.
*/
} else if (Tcl_GetErrno() == EEXIST) {
/*
* Reports EEXIST any time the target already exists. If it makes
* sense, remove the old file and try renaming again.
*/
if (srcAttr & FILE_ATTRIBUTE_DIRECTORY) {
if (dstAttr & FILE_ATTRIBUTE_DIRECTORY) {
/*
* Overwrite empty dst directory with src directory. The
* following call will remove an empty directory. If it fails,
* it's because it wasn't empty.
*/
if (DoRemoveJustDirectory(nativeDst, 0, NULL) == TCL_OK) {
/*
* Now that that empty directory is gone, we can try
* renaming again. If that fails, we'll put this empty
* directory back, for completeness.
*/
if (MoveFileW(nativeSrc, nativeDst) != FALSE) {
return TCL_OK;
}
/*
* Some new error has occurred. Don't know what it could
* be, but report this one.
*/
Tcl_WinConvertError(GetLastError());
CreateDirectoryW(nativeDst, NULL);
SetFileAttributesW(nativeDst, dstAttr);
if (Tcl_GetErrno() == EACCES) {
/*
* Decode the EACCES to a more meaningful error.
*/
goto decode;
}
}
} else { /* (dstAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 */
Tcl_SetErrno(ENOTDIR);
}
} else { /* (srcAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 */
if (dstAttr & FILE_ATTRIBUTE_DIRECTORY) {
Tcl_SetErrno(EISDIR);
} else {
/*
* Overwrite existing file by:
*
* 1. Rename existing file to temp name.
* 2. Rename old file to new name.
* 3. If success, delete temp file. If failure, put temp file
* back to old name.
*/
WCHAR *nativeRest, *nativeTmp, *nativePrefix;
int result, size;
WCHAR tempBuf[MAX_PATH];
size = GetFullPathNameW(nativeDst, MAX_PATH,
tempBuf, &nativeRest);
if ((size == 0) || (size > MAX_PATH) || (nativeRest == NULL)) {
return TCL_ERROR;
}
nativeTmp = (WCHAR *) tempBuf;
nativeRest[0] = '\0';
result = TCL_ERROR;
nativePrefix = (WCHAR *)L"tclr";
if (GetTempFileNameW(nativeTmp, nativePrefix,
0, tempBuf) != 0) {
/*
* Strictly speaking, need the following DeleteFile and
* MoveFile to be joined as an atomic operation so no
* other app comes along in the meantime and creates the
* same temp file.
*/
nativeTmp = tempBuf;
DeleteFileW(nativeTmp);
if (MoveFileW(nativeDst, nativeTmp) != FALSE) {
if (MoveFileW(nativeSrc, nativeDst) != FALSE) {
SetFileAttributesW(nativeTmp, FILE_ATTRIBUTE_NORMAL);
DeleteFileW(nativeTmp);
return TCL_OK;
} else {
DeleteFileW(nativeDst);
MoveFileW(nativeTmp, nativeDst);
}
}
/*
* Can't backup dst file or move src file. Return that
* error. Could happen if an open file refers to dst.
*/
Tcl_WinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
/*
* Decode the EACCES to a more meaningful error.
*/
goto decode;
}
}
return result;
}
}
}
return TCL_ERROR;
}
/*
*---------------------------------------------------------------------------
*
* TclpObjCopyFile, DoCopyFile --
*
* Copy a single file (not a directory). If dst already exists and is not
* a directory, it is removed.
*
* Results:
* If the file was successfully copied, returns TCL_OK. Otherwise the
* return value is TCL_ERROR and errno is set to indicate the error.
* Some possible values for errno are:
*
* EACCES: src or dst parent directory can't be read and/or written.
* EISDIR: src or dst is a directory.
* ENOENT: src doesn't exist. src or dst is "".
*
* EACCES: exists an open file already referring to dst (95).
* EACCES: src specifies a char device (nul:, com1:, etc.) (NT)
* ENOENT: src specifies a char device (nul:, com1:, etc.) (95)
*
* Side effects:
* It is not an error to copy to a char device.
|
| ︙ | ︙ | |||
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
}
static int
DoCopyFile(
const WCHAR *nativeSrc, /* Pathname of file to be copied (native). */
const WCHAR *nativeDst) /* Pathname of file to copy to (native). */
{
int retval = -1;
/*
* The CopyFile API acts differently under Win95/98 and NT WRT NULL and
* "". Avoid passing these values.
*/
if (nativeSrc == NULL || nativeSrc[0] == '\0' ||
nativeDst == NULL || nativeDst[0] == '\0') {
Tcl_SetErrno(ENOENT);
return TCL_ERROR;
}
/*
* The CopyFile API would throw an exception under NT if one of the
* arguments is a char block device.
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
}
static int
DoCopyFile(
const WCHAR *nativeSrc, /* Pathname of file to be copied (native). */
const WCHAR *nativeDst) /* Pathname of file to copy to (native). */
{
#if defined(HAVE_NO_SEH) && !defined(_WIN64)
TCLEXCEPTION_REGISTRATION registration;
#endif
int retval = -1;
/*
* The CopyFile API acts differently under Win95/98 and NT WRT NULL and
* "". Avoid passing these values.
*/
if (nativeSrc == NULL || nativeSrc[0] == '\0' ||
nativeDst == NULL || nativeDst[0] == '\0') {
Tcl_SetErrno(ENOENT);
return TCL_ERROR;
}
/*
* The CopyFile API would throw an exception under NT if one of the
* arguments is a char block device.
*/
#if defined(HAVE_NO_SEH) && !defined(_WIN64)
/*
* Don't have SEH available, do things the hard way. Note that this needs
* to be one block of asm, to avoid stack imbalance; also, it is illegal
* for one asm block to contain a jump to another.
*/
__asm__ __volatile__ (
/*
* Pick up parameters before messing with the stack
*/
"movl %[nativeDst], %%ebx" "\n\t"
"movl %[nativeSrc], %%ecx" "\n\t"
/*
* Construct an TCLEXCEPTION_REGISTRATION to protect the call to
* CopyFile.
*/
"leal %[registration], %%edx" "\n\t"
"movl %%fs:0, %%eax" "\n\t"
"movl %%eax, 0x0(%%edx)" "\n\t" /* link */
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
"movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
"movl $0, 0x10(%%edx)" "\n\t" /* status */
/*
* Link the TCLEXCEPTION_REGISTRATION on the chain.
*/
"movl %%edx, %%fs:0" "\n\t"
/*
* Call CopyFileW(nativeSrc, nativeDst, 0)
*/
"movl %[copyFileW], %%eax" "\n\t"
"pushl $0" "\n\t"
"pushl %%ebx" "\n\t"
"pushl %%ecx" "\n\t"
"call *%%eax" "\n\t"
/*
* Come here on normal exit. Recover the TCLEXCEPTION_REGISTRATION and
* put the status return from CopyFile into it.
*/
"movl %%fs:0, %%edx" "\n\t"
"movl %%eax, 0x10(%%edx)" "\n\t"
"jmp 2f" "\n"
/*
* Come here on an exception. Recover the TCLEXCEPTION_REGISTRATION
*/
"1:" "\t"
"movl %%fs:0, %%edx" "\n\t"
"movl 0x8(%%edx), %%edx" "\n\t"
/*
* Come here however we exited. Restore context from the
* TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
*/
"2:" "\t"
"movl 0xC(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
:
/* No outputs */
:
[registration] "m" (registration),
[nativeDst] "m" (nativeDst),
[nativeSrc] "m" (nativeSrc),
[copyFileW] "r" (CopyFileW)
:
"%eax", "%ebx", "%ecx", "%edx", "memory"
);
if (registration.status != FALSE) {
retval = TCL_OK;
}
#else
#ifndef HAVE_NO_SEH
__try {
#endif
if (CopyFileW(nativeSrc, nativeDst, 0) != FALSE) {
retval = TCL_OK;
}
#ifndef HAVE_NO_SEH
} __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif
#endif
if (retval != -1) {
return retval;
}
Tcl_WinConvertError(GetLastError());
if (Tcl_GetErrno() == EBADF) {
|
| ︙ | ︙ | |||
548 549 550 551 552 553 554 |
if (DeleteFileW(path) != FALSE) {
return TCL_OK;
}
Tcl_WinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
attr = GetFileAttributesW(path);
| | < < < | | | | | | < < < < < < < < | | | 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 |
if (DeleteFileW(path) != FALSE) {
return TCL_OK;
}
Tcl_WinConvertError(GetLastError());
if (Tcl_GetErrno() == EACCES) {
attr = GetFileAttributesW(path);
if (attr != 0xFFFFFFFF) {
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
/*
* It is a symbolic link - remove it.
*/
if (TclWinSymLinkDelete(path, 0) == 0) {
return TCL_OK;
}
}
/*
* If we fall through here, it is a directory.
*
* Windows NT reports removing a directory as EACCES instead
* of EISDIR.
*/
Tcl_SetErrno(EISDIR);
} else if (attr & FILE_ATTRIBUTE_READONLY) {
int res = SetFileAttributesW(path,
attr & ~((DWORD) FILE_ATTRIBUTE_READONLY));
if ((res != 0) && (DeleteFileW(path) != FALSE)) {
return TCL_OK;
}
Tcl_WinConvertError(GetLastError());
if (res != 0) {
SetFileAttributesW(path, attr);
}
}
}
} else if (Tcl_GetErrno() == ENOENT) {
attr = GetFileAttributesW(path);
if (attr != 0xFFFFFFFF) {
|
| ︙ | ︙ | |||
699 700 701 702 703 704 705 |
Tcl_Obj *normSrcPtr, *normDestPtr;
int ret;
normSrcPtr = Tcl_FSGetNormalizedPath(NULL,srcPathPtr);
if (normSrcPtr == NULL) {
return TCL_ERROR;
}
| | < < | < < | < < | 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 |
Tcl_Obj *normSrcPtr, *normDestPtr;
int ret;
normSrcPtr = Tcl_FSGetNormalizedPath(NULL,srcPathPtr);
if (normSrcPtr == NULL) {
return TCL_ERROR;
}
if (normSrcPtr != srcPathPtr) { Tcl_IncrRefCount(normSrcPtr); }
normDestPtr = Tcl_FSGetNormalizedPath(NULL,destPathPtr);
if (normDestPtr == NULL) {
if (normSrcPtr != srcPathPtr) { Tcl_DecrRefCount(normSrcPtr); }
return TCL_ERROR;
}
if (normDestPtr != destPathPtr) { Tcl_IncrRefCount(normDestPtr); }
Tcl_DStringInit(&srcString);
Tcl_DStringInit(&dstString);
Tcl_UtfToWCharDString(TclGetString(normSrcPtr), TCL_INDEX_NONE, &srcString);
Tcl_UtfToWCharDString(TclGetString(normDestPtr), TCL_INDEX_NONE, &dstString);
ret = TraverseWinTree(TraversalCopy, &srcString, &dstString, &ds);
|
| ︙ | ︙ | |||
735 736 737 738 739 740 741 |
} else {
*errorPtr = Tcl_DStringToObj(&ds);
}
Tcl_DStringFree(&ds);
Tcl_IncrRefCount(*errorPtr);
}
| | < < | < < | 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 |
} else {
*errorPtr = Tcl_DStringToObj(&ds);
}
Tcl_DStringFree(&ds);
Tcl_IncrRefCount(*errorPtr);
}
if (normSrcPtr != srcPathPtr) { Tcl_DecrRefCount(normSrcPtr); }
if (normDestPtr != destPathPtr) { Tcl_DecrRefCount(normDestPtr); }
return ret;
}
/*
*----------------------------------------------------------------------
*
* TclpObjRemoveDirectory, DoRemoveDirectory --
|
| ︙ | ︙ | |||
795 796 797 798 799 800 801 |
*/
Tcl_DString native;
normPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
if (normPtr == NULL) {
return TCL_ERROR;
}
| | < < | < < | 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 |
*/
Tcl_DString native;
normPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
if (normPtr == NULL) {
return TCL_ERROR;
}
if (normPtr != pathPtr) { Tcl_IncrRefCount(normPtr); }
Tcl_DStringInit(&native);
Tcl_UtfToWCharDString(TclGetString(normPtr), TCL_INDEX_NONE, &native);
ret = DoRemoveDirectory(&native, recursive, &ds);
Tcl_DStringFree(&native);
} else {
ret = DoRemoveJustDirectory((const WCHAR *)Tcl_FSGetNativePath(pathPtr), 0, &ds);
}
if (ret != TCL_OK) {
if (Tcl_DStringLength(&ds) > 0) {
if (normPtr != NULL &&
!strcmp(Tcl_DStringValue(&ds), TclGetString(normPtr))) {
*errorPtr = pathPtr;
} else {
*errorPtr = Tcl_DStringToObj(&ds);
}
Tcl_IncrRefCount(*errorPtr);
}
Tcl_DStringFree(&ds);
}
if (normPtr && normPtr != pathPtr) { Tcl_DecrRefCount(normPtr); }
return ret;
}
static int
DoRemoveJustDirectory(
const WCHAR *nativePath, /* Pathname of directory to be removed
|
| ︙ | ︙ | |||
1425 1426 1427 1428 1429 1430 1431 |
errno = ENOENT;
Tcl_PosixError(interp);
}
goto cleanup;
}
/*
| | | 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 |
errno = ENOENT;
Tcl_PosixError(interp);
}
goto cleanup;
}
/*
* We will decrement this again at the end. It is safer to do this in
* case any of the calls below retain a reference to splitPath.
*/
Tcl_IncrRefCount(splitPath);
for (i = 0; i < pathc; i++) {
Tcl_Obj *elt;
|
| ︙ | ︙ | |||
1849 1850 1851 1852 1853 1854 1855 |
*/
baseLen = Tcl_DStringLength(&base);
do {
char tempbuf[SUFFIX_LENGTH + 1];
int i;
static const char randChars[] =
| | | 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 |
*/
baseLen = Tcl_DStringLength(&base);
do {
char tempbuf[SUFFIX_LENGTH + 1];
int i;
static const char randChars[] =
"QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
static const int numRandChars = sizeof(randChars) - 1;
/*
* Put a random suffix on the end.
*/
error = ERROR_SUCCESS;
|
| ︙ | ︙ | |||
1887 1888 1889 1890 1891 1892 1893 |
*/
Tcl_DStringInit(&name);
Tcl_WCharToUtfDString((LPCWSTR) Tcl_DStringValue(&base), TCL_INDEX_NONE, &name);
Tcl_DStringFree(&base);
return Tcl_DStringToObj(&name);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 |
*/
Tcl_DStringInit(&name);
Tcl_WCharToUtfDString((LPCWSTR) Tcl_DStringValue(&base), TCL_INDEX_NONE, &name);
Tcl_DStringFree(&base);
return Tcl_DStringToObj(&name);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to win/tclWinFile.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /* * tclWinFile.c -- * * This file contains temporary wrappers around UNIX file handling * functions. These wrappers map the UNIX functions to Win32 HANDLE-style * files, which can be manipulated through the Win32 console redirection * interfaces. * * Copyright © 1995-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #include "tclFileSystem.h" #include <winioctl.h> #include <shlobj.h> | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /* * tclWinFile.c -- * * This file contains temporary wrappers around UNIX file handling * functions. These wrappers map the UNIX functions to Win32 HANDLE-style * files, which can be manipulated through the Win32 console redirection * interfaces. * * Copyright © 1995-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" #include "tclFileSystem.h" #include <winioctl.h> #include <shlobj.h> #include <lm.h> /* For TclpGetUserHome(). */ #include <userenv.h> /* For TclpGetUserHome(). */ #include <aclapi.h> /* For GetNamedSecurityInfo */ #if defined (__clang__) && (__clang_major__ > 20) #pragma clang diagnostic ignored "-Wc++-keyword" #endif #ifdef _MSC_VER # pragma comment(lib, "userenv.lib") #endif /* |
| ︙ | ︙ | |||
89 90 91 92 93 94 95 |
# define FSCTL_DELETE_REPARSE_POINT \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#endif
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
| > > > > | | < | | < | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# define FSCTL_DELETE_REPARSE_POINT \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#endif
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
/*
* Maximum reparse buffer info size. The max user defined reparse data is
* 16KB, plus there's a header.
*/
#define MAX_REPARSE_SIZE 17000
/*
* Undocumented REPARSE_MOUNTPOINT_HEADER_SIZE structure definition. This is
* found in winnt.h.
*
* IMPORTANT: caution when using this structure, since the actual structures
* used will want to store a full path in the 'PathBuffer' field, but there
* isn't room (there's only a single WCHAR!). Therefore one must artificially
* create a larger space of memory and then cast it to this type. We use the
* 'DUMMY_REPARSE_BUFFER' struct just below to deal with this problem.
*/
#define REPARSE_MOUNTPOINT_HEADER_SIZE 8
#ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
typedef struct _REPARSE_DATA_BUFFER {
DWORD ReparseTag;
WORD ReparseDataLength;
|
| ︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
struct {
BYTE DataBuffer[1];
} GenericReparseBuffer;
};
} REPARSE_DATA_BUFFER;
#endif
/*
* Other typedefs required by this code.
*/
static __time64_t ToCTime(FILETIME fileTime);
static void FromCTime(__time64_t posixTime, FILETIME *fileTime);
/*
* Declarations for local functions defined in this file:
*/
static int NativeAccess(const WCHAR *path, int mode);
static int NativeDev(const WCHAR *path);
static int NativeStat(const WCHAR *path, Tcl_StatBuf *statPtr,
int checkLinks);
static unsigned short NativeStatMode(DWORD attr, int checkLinks,
int isExec);
static int NativeIsExec(const WCHAR *path);
static int NativeReadReparse(const WCHAR *LinkDirectory,
| > > > > > | < < < < < < | | < < | < | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
struct {
BYTE DataBuffer[1];
} GenericReparseBuffer;
};
} REPARSE_DATA_BUFFER;
#endif
typedef struct {
REPARSE_DATA_BUFFER dummy;
WCHAR dummyBuf[MAX_PATH * 3];
} DUMMY_REPARSE_BUFFER;
/*
* Other typedefs required by this code.
*/
static __time64_t ToCTime(FILETIME fileTime);
static void FromCTime(__time64_t posixTime, FILETIME *fileTime);
/*
* Declarations for local functions defined in this file:
*/
static int NativeAccess(const WCHAR *path, int mode);
static int NativeDev(const WCHAR *path);
static int NativeStat(const WCHAR *path, Tcl_StatBuf *statPtr,
int checkLinks);
static unsigned short NativeStatMode(DWORD attr, int checkLinks,
int isExec);
static int NativeIsExec(const WCHAR *path);
static int NativeReadReparse(const WCHAR *LinkDirectory,
REPARSE_DATA_BUFFER *buffer, DWORD desiredAccess);
static int NativeWriteReparse(const WCHAR *LinkDirectory,
REPARSE_DATA_BUFFER *buffer);
static int NativeMatchType(int isDrive, DWORD attr,
const WCHAR *nativeName, Tcl_GlobTypeData *types);
static int WinIsDrive(const char *name, size_t nameLen);
static size_t WinIsReserved(const char *path);
static Tcl_Obj * WinReadLink(const WCHAR *LinkSource);
static Tcl_Obj * WinReadLinkDirectory(const WCHAR *LinkDirectory);
static int WinLink(const WCHAR *LinkSource,
const WCHAR *LinkTarget, int linkAction);
static int WinSymLinkDirectory(const WCHAR *LinkDirectory,
const WCHAR *LinkTarget);
MODULE_SCOPE void tclWinDebugPanic(const char *format, ...);
/*
* Check if a Windows error code is one that might be returned for
* non-existent files
*/
static inline int
IsNoSuchFileError(DWORD winError)
{
return (winError == ERROR_FILE_NOT_FOUND ||
winError == ERROR_PATH_NOT_FOUND ||
winError == ERROR_INVALID_NAME);
}
/*
|
| ︙ | ︙ | |||
205 206 207 208 209 210 211 |
static int
WinLink(
const WCHAR *linkSourcePath,
const WCHAR *linkTargetPath,
int linkAction)
{
| | | > > > | | | < > | > > < > | > | < > | > | | | < > | > > | > > > < > > > > > | > > > > > > > > > > > > > | > > | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
static int
WinLink(
const WCHAR *linkSourcePath,
const WCHAR *linkTargetPath,
int linkAction)
{
WCHAR tempFileName[MAX_PATH];
WCHAR *tempFilePart;
DWORD attr;
/*
* Get the full path referenced by the target.
*/
if (!GetFullPathNameW(linkTargetPath, MAX_PATH, tempFileName,
&tempFilePart)) {
/*
* Invalid file.
*/
Tcl_WinConvertError(GetLastError());
return -1;
}
/*
* Make sure source file doesn't exist.
*/
attr = GetFileAttributesW(linkSourcePath);
if (attr != INVALID_FILE_ATTRIBUTES) {
Tcl_SetErrno(EEXIST);
return -1;
}
/*
* Get the full path referenced by the source file/directory.
*/
if (!GetFullPathNameW(linkSourcePath, MAX_PATH, tempFileName,
&tempFilePart)) {
/*
* Invalid file.
*/
Tcl_WinConvertError(GetLastError());
return -1;
}
/*
* Check the target.
*/
attr = GetFileAttributesW(linkTargetPath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The target doesn't exist.
*/
Tcl_WinConvertError(GetLastError());
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
/*
* It is a file.
*/
if (linkAction & TCL_CREATE_HARD_LINK) {
if (CreateHardLinkW(linkSourcePath, linkTargetPath, NULL)) {
/*
* Success!
*/
return 0;
}
Tcl_WinConvertError(GetLastError());
} else if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
if (CreateSymbolicLinkW(linkSourcePath, linkTargetPath,
0x2 /* SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE */)) {
/*
* Success!
*/
return 0;
} else {
Tcl_WinConvertError(GetLastError());
}
} else {
Tcl_SetErrno(ENODEV);
}
} else {
/*
* We've got a directory. Now check whether what we're trying to do is
* reasonable.
*/
if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
return WinSymLinkDirectory(linkSourcePath, linkTargetPath);
} else if (linkAction & TCL_CREATE_HARD_LINK) {
/*
* Can't hard link directories.
*/
Tcl_SetErrno(EISDIR);
} else {
Tcl_SetErrno(ENODEV);
}
}
return -1;
}
|
| ︙ | ︙ | |||
292 293 294 295 296 297 298 |
*--------------------------------------------------------------------
*/
static Tcl_Obj *
WinReadLink(
const WCHAR *linkSourcePath)
{
| | | > | > | | | < > | > > < > | > | > | > > > > | > > | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
*--------------------------------------------------------------------
*/
static Tcl_Obj *
WinReadLink(
const WCHAR *linkSourcePath)
{
WCHAR tempFileName[MAX_PATH];
WCHAR *tempFilePart;
DWORD attr;
/*
* Get the full path referenced by the target.
*/
if (!GetFullPathNameW(linkSourcePath, MAX_PATH, tempFileName,
&tempFilePart)) {
/*
* Invalid file.
*/
Tcl_WinConvertError(GetLastError());
return NULL;
}
/*
* Make sure source file does exist.
*/
attr = GetFileAttributesW(linkSourcePath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The source doesn't exist.
*/
Tcl_WinConvertError(GetLastError());
return NULL;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
/*
* It is a file - this is not yet supported.
*/
Tcl_SetErrno(ENOTDIR);
return NULL;
}
return WinReadLinkDirectory(linkSourcePath);
}
|
| ︙ | ︙ | |||
340 341 342 343 344 345 346 | * * Returns: * Zero on success. * *-------------------------------------------------------------------- */ | < < < < > | | | < > < | < < < < < < < < < < | | | < < < < | < < < < < < < < | | | | < < < < < < | | < | > | > | > > > | > > | > > > > > > | > | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
*
* Returns:
* Zero on success.
*
*--------------------------------------------------------------------
*/
static int
WinSymLinkDirectory(
const WCHAR *linkDirPath,
const WCHAR *linkTargetPath)
{
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
int len;
WCHAR nativeTarget[MAX_PATH];
WCHAR *loop;
/*
* Make the native target name.
*/
memcpy(nativeTarget, L"\\??\\", 4 * sizeof(WCHAR));
memcpy(nativeTarget + 4, linkTargetPath,
sizeof(WCHAR) * (1+wcslen((WCHAR *) linkTargetPath)));
len = wcslen(nativeTarget);
/*
* We must have backslashes only. This is VERY IMPORTANT. If we have any
* forward slashes everything appears to work, but the resulting symlink
* is useless!
*/
for (loop = nativeTarget; *loop != 0; loop++) {
if (*loop == '/') {
*loop = '\\';
}
}
if ((nativeTarget[len-1] == '\\') && (nativeTarget[len-2] != ':')) {
nativeTarget[len-1] = 0;
}
/*
* Build the reparse info.
*/
memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER));
reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
reparseBuffer->MountPointReparseBuffer.SubstituteNameLength =
wcslen(nativeTarget) * sizeof(WCHAR);
reparseBuffer->Reserved = 0;
reparseBuffer->MountPointReparseBuffer.PrintNameLength = 0;
reparseBuffer->MountPointReparseBuffer.PrintNameOffset =
reparseBuffer->MountPointReparseBuffer.SubstituteNameLength
+ sizeof(WCHAR);
memcpy(reparseBuffer->MountPointReparseBuffer.PathBuffer, nativeTarget,
sizeof(WCHAR)
+ reparseBuffer->MountPointReparseBuffer.SubstituteNameLength);
reparseBuffer->ReparseDataLength =
reparseBuffer->MountPointReparseBuffer.SubstituteNameLength+12;
return NativeWriteReparse(linkDirPath, reparseBuffer);
}
/*
*--------------------------------------------------------------------
*
* TclWinSymLinkCopyDirectory --
*
|
| ︙ | ︙ | |||
436 437 438 439 440 441 442 |
*/
int
TclWinSymLinkCopyDirectory(
const WCHAR *linkOrigPath, /* Existing junction - reparse point */
const WCHAR *linkCopyPath) /* Will become a duplicate junction */
{
| | < < < < < | < | < < > | < | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
*/
int
TclWinSymLinkCopyDirectory(
const WCHAR *linkOrigPath, /* Existing junction - reparse point */
const WCHAR *linkCopyPath) /* Will become a duplicate junction */
{
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
if (NativeReadReparse(linkOrigPath, reparseBuffer, GENERIC_READ)) {
return -1;
}
return NativeWriteReparse(linkCopyPath, reparseBuffer);
}
/*
*--------------------------------------------------------------------
*
* TclWinSymLinkDelete --
*
|
| ︙ | ︙ | |||
479 480 481 482 483 484 485 |
const WCHAR *linkOrigPath,
int linkOnly)
{
/*
* It is a symbolic link - remove it.
*/
| | | | | | | < | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
const WCHAR *linkOrigPath,
int linkOnly)
{
/*
* It is a symbolic link - remove it.
*/
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
HANDLE hFile;
DWORD returnedLength;
memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER));
reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
hFile = CreateFileW(linkOrigPath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
if (!DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, reparseBuffer,
REPARSE_MOUNTPOINT_HEADER_SIZE,NULL,0,&returnedLength,NULL)) {
/*
* Error setting junction.
*/
Tcl_WinConvertError(GetLastError());
CloseHandle(hFile);
} else {
|
| ︙ | ︙ | |||
540 541 542 543 544 545 546 |
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
static Tcl_Obj *
WinReadLinkDirectory(
const WCHAR *linkDirPath)
{
| | | | < < < < < < < < | < < | > | | | > | < > | > | | > > | | | | < < < < < < | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
static Tcl_Obj *
WinReadLinkDirectory(
const WCHAR *linkDirPath)
{
int attr, len, offset;
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
Tcl_Obj *retVal;
Tcl_DString ds;
const char *copy;
attr = GetFileAttributesW(linkDirPath);
if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {
goto invalidError;
}
if (NativeReadReparse(linkDirPath, reparseBuffer, 0)) {
return NULL;
}
switch (reparseBuffer->ReparseTag) {
case 0x80000000|IO_REPARSE_TAG_SYMBOLIC_LINK:
case IO_REPARSE_TAG_SYMBOLIC_LINK:
case IO_REPARSE_TAG_MOUNT_POINT:
/*
* Certain native path representations on Windows have a special
* prefix to indicate that they are to be treated specially. For
* example extremely long paths, or symlinks, or volumes mounted
* inside directories.
*
* There is an assumption in this code that 'wide' interfaces are
* being used (see tclWin32Dll.c), which is true for the only systems
* which support reparse tags at present. If that changes in the
* future, this code will have to be generalised.
*/
offset = 0;
if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == '\\') {
/*
* Check whether this is a mounted volume.
*/
if (wcsncmp(reparseBuffer->MountPointReparseBuffer.PathBuffer,
L"\\??\\Volume{",11) == 0) {
char drive;
/*
* There is some confusion between \??\ and \\?\ which we have
* to fix here. It doesn't seem very well documented.
*/
reparseBuffer->MountPointReparseBuffer.PathBuffer[1] = '\\';
/*
* Check if a corresponding drive letter exists, and use that
* if it is found
*/
drive = TclWinDriveLetterForVolMountPoint(
reparseBuffer->MountPointReparseBuffer.PathBuffer);
if (drive != -1) {
char driveSpec[3] = {
'\0', ':', '\0'
};
driveSpec[0] = drive;
retVal = Tcl_NewStringObj(driveSpec,2);
Tcl_IncrRefCount(retVal);
return retVal;
}
/*
* This is actually a mounted drive, which doesn't exists as a
* DOS drive letter. This means the path isn't actually a
* link, although we partially treat it like one ('file type'
* will return 'link'), but then the link will actually just
* be treated like an ordinary directory. I don't believe any
* serious inconsistency will arise from this, but it is
* something to be aware of.
*/
goto invalidError;
} else if (wcsncmp(reparseBuffer->MountPointReparseBuffer
.PathBuffer, L"\\\\?\\",4) == 0) {
/*
* Strip off the prefix.
*/
offset = 4;
} else if (wcsncmp(reparseBuffer->MountPointReparseBuffer
.PathBuffer, L"\\??\\",4) == 0) {
/*
* Strip off the prefix.
*/
offset = 4;
}
}
Tcl_DStringInit(&ds);
Tcl_WCharToUtfDString(
reparseBuffer->MountPointReparseBuffer.PathBuffer,
reparseBuffer->MountPointReparseBuffer
.SubstituteNameLength>>1, &ds);
copy = Tcl_DStringValue(&ds)+offset;
len = Tcl_DStringLength(&ds)-offset;
retVal = Tcl_NewStringObj(copy,len);
Tcl_IncrRefCount(retVal);
Tcl_DStringFree(&ds);
return retVal;
}
invalidError:
Tcl_SetErrno(EINVAL);
return NULL;
}
#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
#pragma GCC diagnostic pop
#endif
/*
*--------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
686 687 688 689 690 691 692 |
*
*--------------------------------------------------------------------
*/
static int
NativeReadReparse(
const WCHAR *linkDirPath, /* The junction to read */
| | < | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
*
*--------------------------------------------------------------------
*/
static int
NativeReadReparse(
const WCHAR *linkDirPath, /* The junction to read */
REPARSE_DATA_BUFFER *buffer,/* Pointer to buffer. Cannot be NULL */
DWORD desiredAccess)
{
HANDLE hFile;
DWORD returnedLength;
hFile = CreateFileW(linkDirPath, desiredAccess, FILE_SHARE_READ, NULL,
OPEN_EXISTING,
|
| ︙ | ︙ | |||
711 712 713 714 715 716 717 |
}
/*
* Get the link.
*/
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer,
| | | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 |
}
/*
* Get the link.
*/
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer,
sizeof(DUMMY_REPARSE_BUFFER), &returnedLength, NULL)) {
/*
* Error setting junction.
*/
Tcl_WinConvertError(GetLastError());
CloseHandle(hFile);
return -1;
|
| ︙ | ︙ | |||
868 869 870 871 872 873 874 |
*---------------------------------------------------------------------------
*/
void
TclpFindExecutable(
TCL_UNUSED(const char *))
{
| < | < < | < < < < < < < | < < < < < | | | < < | | | < < | < < | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
*---------------------------------------------------------------------------
*/
void
TclpFindExecutable(
TCL_UNUSED(const char *))
{
WCHAR wName[MAX_PATH];
char name[MAX_PATH * TCL_UTF_MAX];
GetModuleFileNameW(NULL, wName, sizeof(wName)/sizeof(wName[0]));
WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL);
TclWinNoBackslash(name);
TclSetObjNameOfExecutable(Tcl_NewStringObj(name, TCL_INDEX_NONE), NULL);
#if !defined(STATIC_BUILD)
HMODULE hModule = (HMODULE)TclWinGetTclInstance();
if (hModule) {
GetModuleFileNameW(hModule, wName, sizeof(wName) / sizeof(wName[0]));
WideCharToMultiByte(CP_UTF8, 0, wName, -1,
name, sizeof(name), NULL, NULL);
TclSetObjNameOfShlib(Tcl_NewStringObj(name, TCL_AUTO_LENGTH), NULL);
}
#endif
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
960 961 962 963 964 965 966 | */ DWORD attr; WIN32_FILE_ATTRIBUTE_DATA data; Tcl_Size len = 0; const char *str; | | < < | < < | < < | 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 |
*/
DWORD attr;
WIN32_FILE_ATTRIBUTE_DATA data;
Tcl_Size len = 0;
const char *str;
if (norm != pathPtr) { Tcl_IncrRefCount(norm); }
str = TclGetStringFromObj(norm, &len);
native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
if (GetFileAttributesExW(native,
GetFileExInfoStandard, &data) != TRUE) {
if (norm != pathPtr) { Tcl_DecrRefCount(norm); }
return TCL_OK;
}
attr = data.dwFileAttributes;
if (NativeMatchType(WinIsDrive(str, len), attr, native, types)) {
Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
}
if (norm != pathPtr) { Tcl_DecrRefCount(norm); }
}
return TCL_OK;
} else {
DWORD attr;
HANDLE handle;
WIN32_FIND_DATAW data;
const char *dirName; /* UTF-8 dir name, later with pattern
|
| ︙ | ︙ | |||
1007 1008 1009 1010 1011 1012 1013 |
*/
fileNamePtr = Tcl_FSGetNormalizedPath(interp, pathPtr);
if (fileNamePtr == NULL) {
return TCL_ERROR;
}
/* Ensure it'd be alive, while used. */
| | < < | < < | < < | < < | 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 |
*/
fileNamePtr = Tcl_FSGetNormalizedPath(interp, pathPtr);
if (fileNamePtr == NULL) {
return TCL_ERROR;
}
/* Ensure it'd be alive, while used. */
if (fileNamePtr != pathPtr) { Tcl_IncrRefCount(fileNamePtr); }
/*
* Verify that the specified path exists and is actually a directory.
*/
native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
if (native == NULL) {
if (fileNamePtr != pathPtr) { Tcl_DecrRefCount(fileNamePtr); }
return TCL_OK;
}
attr = GetFileAttributesW(native);
if ((attr == INVALID_FILE_ATTRIBUTES)
|| ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
if (fileNamePtr != pathPtr) { Tcl_DecrRefCount(fileNamePtr); }
return TCL_OK;
}
/*
* Build up the directory name for searching, including a trailing
* directory separator.
*/
Tcl_DStringInit(&dsOrig);
dirName = TclGetStringFromObj(fileNamePtr, &dirLength);
Tcl_DStringAppend(&dsOrig, dirName, dirLength);
lastChar = dirName[dirLength -1];
if ((lastChar != '\\') && (lastChar != '/') && (lastChar != ':')) {
TclDStringAppendLiteral(&dsOrig, "/");
dirLength++;
}
if (fileNamePtr != pathPtr) { Tcl_DecrRefCount(fileNamePtr); }
dirName = Tcl_DStringValue(&dsOrig);
/*
* We need to check all files in the directory, so we append '*.*' to
* the path, unless the pattern we've been given is rather simple,
* when we can use that instead.
*/
|
| ︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 |
dirName = Tcl_DStringAppend(&dsOrig, pattern, TCL_INDEX_NONE);
} else {
dirName = TclDStringAppendLiteral(&dsOrig, "*.*");
}
Tcl_DStringInit(&ds);
native = Tcl_UtfToWCharDString(dirName, TCL_INDEX_NONE, &ds);
| > | > > > > | > > | < > | 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 |
dirName = Tcl_DStringAppend(&dsOrig, pattern, TCL_INDEX_NONE);
} else {
dirName = TclDStringAppendLiteral(&dsOrig, "*.*");
}
Tcl_DStringInit(&ds);
native = Tcl_UtfToWCharDString(dirName, TCL_INDEX_NONE, &ds);
if ((types == NULL) || (types->type != TCL_GLOB_TYPE_DIR)) {
handle = FindFirstFileW(native, &data);
} else {
/*
* We can be more efficient, for pure directory requests.
*/
handle = FindFirstFileExW(native,
FindExInfoStandard, &data,
FindExSearchLimitToDirectories, NULL, 0);
}
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
Tcl_DStringFree(&ds);
if (IsNoSuchFileError(err)) {
/*
|
| ︙ | ︙ | |||
1187 1188 1189 1190 1191 1192 1193 |
Tcl_DStringSetLength(&dsOrig, dirLength);
} else {
isDrive = 0;
}
if (NativeMatchType(isDrive, attr, native, types)) {
Tcl_ListObjAppendElement(interp, resultPtr,
TclNewFSPathObj(pathPtr, utfname,
| | < < < < < < | | | | | < | 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 |
Tcl_DStringSetLength(&dsOrig, dirLength);
} else {
isDrive = 0;
}
if (NativeMatchType(isDrive, attr, native, types)) {
Tcl_ListObjAppendElement(interp, resultPtr,
TclNewFSPathObj(pathPtr, utfname,
Tcl_DStringLength(&ds)));
}
}
/*
* Free ds here to ensure that native is valid above.
*/
Tcl_DStringFree(&ds);
} while (FindNextFileW(handle, &data) == TRUE);
FindClose(handle);
Tcl_DStringFree(&dsOrig);
return TCL_OK;
}
}
/*
* Does the given path represent a root volume? We need this special case
* because for NTFS root volumes, the getFileAttributesProc returns a 'hidden'
* attribute when it should not.
*/
static int
WinIsDrive(
const char *name, /* Name (UTF-8) */
size_t len) /* Length of name */
{
int remove = 0;
|
| ︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 |
} else if (len == 1 && (name[0] == '/' || name[0] == '\\')) {
/*
* Path is pointing to the root volume.
*/
return 1;
} else if ((name[1] == ':')
| | < < < < | | | | | < | 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 |
} else if (len == 1 && (name[0] == '/' || name[0] == '\\')) {
/*
* Path is pointing to the root volume.
*/
return 1;
} else if ((name[1] == ':')
&& (len == 2 || (name[2] == '/' || name[2] == '\\'))) {
/*
* Path is of the form 'x:' or 'x:/' or 'x:\'
*/
return 1;
}
}
return 0;
}
/*
* Does the given path represent a reserved window path name? If not return 0,
* if true, return the number of characters of the path that we actually want
* (not any trailing :).
*/
static size_t
WinIsReserved(
const char *path) /* Path in UTF-8 */
{
if ((path[0] == 'c' || path[0] == 'C')
&& (path[1] == 'o' || path[1] == 'O')) {
if ((path[2] == 'm' || path[2] == 'M')
|
| ︙ | ︙ | |||
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 |
} else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') {
/*
* Have match for 'con'
*/
return 3;
}
} else if ((path[0] == 'l' || path[0] == 'L')
&& (path[1] == 'p' || path[1] == 'P')
&& (path[2] == 't' || path[2] == 'T')) {
if (path[3] >= '1' && path[3] <= '9') {
/*
* May have match for 'lpt[1-9]:?'
*/
if (path[4] == '\0') {
return 4;
} else if (path[4] == ':' && path[5] == '\0') {
return 4;
}
}
} else if (!strcasecmp(path, "prn") || !strcasecmp(path, "nul")
|| !strcasecmp(path, "aux")) {
/*
* Have match for 'prn', 'nul' or 'aux'.
*/
return 3;
| > > | 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 |
} else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') {
/*
* Have match for 'con'
*/
return 3;
}
} else if ((path[0] == 'l' || path[0] == 'L')
&& (path[1] == 'p' || path[1] == 'P')
&& (path[2] == 't' || path[2] == 'T')) {
if (path[3] >= '1' && path[3] <= '9') {
/*
* May have match for 'lpt[1-9]:?'
*/
if (path[4] == '\0') {
return 4;
} else if (path[4] == ':' && path[5] == '\0') {
return 4;
}
}
} else if (!strcasecmp(path, "prn") || !strcasecmp(path, "nul")
|| !strcasecmp(path, "aux")) {
/*
* Have match for 'prn', 'nul' or 'aux'.
*/
return 3;
|
| ︙ | ︙ | |||
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 |
if ((types->type & TCL_GLOB_TYPE_DIR)
&& (attr & FILE_ATTRIBUTE_DIRECTORY)) {
/*
* Quicker test for directory, which is a common case.
*/
return 1;
} else if (types->type != 0) {
unsigned short st_mode;
int isExec = NativeIsExec(nativeName);
st_mode = NativeStatMode(attr, 0, isExec);
/*
| > | 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 |
if ((types->type & TCL_GLOB_TYPE_DIR)
&& (attr & FILE_ATTRIBUTE_DIRECTORY)) {
/*
* Quicker test for directory, which is a common case.
*/
return 1;
} else if (types->type != 0) {
unsigned short st_mode;
int isExec = NativeIsExec(nativeName);
st_mode = NativeStatMode(attr, 0, isExec);
/*
|
| ︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 |
const char *name, /* User name for desired home directory. */
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
* name of user's home directory. */
{
char *result = NULL;
USER_INFO_1 *uiPtr;
Tcl_DString ds;
| | < < < < | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 |
const char *name, /* User name for desired home directory. */
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
* name of user's home directory. */
{
char *result = NULL;
USER_INFO_1 *uiPtr;
Tcl_DString ds;
int nameLen = -1;
int rc = 0;
const char *domain;
WCHAR *wName, *wHomeDir, *wDomain;
Tcl_DStringInit(bufferPtr);
wDomain = NULL;
domain = Tcl_UtfFindFirst(name, '@');
if (domain == NULL) {
const char *ptr;
/*
|
| ︙ | ︙ | |||
1522 1523 1524 1525 1526 1527 1528 |
* and USERPROFILE.
*
* Fixing this for the general user needs more investigating but
* at least for the current user we can use a direct call.
*/
ptr = TclpGetUserName(&ds);
if (ptr != NULL && strcasecmp(name, ptr) == 0) {
| | > > > | < | < < | | | | | > < < < < < | 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 |
* and USERPROFILE.
*
* Fixing this for the general user needs more investigating but
* at least for the current user we can use a direct call.
*/
ptr = TclpGetUserName(&ds);
if (ptr != NULL && strcasecmp(name, ptr) == 0) {
HANDLE hProcess;
WCHAR buf[MAX_PATH];
DWORD nChars = sizeof(buf) / sizeof(buf[0]);
/* Sadly GetCurrentProcessToken not in Win 7 so slightly longer */
hProcess = GetCurrentProcess(); /* Need not be closed */
if (hProcess) {
HANDLE hToken;
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
if (GetUserProfileDirectoryW(hToken, buf, &nChars)) {
result = Tcl_WCharToUtfDString(buf, nChars-1, (bufferPtr));
rc = 1;
}
CloseHandle(hToken);
}
}
}
Tcl_DStringFree(&ds);
} else {
Tcl_DStringInit(&ds);
wName = Tcl_UtfToWCharDString(domain + 1, TCL_INDEX_NONE, &ds);
rc = NetGetDCName(NULL, wName, (LPBYTE *) &wDomain);
|
| ︙ | ︙ | |||
1575 1576 1577 1578 1579 1580 1581 1582 1583 |
rc = NetGetDCName(NULL, NULL, (LPBYTE *) &wDomain);
if (rc != 0) {
break;
}
domain = (const char *)INT2PTR(-1); /* repeat once */
}
if (rc == 0) {
wHomeDir = uiPtr->usri1_home_dir;
if ((wHomeDir != NULL) && (wHomeDir[0] != '\0')) {
| > > > | > | < < < < < < < < < < < | | | | < | < < > | > | > > > > < | 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 |
rc = NetGetDCName(NULL, NULL, (LPBYTE *) &wDomain);
if (rc != 0) {
break;
}
domain = (const char *)INT2PTR(-1); /* repeat once */
}
if (rc == 0) {
DWORD i, size = MAX_PATH;
wHomeDir = uiPtr->usri1_home_dir;
if ((wHomeDir != NULL) && (wHomeDir[0] != '\0')) {
size = lstrlenW(wHomeDir);
Tcl_WCharToUtfDString(wHomeDir, size, bufferPtr);
} else {
WCHAR buf[MAX_PATH];
/*
* User exists but has no home dir. Return
* "{GetProfilesDirectory}/<user>".
*/
GetProfilesDirectoryW(buf, &size);
Tcl_WCharToUtfDString(buf, size-1, bufferPtr);
Tcl_DStringAppend(bufferPtr, "/", 1);
Tcl_DStringAppend(bufferPtr, name, nameLen);
}
result = Tcl_DStringValue(bufferPtr);
/*
* Be sure we return normalized path
*/
for (i = 0; i < size; ++i) {
if (result[i] == '\\') {
result[i] = '/';
}
}
NetApiBufferFree((void *)uiPtr);
}
Tcl_DStringFree(&ds);
}
if (wDomain != NULL) {
NetApiBufferFree((void *)wDomain);
}
return result;
}
/*
*---------------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1813 1814 1815 1816 1817 1818 1819 | goto accessError; } /* * As of Samba 3.0.23 (10-Jul-2006), unmapped users and groups are * assigned to SID domains S-1-22-1 and S-1-22-2, where "22" is the | | | | | | 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 |
goto accessError;
}
/*
* As of Samba 3.0.23 (10-Jul-2006), unmapped users and groups are
* assigned to SID domains S-1-22-1 and S-1-22-2, where "22" is the
* top-level authority. If the file owner and group is unmapped then
* the ACL access check below will only test against world access,
* which is likely to be more restrictive than the actual access
* restrictions. Since the ACL tests are more likely wrong than
* right, skip them. Moreover, the unix owner access permissions are
* usually mapped to the Windows attributes, so if the user is the
* file owner then the attrib checks above are correct (as far as they
* go).
*/
if(!GetSecurityDescriptorOwner(sdPtr,&pSid,&SidDefaulted) ||
memcmp(GetSidIdentifierAuthority(pSid),&samba_unmapped,
sizeof(SID_IDENTIFIER_AUTHORITY))==0) {
HeapFree(GetProcessHeap(), 0, sdPtr);
return 0; /* Attrib tests say access allowed. */
}
/*
* Perform security impersonation of the user and open the resulting
* thread token.
|
| ︙ | ︙ | |||
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 |
HeapFree(GetProcessHeap(), 0, sdPtr);
CloseHandle(hToken);
if (!accessYesNo) {
Tcl_SetErrno(EACCES);
return -1;
}
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* NativeIsExec --
*
* Determines if a path is executable. On windows this is simply defined
| > | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 |
HeapFree(GetProcessHeap(), 0, sdPtr);
CloseHandle(hToken);
if (!accessYesNo) {
Tcl_SetErrno(EACCES);
return -1;
}
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* NativeIsExec --
*
* Determines if a path is executable. On windows this is simply defined
* by whether the path ends in a standard executable extension.
*
* Results:
* 1 = executable, 0 = not.
*
*----------------------------------------------------------------------
*/
static int
NativeIsExec(
const WCHAR *path)
{
int len = wcslen(path);
if (len < 5) {
return 0;
}
if (path[len-4] != '.') {
return 0;
}
path += len-3;
if ((_wcsicmp(path, L"exe") == 0)
|| (_wcsicmp(path, L"com") == 0)
|| (_wcsicmp(path, L"cmd") == 0)
|| (_wcsicmp(path, L"bat") == 0)) {
return 1;
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* TclpObjChdir --
*
* This function replaces the library version of chdir().
*
* Results:
* See chdir() documentation.
*
* Side effects:
* See chdir() documentation.
*
*----------------------------------------------------------------------
*/
int
TclpObjChdir(
Tcl_Obj *pathPtr) /* Path to new working directory. */
{
int result;
const WCHAR *nativePath;
nativePath = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
if (!nativePath) {
return -1;
}
result = SetCurrentDirectoryW(nativePath);
if (result == 0) {
Tcl_WinConvertError(GetLastError());
return -1;
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* TclpGetCwd --
|
| ︙ | ︙ | |||
2080 2081 2082 2083 2084 2085 2086 2087 2088 |
const char *
TclpGetCwd(
Tcl_Interp *interp, /* If non-NULL, used for error reporting. */
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
* name of current directory. */
{
char *p;
WCHAR *native;
| > < | < > | > > < > | > | 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 |
const char *
TclpGetCwd(
Tcl_Interp *interp, /* If non-NULL, used for error reporting. */
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
* name of current directory. */
{
WCHAR buffer[MAX_PATH];
char *p;
WCHAR *native;
if (GetCurrentDirectoryW(MAX_PATH, buffer) == 0) {
Tcl_WinConvertError(GetLastError());
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"error getting working directory name: %s",
Tcl_PosixError(interp)));
}
return NULL;
}
/*
* Watch for the weird Windows c:\\UNC syntax.
*/
native = (WCHAR *) buffer;
if ((native[0] != '\0') && (native[1] == ':')
&& (native[2] == '\\') && (native[3] == '\\')) {
native += 2;
}
Tcl_DStringInit(bufferPtr);
Tcl_WCharToUtfDString(native, TCL_INDEX_NONE, bufferPtr);
/*
* Convert to forward slashes for easier use in scripts.
*/
for (p = Tcl_DStringValue(bufferPtr); *p != '\0'; p++) {
if (*p == '\\') {
*p = '/';
}
}
return Tcl_DStringValue(bufferPtr);
|
| ︙ | ︙ | |||
2162 2163 2164 2165 2166 2167 2168 |
NativeStat(
const WCHAR *nativePath, /* Path of file to stat */
Tcl_StatBuf *statPtr, /* Filled with results of stat call. */
int checkLinks) /* If non-zero, behave like 'lstat' */
{
DWORD attr;
int dev, nlink = 1;
| | | 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 |
NativeStat(
const WCHAR *nativePath, /* Path of file to stat */
Tcl_StatBuf *statPtr, /* Filled with results of stat call. */
int checkLinks) /* If non-zero, behave like 'lstat' */
{
DWORD attr;
int dev, nlink = 1;
unsigned short mode;
unsigned int inode = 0;
HANDLE fileHandle;
DWORD fileType = FILE_TYPE_UNKNOWN;
/*
* If we can use 'createFile' on this, then we can use the resulting
* fileHandle to read more information (nlink, ino) than we can get from
|
| ︙ | ︙ | |||
2190 2191 2192 2193 2194 2195 2196 |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) {
BY_HANDLE_FILE_INFORMATION data;
| | | 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 |
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (fileHandle != INVALID_HANDLE_VALUE) {
BY_HANDLE_FILE_INFORMATION data;
if (GetFileInformationByHandle(fileHandle,&data) != TRUE) {
fileType = GetFileType(fileHandle);
CloseHandle(fileHandle);
if (fileType != FILE_TYPE_CHAR && fileType != FILE_TYPE_DISK) {
Tcl_SetErrno(ENOENT);
return -1;
}
|
| ︙ | ︙ | |||
2249 2250 2251 2252 2253 2254 2255 |
HANDLE hFind;
WIN32_FIND_DATAW ffd;
DWORD lasterror = GetLastError();
if (lasterror != ERROR_SHARING_VIOLATION) {
Tcl_WinConvertError(lasterror);
return -1;
| | | 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 |
HANDLE hFind;
WIN32_FIND_DATAW ffd;
DWORD lasterror = GetLastError();
if (lasterror != ERROR_SHARING_VIOLATION) {
Tcl_WinConvertError(lasterror);
return -1;
}
hFind = FindFirstFileW(nativePath, &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
Tcl_WinConvertError(GetLastError());
return -1;
}
memcpy(&data, &ffd, sizeof(data));
FindClose(hFind);
|
| ︙ | ︙ | |||
2271 2272 2273 2274 2275 2276 2277 |
statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
statPtr->st_ctime = ToCTime(data.ftCreationTime);
}
dev = NativeDev(nativePath);
mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
if (fileType == FILE_TYPE_CHAR) {
| | | | | | | 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 |
statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
statPtr->st_ctime = ToCTime(data.ftCreationTime);
}
dev = NativeDev(nativePath);
mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
if (fileType == FILE_TYPE_CHAR) {
mode &= ~S_IFMT;
mode |= S_IFCHR;
} else if (fileType == FILE_TYPE_DISK) {
mode &= ~S_IFMT;
mode |= S_IFBLK;
}
statPtr->st_dev = (dev_t) dev;
statPtr->st_ino = inode;
statPtr->st_mode = mode;
statPtr->st_nlink = nlink;
statPtr->st_uid = 0;
statPtr->st_gid = 0;
statPtr->st_rdev = (dev_t) dev;
return 0;
}
/*
|
| ︙ | ︙ | |||
2304 2305 2306 2307 2308 2309 2310 |
static int
NativeDev(
const WCHAR *nativePath) /* Full path of file to stat */
{
int dev;
Tcl_DString ds;
| | < < | < < < < | 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 |
static int
NativeDev(
const WCHAR *nativePath) /* Full path of file to stat */
{
int dev;
Tcl_DString ds;
WCHAR nativeFullPath[MAX_PATH];
WCHAR *nativePart;
const char *fullPath;
GetFullPathNameW(nativePath, MAX_PATH, nativeFullPath, &nativePart);
Tcl_DStringInit(&ds);
fullPath = Tcl_WCharToUtfDString(nativeFullPath, TCL_INDEX_NONE, &ds);
if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
const char *p;
DWORD dw;
const WCHAR *nativeVol;
Tcl_DString volString;
|
| ︙ | ︙ | |||
2484 2485 2486 2487 2488 2489 2490 |
*----------------------------------------------------------------------
*/
void *
TclpGetNativeCwd(
void *clientData)
{
| | < | < | < | < < | | 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 |
*----------------------------------------------------------------------
*/
void *
TclpGetNativeCwd(
void *clientData)
{
WCHAR buffer[MAX_PATH];
if (GetCurrentDirectoryW(MAX_PATH, buffer) == 0) {
Tcl_WinConvertError(GetLastError());
return NULL;
}
if (clientData != NULL) {
if (wcscmp((const WCHAR *) clientData, buffer) == 0) {
return clientData;
}
}
return TclNativeDupInternalRep(buffer);
}
int
TclpObjAccess(
Tcl_Obj *pathPtr,
int mode)
{
return NativeAccess((const WCHAR *)Tcl_FSGetNativePath(pathPtr), mode);
}
|
| ︙ | ︙ | |||
2545 2546 2547 2548 2549 2550 2551 |
const WCHAR *LinkTarget;
const WCHAR *LinkSource = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
Tcl_Obj *normToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr);
if (normToPtr == NULL) {
return NULL;
}
| | < < | < < | < < | 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 |
const WCHAR *LinkTarget;
const WCHAR *LinkSource = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
Tcl_Obj *normToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr);
if (normToPtr == NULL) {
return NULL;
}
if (normToPtr != toPtr) { Tcl_IncrRefCount(normToPtr); }
LinkTarget = (const WCHAR *)Tcl_FSGetNativePath(normToPtr);
if (LinkSource == NULL || LinkTarget == NULL) {
if (normToPtr != toPtr) { Tcl_DecrRefCount(normToPtr); }
return NULL;
}
res = WinLink(LinkSource, LinkTarget, linkAction);
if (normToPtr != toPtr) { Tcl_DecrRefCount(normToPtr); }
if (res == 0) {
return toPtr;
} else {
return NULL;
}
} else {
const WCHAR *LinkSource = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
|
| ︙ | ︙ | |||
2662 2663 2664 2665 2666 2667 2668 |
*
*---------------------------------------------------------------------------
*/
int
TclpObjNormalizePath(
TCL_UNUSED(Tcl_Interp *),
| | | < | 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 |
*
*---------------------------------------------------------------------------
*/
int
TclpObjNormalizePath(
TCL_UNUSED(Tcl_Interp *),
Tcl_Obj *pathPtr, /* An unshared object containing the path to
* normalize */
int nextCheckpoint) /* offset to start at in pathPtr */
{
char *lastValidPathEnd = NULL;
Tcl_DString dsNorm; /* This will hold the normalized string. */
char *path, *currentPathEndPosition;
Tcl_Obj *temp = NULL;
int isDrive = 1;
Tcl_DString ds; /* Some workspace. */
Tcl_DStringInit(&dsNorm);
path = TclGetString(pathPtr);
currentPathEndPosition = path + nextCheckpoint;
if (*currentPathEndPosition == '/') {
currentPathEndPosition++;
|
| ︙ | ︙ | |||
2825 2826 2827 2828 2829 2830 2831 |
checkDots = NULL;
break;
}
checkDots++;
}
}
if (checkDots != NULL) {
| | | 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 |
checkDots = NULL;
break;
}
checkDots++;
}
}
if (checkDots != NULL) {
int dotLen = currentPathEndPosition-lastValidPathEnd;
/*
* Path is just dots. We shouldn't really ever see a path
* like that. However, to be nice we at least don't mangle
* the path - we just add the dots as a path segment and
* continue.
*/
|
| ︙ | ︙ | |||
2944 2945 2946 2947 2948 2949 2950 |
* sharing the same underlying string.
*/
if (temp != NULL) {
Tcl_DecrRefCount(temp);
}
| | | 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 |
* sharing the same underlying string.
*/
if (temp != NULL) {
Tcl_DecrRefCount(temp);
}
return nextCheckpoint;
}
/*
*---------------------------------------------------------------------------
*
* TclWinVolumeRelativeNormalize --
*
|
| ︙ | ︙ | |||
2966 2967 2968 2969 2970 2971 2972 | * code path to be executed, causing various errors because * volume-relative paths really do not exist. * * Results: * A valid normalized path. * * Side effects: | | < < < < | | < | < < > | | < < | < | < | | < < | | < < | < < < < < < > > > > > | < > < < < < < < < < | < < > | | | < < > | > > | < < > | < < > > | | | | | | > > | > > > > > > > > > > > | < < | | 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 |
* code path to be executed, causing various errors because
* volume-relative paths really do not exist.
*
* Results:
* A valid normalized path.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
Tcl_Obj *
TclWinVolumeRelativeNormalize(
Tcl_Interp *interp,
const char *path,
Tcl_Obj **useThisCwdPtr)
{
Tcl_Obj *absolutePath, *useThisCwd;
useThisCwd = Tcl_FSGetCwd(interp);
if (useThisCwd == NULL) {
return NULL;
}
if (path[0] == '/') {
/*
* Path of form /foo/bar which is a path in the root directory of the
* current volume.
*/
const char *drive = TclGetString(useThisCwd);
absolutePath = Tcl_NewStringObj(drive,2);
Tcl_AppendToObj(absolutePath, path, TCL_INDEX_NONE);
Tcl_IncrRefCount(absolutePath);
/*
* We have a refCount on the cwd.
*/
} else {
/*
* Path of form C:foo/bar, but this only makes sense if the cwd is
* also on drive C.
*/
Tcl_Size cwdLen;
const char *drive = TclGetStringFromObj(useThisCwd, &cwdLen);
char drive_cur = path[0];
if (drive_cur >= 'a') {
drive_cur -= ('a' - 'A');
}
if (drive[0] == drive_cur) {
absolutePath = Tcl_DuplicateObj(useThisCwd);
/*
* We have a refCount on the cwd, which we will release later.
*/
if (drive[cwdLen-1] != '/' && (path[2] != '\0')) {
/*
* Only add a trailing '/' if needed, which is if there isn't
* one already, and if we are going to be adding some more
* characters.
*/
Tcl_AppendToObj(absolutePath, "/", 1);
}
} else {
Tcl_DecrRefCount(useThisCwd);
useThisCwd = NULL;
/*
* The path is not in the current drive, but is volume-relative.
* The way Tcl 8.3 handles this is that it treats such a path as
* relative to the root of the drive. We therefore behave the same
* here. This behaviour is, however, different to that of the
* windows command-line. If we want to fix this at some point in
* the future (at the expense of a behaviour change to Tcl), we
* could use the '_dgetdcwd' Win32 API to get the drive's cwd.
*/
absolutePath = Tcl_NewStringObj(path, 2);
Tcl_AppendToObj(absolutePath, "/", 1);
}
Tcl_IncrRefCount(absolutePath);
Tcl_AppendToObj(absolutePath, path+2, TCL_INDEX_NONE);
}
*useThisCwdPtr = useThisCwd;
return absolutePath;
}
/*
*---------------------------------------------------------------------------
*
* TclpNativeToNormalized --
|
| ︙ | ︙ | |||
3107 3108 3109 3110 3111 3112 3113 |
/*
* Certain native path representations on Windows have this special prefix
* to indicate that they are to be treated specially. For example
* extremely long paths, or symlinks.
*/
if (*copy == '\\') {
| | | | | 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 |
/*
* Certain native path representations on Windows have this special prefix
* to indicate that they are to be treated specially. For example
* extremely long paths, or symlinks.
*/
if (*copy == '\\') {
if (0 == strncmp(copy,"\\??\\",4)) {
copy += 4;
len -= 4;
} else if (0 == strncmp(copy,"\\\\?\\",4)) {
copy += 4;
len -= 4;
}
}
/*
* Ensure we are using forward slashes only.
*/
for (p = copy; *p != '\0'; p++) {
if (*p == '\\') {
*p = '/';
}
}
objPtr = Tcl_NewStringObj(copy,len);
Tcl_DStringFree(&ds);
return objPtr;
}
/*
*---------------------------------------------------------------------------
|
| ︙ | ︙ | |||
3228 3229 3230 3231 3232 3233 3234 |
*/
wp = nativePathPtr = (WCHAR *)Tcl_Alloc((len + 6) * sizeof(WCHAR));
if (nativePathPtr==0) {
goto done;
}
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, nativePathPtr,
| | < | < | 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 |
*/
wp = nativePathPtr = (WCHAR *)Tcl_Alloc((len + 6) * sizeof(WCHAR));
if (nativePathPtr==0) {
goto done;
}
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, nativePathPtr,
len + 2);
nativePathPtr[len] = 0;
/*
* If path starts with "//?/" or "\\?\" (extended path), translate any
* slashes to backslashes but leave the '?' intact
*/
if ((str[0] == '\\' || str[0] == '/') && (str[1] == '\\' || str[1] == '/')
&& str[2] == '?' && (str[3] == '\\' || str[3] == '/')) {
wp[0] = wp[1] = wp[3] = '\\';
str += 4;
wp += 4;
}
/*
* If there is no "\\?\" prefix but there is a drive or UNC path prefix
* and the path is larger than MAX_PATH chars, no Win32 API function can
* handle that unless it is prefixed with the extended path prefix. See:
* <https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maxpath>
*/
if (((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z'))
&& str[1] == ':') {
if (wp == nativePathPtr && len > MAX_PATH
&& (str[2] == '\\' || str[2] == '/')) {
memmove(wp + 4, wp, len * sizeof(WCHAR));
memcpy(wp, L"\\\\?\\", 4 * sizeof(WCHAR));
wp += 4;
}
/*
* If (remainder of) path starts with "<drive>:", leave the ':'
|
| ︙ | ︙ | |||
3394 3395 3396 3397 3398 3399 3400 | /* *--------------------------------------------------------------------------- * * TclWinFileOwned -- * * Returns 1 if the specified file exists and is owned by the current | | | | 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 |
/*
*---------------------------------------------------------------------------
*
* TclWinFileOwned --
*
* Returns 1 if the specified file exists and is owned by the current
* user and 0 otherwise. Like the Unix case, the check is made using
* the real process SID, not the effective (impersonation) one.
*
*---------------------------------------------------------------------------
*/
int
TclWinFileOwned(
Tcl_Obj *pathPtr) /* File whose ownership is to be checked */
|
| ︙ | ︙ | |||
3432 3433 3434 3435 3436 3437 3438 |
/*
* Getting the current process SID is a multi-step process. We make the
* assumption that if a call fails, this process is so underprivileged it
* could not possibly own anything. Normally a process can *always* look
* up its own token.
*/
| > > > > | | < | | | | | | > > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 |
/*
* Getting the current process SID is a multi-step process. We make the
* assumption that if a call fails, this process is so underprivileged it
* could not possibly own anything. Normally a process can *always* look
* up its own token.
*/
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
/*
* Find out how big the buffer needs to be.
*/
bufsz = 0;
GetTokenInformation(token, TokenUser, NULL, 0, &bufsz);
if (bufsz) {
buf = (LPBYTE)Tcl_Alloc(bufsz);
if (GetTokenInformation(token, TokenUser, buf, bufsz, &bufsz)) {
owned = EqualSid(ownerSid, ((PTOKEN_USER) buf)->User.Sid);
}
}
CloseHandle(token);
}
/*
* Free allocations and be done.
*/
if (secd) {
LocalFree(secd); /* Also frees ownerSid */
}
if (buf) {
Tcl_Free(buf);
}
return (owned != 0); /* Convert non-0 to 1 */
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to win/tclWinInit.c.
| ︙ | ︙ | |||
65 66 67 68 69 70 71 |
static ProcessGlobalValue defaultLibraryDir =
{0, 0, NULL, NULL, InitializeDefaultLibraryDir, NULL, NULL};
static ProcessGlobalValue sourceLibraryDir =
{0, 0, NULL, NULL, InitializeSourceLibraryDir, NULL, NULL};
/*
| < < | | | < < | < < < > | | | | > > | | | < > > | > > > > | < < < < < < < < > | | | > | | | < < < < < < < < < | < > > | > > > > > > > > > > > > > | | | | | < | > | | < | | < < | | < < < < < < < > > > | | | | | > > > > > > | | > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
static ProcessGlobalValue defaultLibraryDir =
{0, 0, NULL, NULL, InitializeDefaultLibraryDir, NULL, NULL};
static ProcessGlobalValue sourceLibraryDir =
{0, 0, NULL, NULL, InitializeSourceLibraryDir, NULL, NULL};
/*
* TclpGetWindowsVersionOnce --
*
* Callback to retrieve Windows version information. To be invoked only
* through InitOnceExecuteOnce for thread safety.
*
* Results:
* None.
*/
static BOOL CALLBACK TclpGetWindowsVersionOnce(
TCL_UNUSED(PINIT_ONCE),
TCL_UNUSED(PVOID),
PVOID *lpContext)
{
typedef int(__stdcall getVersionProc)(void *);
static OSVERSIONINFOW osInfo;
/*
* GetVersionExW will not return the "real" Windows version so use
* RtlGetVersion if available and falling back.
*/
HMODULE handle = GetModuleHandleW(L"NTDLL");
getVersionProc *getVersion =
(getVersionProc *)(void *)GetProcAddress(handle, "RtlGetVersion");
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
if (getVersion == NULL || getVersion(&osInfo)) {
if (!GetVersionExW(&osInfo)) {
/* Should never happen but ...*/
return FALSE;
}
}
*lpContext = (LPVOID)&osInfo;
return TRUE;
}
/*
* TclpGetWindowsVersion --
*
* Returns a pointer to the OSVERSIONINFOW structure containing the
* version information for the current Windows version.
*
* Results:
* Pointer to OSVERSIONINFOW structure.
*/
static const OSVERSIONINFOW *TclpGetWindowsVersion(void)
{
static INIT_ONCE osInfoOnce = INIT_ONCE_STATIC_INIT;
OSVERSIONINFOW *osInfoPtr = NULL;
BOOL result = InitOnceExecuteOnce(
&osInfoOnce, TclpGetWindowsVersionOnce, NULL, (LPVOID *)&osInfoPtr);
return result ? osInfoPtr : NULL;
}
/*
* TclpGetCodePageOnce --
*
* Callback to retrieve user code page. To be invoked only
* through InitOnceExecuteOnce for thread safety.
*
* Results:
* None.
*/
static BOOL CALLBACK
TclpGetCodePageOnce(
TCL_UNUSED(PINIT_ONCE),
TCL_UNUSED(PVOID),
PVOID *lpContext)
{
static char codePage[20];
codePage[0] = 'c';
codePage[1] = 'p';
DWORD size = sizeof(codePage) - 2;
/*
* When retrieving code page from registry,
* - use ANSI API's since all values will be ASCII and saves conversion
* - use RegGetValue, not RegQueryValueEx, since the latter does not
* guarantee the value is null terminated
* - added bonus, RegGetValue is much more convenient to use
*/
if (RegGetValueA(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage",
"ACP", RRF_RT_REG_SZ, NULL, codePage+2,
&size) != ERROR_SUCCESS) {
/* On failure, fallback to GetACP() */
UINT acp = GetACP();
snprintf(codePage, sizeof(codePage), "cp%u", acp);
}
if (strcmp(codePage, "cp65001") == 0) {
strcpy(codePage, "utf-8");
}
*lpContext = (LPVOID)&codePage[0];
return TRUE;
}
/*
* TclpGetCodePage --
*
* Returns a pointer to the string identifying the user code page.
*
* For consistency with Windows, which caches the code page at program
* startup, the code page is not updated even if the value in the registry
* changes. (This is similar to environment variables.)
*/
static const char *
TclpGetCodePage(void)
{
static INIT_ONCE codePageOnce = INIT_ONCE_STATIC_INIT;
const char *codePagePtr = NULL;
BOOL result = InitOnceExecuteOnce(
&codePageOnce, TclpGetCodePageOnce, NULL, (LPVOID *)&codePagePtr);
#ifdef NDEBUG
(void) result; /* Keep gcc unused variable quiet */
#else
assert(result == TRUE);
#endif
assert(codePagePtr != NULL);
return codePagePtr;
}
/*
*---------------------------------------------------------------------------
*
* TclpInitPlatform --
*
* Initialize all the platform-dependent things like signals,
* floating-point error handling and sockets.
|
| ︙ | ︙ | |||
229 230 231 232 233 234 235 |
* initialize the Windows function tables here since DllMain() will not be
* invoked.
*/
TclWinInit(GetModuleHandleW(NULL));
#endif
| | | | | < > | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
* initialize the Windows function tables here since DllMain() will not be
* invoked.
*/
TclWinInit(GetModuleHandleW(NULL));
#endif
/* Initialize code page once at startup, will not be updated */
(void)TclpGetCodePage();
}
/*
*-------------------------------------------------------------------------
*
* TclpInitLibraryPath --
*
* This is the fallback routine that sets the library path if the
* application has not set one by the first time it is needed.
*
* Results:
* None.
*
* Side effects:
* Sets the library path to an initial value.
*
*-------------------------------------------------------------------------
*/
void
TclpInitLibraryPath(
char **valuePtr,
size_t *lengthPtr,
Tcl_Encoding *encodingPtr)
{
#define LIBRARY_SIZE 64
|
| ︙ | ︙ | |||
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
* None.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
static void
AppendEnvironment(
Tcl_Obj *pathPtr,
const char *lib)
{
Tcl_Size pathc;
Tcl_Obj *objPtr;
const char **pathv;
char *shortlib;
| > > > > > < | | | < < < < | | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
* None.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
static void
AppendEnvironment(
Tcl_Obj *pathPtr,
const char *lib)
{
Tcl_Size pathc;
WCHAR wBuf[MAX_PATH];
DWORD dw;
char buf[MAX_PATH * 3];
Tcl_Obj *objPtr;
Tcl_DString ds;
const char **pathv;
char *shortlib;
/*
* The shortlib value needs to be the tail component of the lib path. For
* example, "lib/tcl9.0" -> "tcl9.0" while "usr/share/tcl9.0" -> "tcl9.0".
*/
for (shortlib = (char *) &lib[strlen(lib)-1]; shortlib>lib ; shortlib--) {
if (*shortlib == '/') {
if ((size_t)(shortlib - lib) == strlen(lib) - 1) {
Tcl_Panic("last character in lib cannot be '/'");
}
shortlib++;
break;
}
}
if (shortlib == lib) {
Tcl_Panic("no '/' character found in lib");
}
dw = GetEnvironmentVariableW(L"TCL_LIBRARY", wBuf, MAX_PATH);
if (dw <= 0 || dw >= MAX_PATH) {
return;
}
if (WideCharToMultiByte(
CP_UTF8, 0, wBuf, -1, buf, MAX_PATH * 3, NULL, NULL) == 0) {
return;
}
if (buf[0] != '\0') {
objPtr = Tcl_NewStringObj(buf, TCL_INDEX_NONE);
Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
|
| ︙ | ︙ | |||
382 383 384 385 386 387 388 |
if ((pathc > 0) && (lstrcmpiA(shortlib, pathv[pathc - 1]) != 0)) {
/*
* TCL_LIBRARY is set but refers to a different tcl installation
* than the current version. Try fiddling with the specified
* directory to make it refer to this installation by removing the
* old "tclX.Y" and substituting the current version string.
*/
| | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
if ((pathc > 0) && (lstrcmpiA(shortlib, pathv[pathc - 1]) != 0)) {
/*
* TCL_LIBRARY is set but refers to a different tcl installation
* than the current version. Try fiddling with the specified
* directory to make it refer to this installation by removing the
* old "tclX.Y" and substituting the current version string.
*/
pathv[pathc - 1] = shortlib;
Tcl_DStringInit(&ds);
(void) Tcl_JoinPath(pathc, pathv, &ds);
objPtr = Tcl_DStringToObj(&ds);
} else {
objPtr = Tcl_NewStringObj(buf, TCL_INDEX_NONE);
}
Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
Tcl_Free((void *)pathv);
}
}
/*
*---------------------------------------------------------------------------
*
* InitializeDefaultLibraryDir --
*
|
| ︙ | ︙ | |||
482 483 484 485 486 487 488 489 |
static void
InitializeDefaultLibraryDir(
char **valuePtr,
size_t *lengthPtr,
Tcl_Encoding *encodingPtr)
{
*encodingPtr = NULL;
| > > > > > > > > > > > > > > > > > > > > < | | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
static void
InitializeDefaultLibraryDir(
char **valuePtr,
size_t *lengthPtr,
Tcl_Encoding *encodingPtr)
{
HMODULE hModule = (HMODULE)TclWinGetTclInstance();
WCHAR wName[MAX_PATH + LIBRARY_SIZE];
char name[(MAX_PATH + LIBRARY_SIZE) * 3];
char *end, *p;
GetModuleFileNameW(hModule, wName, sizeof(wName)/sizeof(WCHAR));
WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL);
end = strrchr(name, '\\');
*end = '\0';
p = strrchr(name, '\\');
if (p != NULL) {
end = p;
}
*end = '\\';
TclWinNoBackslash(name);
snprintf(end + 1, LIBRARY_SIZE, "lib/tcl%s", TCL_VERSION);
*lengthPtr = strlen(name);
*valuePtr = (char *)Tcl_Alloc(*lengthPtr + 1);
*encodingPtr = NULL;
memcpy(*valuePtr, name, *lengthPtr + 1);
}
/*
*---------------------------------------------------------------------------
*
* InitializeSourceLibraryDir --
*
|
| ︙ | ︙ | |||
511 512 513 514 515 516 517 518 |
static void
InitializeSourceLibraryDir(
char **valuePtr,
size_t *lengthPtr,
Tcl_Encoding *encodingPtr)
{
*encodingPtr = NULL;
| > > > > > > > > > > > > > > > > > > > > | | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
static void
InitializeSourceLibraryDir(
char **valuePtr,
size_t *lengthPtr,
Tcl_Encoding *encodingPtr)
{
HMODULE hModule = (HMODULE)TclWinGetTclInstance();
WCHAR wName[MAX_PATH + LIBRARY_SIZE];
char name[(MAX_PATH + LIBRARY_SIZE) * 3];
char *end, *p;
GetModuleFileNameW(hModule, wName, sizeof(wName)/sizeof(WCHAR));
WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL);
end = strrchr(name, '\\');
*end = '\0';
p = strrchr(name, '\\');
if (p != NULL) {
end = p;
}
*end = '\\';
TclWinNoBackslash(name);
snprintf(end + 1, LIBRARY_SIZE, "../library");
*lengthPtr = strlen(name);
*valuePtr = (char *)Tcl_Alloc(*lengthPtr + 1);
*encodingPtr = NULL;
memcpy(*valuePtr, name, *lengthPtr + 1);
}
/*
*---------------------------------------------------------------------------
*
* TclpSetInitialEncodings --
*
|
| ︙ | ︙ | |||
596 597 598 599 600 601 602 |
}
cchUserNameLen--;
Tcl_DStringInit(bufferPtr);
Tcl_WCharToUtfDString(szUserName, cchUserNameLen, bufferPtr);
}
return Tcl_DStringValue(bufferPtr);
}
| | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
}
cchUserNameLen--;
Tcl_DStringInit(bufferPtr);
Tcl_WCharToUtfDString(szUserName, cchUserNameLen, bufferPtr);
}
return Tcl_DStringValue(bufferPtr);
}
/*
*---------------------------------------------------------------------------
*
* TclpSetVariables --
*
* Performs platform-specific interpreter initialization related to the
* tcl_platform and env variables, and other platform-specific things.
|
| ︙ | ︙ | |||
618 619 620 621 622 623 624 625 626 627 628 629 630 |
*----------------------------------------------------------------------
*/
void
TclpSetVariables(
Tcl_Interp *interp) /* Interp to initialize. */
{
const char *ptr;
char buffer[TCL_INTEGER_SPACE * 2];
union {
SYSTEM_INFO info;
OemId oemId;
} sys;
| > | > > > > > > > > > > > > > > | | > | | < < | 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 |
*----------------------------------------------------------------------
*/
void
TclpSetVariables(
Tcl_Interp *interp) /* Interp to initialize. */
{
typedef int(__stdcall getVersionProc)(void *);
const char *ptr;
char buffer[TCL_INTEGER_SPACE * 2];
union {
SYSTEM_INFO info;
OemId oemId;
} sys;
static OSVERSIONINFOW osInfo;
static int osInfoInitialized = 0;
Tcl_DString ds;
Tcl_SetVar2Ex(interp, "tclDefaultLibrary", NULL,
TclGetProcessGlobalValue(&defaultLibraryDir), TCL_GLOBAL_ONLY);
if (!osInfoInitialized) {
HMODULE handle = GetModuleHandleW(L"NTDLL");
getVersionProc *getVersion = (getVersionProc *) (void *)
GetProcAddress(handle, "RtlGetVersion");
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
if (!getVersion || getVersion(&osInfo)) {
GetVersionExW(&osInfo);
}
osInfoInitialized = 1;
}
GetSystemInfo(&sys.info);
/*
* Define the tcl_platform array.
*/
Tcl_SetVar2(interp, "tcl_platform", "platform", "windows",
TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "tcl_platform", "os", "Windows NT", TCL_GLOBAL_ONLY);
if (osInfo.dwMajorVersion == 10 && osInfo.dwBuildNumber >= 22000) {
osInfo.dwMajorVersion = 11;
}
snprintf(buffer, sizeof(buffer), "%ld.%ld",
osInfo.dwMajorVersion, osInfo.dwMinorVersion);
Tcl_SetVar2(interp, "tcl_platform", "osVersion", buffer, TCL_GLOBAL_ONLY);
if (sys.oemId.wProcessorArchitecture < NUMPROCESSORS) {
Tcl_SetVar2(interp, "tcl_platform", "machine",
processors[sys.oemId.wProcessorArchitecture],
TCL_GLOBAL_ONLY);
}
/*
|
| ︙ | ︙ | |||
783 784 785 786 787 788 789 |
*lengthPtr = i;
done:
Tcl_DStringFree(&envString);
Tcl_Free(nameUpper);
return result;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 |
*lengthPtr = i;
done:
Tcl_DStringFree(&envString);
Tcl_Free(nameUpper);
return result;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to win/tclWinInt.h.
1 2 3 4 5 | /* * tclWinInt.h -- * * Declarations of Windows-specific shared variables and procedures. * | | > < | < < < < < | < | < < | < | | < < < | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < | < < | < | < < < < | < < < < < < > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/*
* tclWinInt.h --
*
* Declarations of Windows-specific shared variables and procedures.
*
* Copyright (c) 1994-1996 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#ifndef _TCLWININT
#define _TCLWININT
#include "tclInt.h"
#ifdef HAVE_NO_SEH
/*
* Unlike Borland and Microsoft, we don't register exception handlers by
* pushing registration records onto the runtime stack. Instead, we register
* them by creating an TCLEXCEPTION_REGISTRATION within the activation record.
*/
typedef struct TCLEXCEPTION_REGISTRATION {
struct TCLEXCEPTION_REGISTRATION *link;
EXCEPTION_DISPOSITION (*handler)(
struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
void *ebp;
void *esp;
int status;
} TCLEXCEPTION_REGISTRATION;
#endif
/*
* Declarations of functions that are not accessible by way of the
* stubs table.
*/
MODULE_SCOPE char TclWinDriveLetterForVolMountPoint(
|
| ︙ | ︙ | |||
101 102 103 104 105 106 107 | char *channelName, int permissions); MODULE_SCOPE HANDLE TclWinSerialOpen(HANDLE handle, const WCHAR *name, DWORD access); MODULE_SCOPE int TclWinSymLinkCopyDirectory(const WCHAR *LinkOriginal, const WCHAR *LinkCopy); MODULE_SCOPE int TclWinSymLinkDelete(const WCHAR *LinkOriginal, int linkOnly); | | < < | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | char *channelName, int permissions); MODULE_SCOPE HANDLE TclWinSerialOpen(HANDLE handle, const WCHAR *name, DWORD access); MODULE_SCOPE int TclWinSymLinkCopyDirectory(const WCHAR *LinkOriginal, const WCHAR *LinkCopy); MODULE_SCOPE int TclWinSymLinkDelete(const WCHAR *LinkOriginal, int linkOnly); MODULE_SCOPE int TclWinFileOwned(Tcl_Obj *); MODULE_SCOPE void TclWinGenerateChannelName(char channelName[], const char *channelTypeName, void *channelImpl); MODULE_SCOPE const char*TclpGetUserName(Tcl_DString *bufferPtr); /* Needed by tclWinFile.c and tclWinFCmd.c */ #ifndef FILE_ATTRIBUTE_REPARSE_POINT #define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400 #endif /* *---------------------------------------------------------------------- |
| ︙ | ︙ | |||
156 157 158 159 160 161 162 | MODULE_SCOPE TclPipeThreadInfo * TclPipeThreadCreateTI(TclPipeThreadInfo **pipeTIPtr, void *clientData); MODULE_SCOPE int TclPipeThreadWaitForSignal( TclPipeThreadInfo **pipeTIPtr); | < < < < < < < < < | < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
MODULE_SCOPE
TclPipeThreadInfo * TclPipeThreadCreateTI(TclPipeThreadInfo **pipeTIPtr,
void *clientData);
MODULE_SCOPE int TclPipeThreadWaitForSignal(
TclPipeThreadInfo **pipeTIPtr);
static inline void
TclPipeThreadSignal(
TclPipeThreadInfo **pipeTIPtr)
{
TclPipeThreadInfo *pipeTI = *pipeTIPtr;
if (pipeTI) {
SetEvent(pipeTI->evControl);
}
};
static inline int
TclPipeThreadIsAlive(
TclPipeThreadInfo **pipeTIPtr)
{
TclPipeThreadInfo *pipeTI = *pipeTIPtr;
return (pipeTI && pipeTI->state != PTI_STATE_DOWN);
};
MODULE_SCOPE int TclPipeThreadStopSignal(TclPipeThreadInfo **pipeTIPtr);
MODULE_SCOPE void TclPipeThreadStop(TclPipeThreadInfo **pipeTIPtr,
HANDLE hThread);
MODULE_SCOPE void TclPipeThreadExit(TclPipeThreadInfo **pipeTIPtr);
#endif /* _TCLWININT */
|
Changes to win/tclWinNotify.c.
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | /* * The following static indicates whether this module has been initialized. */ #define INTERVAL_TIMER 1 /* Handle of interval timer. */ | < | < < < | > | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/*
* The following static indicates whether this module has been initialized.
*/
#define INTERVAL_TIMER 1 /* Handle of interval timer. */
#define WM_WAKEUP WM_USER /* Message that is send by
* Tcl_AlertNotifier. */
/*
* The following static structure contains the state information for the
* Windows implementation of the Tcl notifier. One of these structures is
* created for each thread that is using the notifier.
*/
typedef struct {
CRITICAL_SECTION crit; /* Monitor for this notifier. */
DWORD thread; /* Identifier for thread associated with this
* notifier. */
HANDLE event; /* Event object used to wake up the notifier
* thread. */
int pending; /* Alert message pending, this field is locked
* by the notifierMutex. */
HWND hwnd; /* Messaging window. */
int timerActive; /* 1 if interval timer is running. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
/*
* The following static indicates the number of threads that have initialized
* notifiers. It controls the lifetime of the TclNotifier window class.
*
* You must hold the notifierMutex lock before accessing this variable.
*/
static int notifierCount = 0;
static const WCHAR className[] = L"TclNotifier";
static int initialized = 0;
static CRITICAL_SECTION notifierMutex;
/*
* Static routines defined in this file.
*/
static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
|
| ︙ | ︙ | |||
82 83 84 85 86 87 88 |
void *
TclpInitNotifier(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
TclpGlobalLock();
if (!initialized) {
| | | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
void *
TclpInitNotifier(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
TclpGlobalLock();
if (!initialized) {
initialized = 1;
InitializeCriticalSection(¬ifierMutex);
}
TclpGlobalUnlock();
/*
* Register Notifier window class if this is the first thread to use this
* module.
|
| ︙ | ︙ | |||
115 116 117 118 119 120 121 |
Tcl_Panic("Tcl_InitNotifier: %s",
"unable to register TclNotifier window class");
}
}
notifierCount++;
LeaveCriticalSection(¬ifierMutex);
| | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
Tcl_Panic("Tcl_InitNotifier: %s",
"unable to register TclNotifier window class");
}
}
notifierCount++;
LeaveCriticalSection(¬ifierMutex);
tsdPtr->pending = 0;
tsdPtr->timerActive = 0;
InitializeCriticalSection(&tsdPtr->crit);
tsdPtr->hwnd = NULL;
tsdPtr->thread = GetCurrentThreadId();
tsdPtr->event = CreateEventW(NULL, TRUE /* manual */,
FALSE /* !signaled */, NULL);
|
| ︙ | ︙ | |||
147 148 149 150 151 152 153 | * May dispose of the notifier window and class. * *---------------------------------------------------------------------- */ void TclpFinalizeNotifier( | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
* May dispose of the notifier window and class.
*
*----------------------------------------------------------------------
*/
void
TclpFinalizeNotifier(
void *clientData) /* Pointer to notifier data. */
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
/*
* Only finalize the notifier if a notifier was installed in the current
* thread; there is a route in which this is not guaranteed to be true
* (when tclWin32Dll.c:DllMain() is called with the flag
|
| ︙ | ︙ | |||
217 218 219 220 221 222 223 | * isn't already one pending. * *---------------------------------------------------------------------- */ void TclpAlertNotifier( | | | | 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
* isn't already one pending.
*
*----------------------------------------------------------------------
*/
void
TclpAlertNotifier(
void *clientData) /* Pointer to thread data. */
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
/*
* Note that we do not need to lock around access to the hwnd because the
* race condition has no effect since any race condition implies that the
* notifier thread is already awake.
*/
if (tsdPtr->hwnd) {
/*
* We do need to lock around access to the pending flag.
*/
EnterCriticalSection(&tsdPtr->crit);
if (!tsdPtr->pending) {
PostMessageW(tsdPtr->hwnd, WM_WAKEUP, 0, 0);
}
tsdPtr->pending = 1;
LeaveCriticalSection(&tsdPtr->crit);
} else {
SetEvent(tsdPtr->event);
}
}
/*
|
| ︙ | ︙ | |||
263 264 265 266 267 268 269 | * Replaces any previous timer. * *---------------------------------------------------------------------- */ void TclpSetTimer( | | > | | > < < < | < > > > | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
* Replaces any previous timer.
*
*----------------------------------------------------------------------
*/
void
TclpSetTimer(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
UINT timeout;
/*
* We only need to set up an interval timer if we're being called from an
* external event loop. If we don't have a window handle then we just
* return immediately and let Tcl_WaitForEvent handle timeouts.
*/
if (!tsdPtr->hwnd) {
return;
}
if (!timePtr) {
timeout = 0;
} else {
/*
* Make sure we pass a non-zero value into the timeout argument.
* Windows seems to get confused by zero length timers.
*/
timeout = (UINT)timePtr->sec * 1000 + (unsigned long)timePtr->usec / 1000;
if (timeout == 0) {
timeout = 1;
}
}
if (timeout != 0) {
tsdPtr->timerActive = 1;
SetTimer(tsdPtr->hwnd, INTERVAL_TIMER, timeout, NULL);
} else {
tsdPtr->timerActive = 0;
KillTimer(tsdPtr->hwnd, INTERVAL_TIMER);
}
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
333 334 335 336 337 338 339 |
* loop, then create a communication window. Note that after this point,
* the application needs to service events in a timely fashion or Windows
* will hang waiting for the window to respond to synchronous system
* messages. At some point, we may want to consider destroying the window
* if we leave the modal loop, but for now we'll leave it around.
*/
| | | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
* loop, then create a communication window. Note that after this point,
* the application needs to service events in a timely fashion or Windows
* will hang waiting for the window to respond to synchronous system
* messages. At some point, we may want to consider destroying the window
* if we leave the modal loop, but for now we'll leave it around.
*/
if (mode == TCL_SERVICE_ALL && !tsdPtr->hwnd) {
tsdPtr->hwnd = CreateWindowW(className, className, WS_TILED,
0, 0, 0, 0, NULL, NULL, (HINSTANCE) TclWinGetTclInstance(),
NULL);
/*
* Send an initial message to the window to ensure that we wake up the
* notifier once we get into the modal loop. This will force the
|
| ︙ | ︙ | |||
364 365 366 367 368 369 370 | * Always true. * * Side effetcs: * None. *---------------------------------------------------------------------- */ | < > | | | | | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
* Always true.
*
* Side effetcs:
* None.
*----------------------------------------------------------------------
*/
int
TclAsyncNotifier(
TCL_UNUSED(int), /* Signal number. */
TCL_UNUSED(Tcl_ThreadId), /* Target thread. */
TCL_UNUSED(void *), /* Notifier data. */
TCL_UNUSED(int *), /* Flag to mark. */
TCL_UNUSED(int)) /* Value of mark. */
{
return 0;
}
/*
*----------------------------------------------------------------------
*
* NotifierProc --
*
|
| ︙ | ︙ | |||
404 405 406 407 408 409 410 |
WPARAM wParam, /* Passed on... */
LPARAM lParam) /* Passed on... */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (message == WM_WAKEUP) {
EnterCriticalSection(&tsdPtr->crit);
| | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
WPARAM wParam, /* Passed on... */
LPARAM lParam) /* Passed on... */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (message == WM_WAKEUP) {
EnterCriticalSection(&tsdPtr->crit);
tsdPtr->pending = 0;
LeaveCriticalSection(&tsdPtr->crit);
} else if (message != WM_TIMER) {
return DefWindowProcW(hwnd, message, wParam, lParam);
}
/*
* Process all of the runnable events.
|
| ︙ | ︙ | |||
462 463 464 465 466 467 468 | * Dispatches a message to a window procedure, which could do anything. * *---------------------------------------------------------------------- */ int TclpWaitForEvent( | | | > > > > > | > > | > | > > | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
* Dispatches a message to a window procedure, which could do anything.
*
*----------------------------------------------------------------------
*/
int
TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
MSG msg;
DWORD timeout, result;
int status;
/*
* Compute the timeout in milliseconds.
*/
if (timePtr) {
/*
* TIP #233 (Virtualized Time). Convert virtual domain delay to
* real-time.
*/
Tcl_Time myTime;
myTime.sec = timePtr->sec;
myTime.usec = timePtr->usec;
if (myTime.sec != 0 || myTime.usec != 0) {
TclScaleTime(&myTime);
}
timeout = (DWORD)myTime.sec * 1000 + (unsigned long)myTime.usec / 1000;
} else {
timeout = INFINITE;
}
/*
* Check to see if there are any messages in the queue before waiting
* because MsgWaitForMultipleObjects will not wake up if there are events
|
| ︙ | ︙ | |||
549 550 551 552 553 554 555 |
ResetEvent(tsdPtr->event);
return status;
}
/*
*----------------------------------------------------------------------
*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
ResetEvent(tsdPtr->event);
return status;
}
/*
*----------------------------------------------------------------------
*
* Tcl_Sleep --
*
* Delay execution for the specified number of milliseconds.
*
* Results:
* None.
*
* Side effects:
* Time passes.
*
*----------------------------------------------------------------------
*/
void
Tcl_Sleep(
int ms) /* Number of milliseconds to sleep. */
{
/*
* Simply calling 'Sleep' for the requisite number of milliseconds can
* make the process appear to wake up early because it isn't synchronized
* with the CPU performance counter that is used in tclWinTime.c. This
* behavior is probably benign, but messes up some of the corner cases in
* the test suite. We get around this problem by repeating the 'Sleep'
* call as many times as necessary to make the clock advance by the
* requisite amount.
*/
Tcl_Time now; /* Current wall clock time. */
Tcl_Time desired; /* Desired wakeup time. */
Tcl_Time vdelay; /* Time to sleep, for scaling virtual ->
* real. */
DWORD sleepTime; /* Time to sleep, real-time */
vdelay.sec = ms / 1000;
vdelay.usec = (ms % 1000) * 1000;
Tcl_GetTime(&now);
desired.sec = now.sec + vdelay.sec;
desired.usec = now.usec + vdelay.usec;
if (desired.usec > 1000000) {
++desired.sec;
desired.usec -= 1000000;
}
/*
* TIP #233: Scale delay from virtual to real-time.
*/
TclScaleTime(&vdelay);
sleepTime = (DWORD)vdelay.sec * 1000 + (unsigned long)vdelay.usec / 1000;
for (;;) {
SleepEx(sleepTime, TRUE);
Tcl_GetTime(&now);
if (now.sec > desired.sec) {
break;
} else if ((now.sec == desired.sec) && (now.usec >= desired.usec)) {
break;
}
vdelay.sec = desired.sec - now.sec;
vdelay.usec = desired.usec - now.usec;
TclScaleTime(&vdelay);
sleepTime = (DWORD)vdelay.sec * 1000 + (unsigned long)vdelay.usec / 1000;
}
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to win/tclWinPanic.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* * tclWinPanic.c -- * * Contains the Windows-specific command-line panic proc. * * Copyright © 2013 Jan Nijtmans. * All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* * tclWinPanic.c -- * * Contains the Windows-specific command-line panic proc. * * Copyright © 2013 Jan Nijtmans. * All rights reserved. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclInt.h" /* *---------------------------------------------------------------------- * * Tcl_ConsolePanic -- * * Display a message. If a debugger is present, present it directly to * the debugger, otherwise send it to stderr. |
| ︙ | ︙ | |||
60 61 62 63 64 65 66 |
WriteConsoleW(handle, msgString, (DWORD)wcslen(msgString), &dummy, 0);
} else {
buf[0] = '\xEF'; buf[1] = '\xBB'; buf[2] = '\xBF'; /* UTF-8 bom */
WriteFile(handle, buf, (DWORD)strlen(buf), &dummy, 0);
WriteFile(handle, "\n", 1, &dummy, 0);
FlushFileBuffers(handle);
}
| < < < < | | | | | | | | | < < < < | | | < | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
WriteConsoleW(handle, msgString, (DWORD)wcslen(msgString), &dummy, 0);
} else {
buf[0] = '\xEF'; buf[1] = '\xBB'; buf[2] = '\xBF'; /* UTF-8 bom */
WriteFile(handle, buf, (DWORD)strlen(buf), &dummy, 0);
WriteFile(handle, "\n", 1, &dummy, 0);
FlushFileBuffers(handle);
}
# if defined(__GNUC__)
__builtin_trap();
# elif defined(_WIN64)
__debugbreak();
# elif defined(_MSC_VER)
_asm {int 3}
# else
DebugBreak();
# endif
#if defined(_WIN32)
ExitProcess(1);
#else
abort();
#endif
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* tab-width: 8
* End:
*/
|
Changes to win/tclWinPipe.c.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 33 34 35 36 37 | * The pipeMutex locks around access to the initialized and procList * variables, and it is used to protect background threads from being * terminated while they are using APIs that hold locks. */ TCL_DECLARE_MUTEX(pipeMutex) /* * The following constants and structures are used to encapsulate the state of * various types of files used in a pipeline. This used to have a 1 && 2 that * supported Win32s. */ | > > > > > > > > > > | | < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
* The pipeMutex locks around access to the initialized and procList
* variables, and it is used to protect background threads from being
* terminated while they are using APIs that hold locks.
*/
TCL_DECLARE_MUTEX(pipeMutex)
/*
* The following defines identify the various types of applications that run
* under windows. There is special case code for the various types.
*/
#define APPL_NONE 0
#define APPL_DOS 1
#define APPL_WIN3X 2
#define APPL_WIN32 3
/*
* The following constants and structures are used to encapsulate the state of
* various types of files used in a pipeline. This used to have a 1 && 2 that
* supported Win32s.
*/
#define WIN_FILE 3 /* Basic Win32 file. */
/*
* This structure encapsulates the common state associated with all file types
* used in a pipeline.
*/
typedef struct {
|
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
int dwProcessId;
struct ProcInfo *nextPtr;
} ProcInfo;
static ProcInfo *procList;
/*
| | | | | > > > > > | | < | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
int dwProcessId;
struct ProcInfo *nextPtr;
} ProcInfo;
static ProcInfo *procList;
/*
* Bit masks used in the flags field of the PipeInfo structure below.
*/
#define PIPE_PENDING (1<<0) /* Message is pending in the queue. */
#define PIPE_ASYNC (1<<1) /* Channel is non-blocking. */
/*
* Bit masks used in the sharedFlags field of the PipeInfo structure below.
*/
#define PIPE_EOF (1<<2) /* Pipe has reached EOF. */
#define PIPE_EXTRABYTE (1<<3) /* The reader thread has consumed one byte. */
/*
* TODO: It appears the whole EXTRABYTE machinery is in place to support
* outdated Win 95 systems. If this can be confirmed, much code can be
* deleted.
*/
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
* synchronized with the writable object. */
int writeBufLen; /* Size of write buffer. Access is
* synchronized with the writable object. */
int toWrite; /* Current amount to be written. Access is
* synchronized with the writable object. */
int readFlags; /* Flags that are shared with the reader
* thread. Access is synchronized with the
| | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
* synchronized with the writable object. */
int writeBufLen; /* Size of write buffer. Access is
* synchronized with the writable object. */
int toWrite; /* Current amount to be written. Access is
* synchronized with the writable object. */
int readFlags; /* Flags that are shared with the reader
* thread. Access is synchronized with the
* readable object. */
char extraByte; /* Buffer for extra character consumed by
* reader thread. This byte is shared with the
* reader thread so access must be
* synchronized with the readable object. */
} PipeInfo;
typedef struct {
|
| ︙ | ︙ | |||
155 156 157 158 159 160 161 | * pointer. */ } PipeEvent; /* * Declarations for functions used only in this file. */ | | | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | * pointer. */ } PipeEvent; /* * Declarations for functions used only in this file. */ static int ApplicationType(Tcl_Interp *interp, const char *fileName, char *fullName); static void BuildCommandLine(const char *executable, size_t argc, const char **argv, Tcl_DString *linePtr); static BOOL HasConsole(void); static int PipeBlockModeProc(void *instanceData, int mode); static void PipeCheckProc(void *clientData, int flags); static int PipeClose2Proc(void *instanceData, Tcl_Interp *interp, int flags); |
| ︙ | ︙ | |||
294 295 296 297 298 299 300 | * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ | | > | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
*
* Side effects:
* Adjusts the block time if needed.
*
*----------------------------------------------------------------------
*/
void
PipeSetupProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
PipeInfo *infoPtr;
Tcl_Time blockTime = { 0, 0 };
int block = 1;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!(flags & TCL_FILE_EVENTS)) {
return;
}
|
| ︙ | ︙ | |||
325 326 327 328 329 330 331 |
if (infoPtr->watchMask & TCL_READABLE) {
if (WaitForRead(infoPtr, 0) >= 0) {
block = 0;
}
}
}
if (!block) {
| | | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
if (infoPtr->watchMask & TCL_READABLE) {
if (WaitForRead(infoPtr, 0) >= 0) {
block = 0;
}
}
}
if (!block) {
Tcl_SetMaxBlockTime(&blockTime);
}
}
/*
*----------------------------------------------------------------------
*
* PipeCheckProc --
|
| ︙ | ︙ | |||
656 657 658 659 660 661 662 |
}
/*
* Write the file out, doing line translations on the way.
*/
if (contents != NULL) {
| | < | | < | | | | 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 |
}
/*
* Write the file out, doing line translations on the way.
*/
if (contents != NULL) {
DWORD result, length;
const char *p;
int toCopy;
/*
* Convert the contents from UTF to native encoding
*/
if (Tcl_UtfToExternalDStringEx(NULL, NULL, contents, TCL_INDEX_NONE, 0, &dstring, NULL) != TCL_OK) {
goto error;
}
native = Tcl_DStringValue(&dstring);
toCopy = Tcl_DStringLength(&dstring);
for (p = native; toCopy > 0; p++, toCopy--) {
if (*p == '\n') {
length = p - native;
if (length > 0) {
if (!WriteFile(handle, native, length, &result, NULL)) {
goto error;
}
}
if (!WriteFile(handle, "\r\n", 2, &result, NULL)) {
goto error;
}
native = p+1;
}
}
length = p - native;
if (length > 0) {
if (!WriteFile(handle, native, length, &result, NULL)) {
goto error;
}
}
Tcl_DStringFree(&dstring);
if (SetFilePointer(handle, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF) {
goto error;
}
|
| ︙ | ︙ | |||
725 726 727 728 729 730 731 | *---------------------------------------------------------------------- * * TclpTempFileName -- * * This function returns a unique filename. * * Results: | | | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | *---------------------------------------------------------------------- * * TclpTempFileName -- * * This function returns a unique filename. * * Results: * Returns a valid Tcl_Obj* with refCount 0, or NULL on failure. * * Side effects: * None. * *---------------------------------------------------------------------- */ |
| ︙ | ︙ | |||
903 904 905 906 907 908 909 |
int
TclpCreateProcess(
Tcl_Interp *interp, /* Interpreter in which to leave errors that
* occurred when creating the child process.
* Error messages from the child process
* itself are sent to errorFile. */
| | | 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 |
int
TclpCreateProcess(
Tcl_Interp *interp, /* Interpreter in which to leave errors that
* occurred when creating the child process.
* Error messages from the child process
* itself are sent to errorFile. */
size_t argc, /* Number of arguments in following array. */
const char **argv, /* Array of argument strings. argv[0] contains
* the name of the executable converted to
* native format (using the
* Tcl_TranslateFileName call). Additional
* arguments have not been converted. */
TclFile inputFile, /* If non-NULL, gives the file to use as input
* for the child process. If inputFile file is
|
| ︙ | ︙ | |||
933 934 935 936 937 938 939 |
{
int result, applType, createFlags;
Tcl_DString cmdLine; /* Complete command line (WCHAR). */
STARTUPINFOW startInfo;
PROCESS_INFORMATION procInfo;
SECURITY_ATTRIBUTES secAtts;
HANDLE hProcess, h, inputHandle, outputHandle, errorHandle;
| | | < < | < | | | | 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 |
{
int result, applType, createFlags;
Tcl_DString cmdLine; /* Complete command line (WCHAR). */
STARTUPINFOW startInfo;
PROCESS_INFORMATION procInfo;
SECURITY_ATTRIBUTES secAtts;
HANDLE hProcess, h, inputHandle, outputHandle, errorHandle;
char execPath[MAX_PATH * 3];
WinFile *filePtr;
PipeInit();
applType = ApplicationType(interp, argv[0], execPath);
if (applType == APPL_NONE) {
return TCL_ERROR;
}
result = TCL_ERROR;
Tcl_DStringInit(&cmdLine);
hProcess = GetCurrentProcess();
/*
* STARTF_USESTDHANDLES must be used to pass handles to child process.
* Using SetStdHandle() and/or dup2() only works when a console mode
* parent process is spawning an attached console mode child process.
*/
ZeroMemory(&startInfo, sizeof(startInfo));
startInfo.cb = sizeof(startInfo);
startInfo.dwFlags = STARTF_USESTDHANDLES;
startInfo.hStdInput = INVALID_HANDLE_VALUE;
startInfo.hStdOutput= INVALID_HANDLE_VALUE;
startInfo.hStdError = INVALID_HANDLE_VALUE;
secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
secAtts.lpSecurityDescriptor = NULL;
secAtts.bInheritHandle = TRUE;
/*
|
| ︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 |
* slashes only as option delimiters and backslashes only as paths.
*
* Additionally, when calling a 16-bit dos or windows application, all
* path names must use the short, cryptic, path format (e.g., using
* ab~1.def instead of "a b.default").
*/
| | | 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 |
* slashes only as option delimiters and backslashes only as paths.
*
* Additionally, when calling a 16-bit dos or windows application, all
* path names must use the short, cryptic, path format (e.g., using
* ab~1.def instead of "a b.default").
*/
BuildCommandLine(execPath, argc, argv, &cmdLine);
if (CreateProcessW(NULL, (WCHAR *) Tcl_DStringValue(&cmdLine),
NULL, NULL, TRUE, (DWORD) createFlags, NULL, NULL, &startInfo,
&procInfo) == 0) {
Tcl_WinConvertError(GetLastError());
Tcl_SetObjResult(interp, Tcl_ObjPrintf("couldn't execute \"%s\": %s",
argv[0], Tcl_PosixError(interp)));
|
| ︙ | ︙ | |||
1165 1166 1167 1168 1169 1170 1171 |
*pidPtr = (Tcl_Pid)INT2PTR(procInfo.dwProcessId);
if (*pidPtr != 0) {
TclWinAddProcess(procInfo.hProcess, procInfo.dwProcessId);
}
result = TCL_OK;
end:
| < | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 |
*pidPtr = (Tcl_Pid)INT2PTR(procInfo.dwProcessId);
if (*pidPtr != 0) {
TclWinAddProcess(procInfo.hProcess, procInfo.dwProcessId);
}
result = TCL_OK;
end:
Tcl_DStringFree(&cmdLine);
if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
CloseHandle(startInfo.hStdInput);
}
if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
CloseHandle(startInfo.hStdOutput);
}
|
| ︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 1217 1218 |
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
return TRUE;
} else {
return FALSE;
}
}
/*
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | < < | < > < < < > > | > > | < > | | < | > | > > > > > > | > > | | < < < > | | < < > > | | | < > | | | | < < < < < < < < | < < < < > | < > | | < | < < < | < < < < > > > | | > > > | < < < < < < < > > > | < < < < < < < < < < < < < < < < | < | > > > | | < | | < < | < > > > > > > > > > < < < < < < < < | | < < < < < < | < < < | | < < < < < > > > > > > < | < < | < < | < < < < < > | | > | | | < < < < | < < > > | | | | | | > < > < < | | < < | < < < < < | < < < < | < < < < > > > > > < > | > > | < < < < < < < < < < < < < < < < < < | < < < < | < < < | | < < > < | < | < | < | > | | < | | | | | < < < < < < | 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 |
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
return TRUE;
} else {
return FALSE;
}
}
/*
*--------------------------------------------------------------------
*
* ApplicationType --
*
* Search for the specified program and identify if it refers to a DOS,
* Windows 3.X, or Win32 program. Used to determine how to invoke a
* program, or if it can even be invoked.
*
* It is possible to almost positively identify DOS and Windows
* applications that contain the appropriate magic numbers. However, DOS
* .com files do not seem to contain a magic number; if the program name
* ends with .com and could not be identified as a Windows .com file, it
* will be assumed to be a DOS application, even if it was just random
* data. If the program name does not end with .com, no such assumption
* is made.
*
* The Win32 function GetBinaryType incorrectly identifies any junk file
* that ends with .exe as a dos executable and some executables that
* don't end with .exe as not executable. Plus it doesn't exist under
* win95, so I won't feel bad about reimplementing functionality.
*
* Results:
* The return value is one of APPL_DOS, APPL_WIN3X, or APPL_WIN32 if the
* filename referred to the corresponding application type. If the file
* name could not be found or did not refer to any known application
* type, APPL_NONE is returned and an error message is left in interp.
* .bat files are identified as APPL_DOS.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
ApplicationType(
Tcl_Interp *interp, /* Interp, for error message. */
const char *originalName, /* Name of the application to find. */
char fullName[]) /* Filled with complete path to
* application. */
{
int applType, i, nameLen, found;
HANDLE hFile;
WCHAR *rest;
char *ext;
char buf[2];
DWORD attr, read;
IMAGE_DOS_HEADER header;
Tcl_DString nameBuf, ds;
const WCHAR *nativeName;
WCHAR nativeFullPath[MAX_PATH];
static const char extensions[][5] = {"", ".com", ".exe", ".bat", ".cmd"};
/*
* Look for the program as an external program. First try the name as it
* is, then try adding .com, .exe, .bat and .cmd, in that order, to the name,
* looking for an executable.
*
* Using the raw SearchPathW() function doesn't do quite what is necessary.
* If the name of the executable already contains a '.' character, it will
* not try appending the specified extension when searching (in other
* words, SearchPath will not find the program "a.b.exe" if the arguments
* specified "a.b" and ".exe"). So, first look for the file as it is
* named. Then manually append the extensions, looking for a match.
*/
applType = APPL_NONE;
Tcl_DStringInit(&nameBuf);
Tcl_DStringAppend(&nameBuf, originalName, TCL_INDEX_NONE);
nameLen = Tcl_DStringLength(&nameBuf);
for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
Tcl_DStringSetLength(&nameBuf, nameLen);
Tcl_DStringAppend(&nameBuf, extensions[i], TCL_INDEX_NONE);
Tcl_DStringInit(&ds);
nativeName = Tcl_UtfToWCharDString(Tcl_DStringValue(&nameBuf),
Tcl_DStringLength(&nameBuf), &ds);
found = SearchPathW(NULL, nativeName, NULL, MAX_PATH,
nativeFullPath, &rest);
Tcl_DStringFree(&ds);
if (found == 0) {
continue;
}
/*
* Ignore matches on directories or data files, return if identified a
* known type.
*/
attr = GetFileAttributesW(nativeFullPath);
if ((attr == 0xFFFFFFFF) || (attr & FILE_ATTRIBUTE_DIRECTORY)) {
continue;
}
Tcl_DStringInit(&ds);
strcpy(fullName, Tcl_WCharToUtfDString(nativeFullPath, TCL_INDEX_NONE, &ds));
Tcl_DStringFree(&ds);
ext = strrchr(fullName, '.');
if ((ext != NULL) &&
(strcasecmp(ext, ".cmd") == 0 || strcasecmp(ext, ".bat") == 0)) {
applType = APPL_DOS;
break;
}
hFile = CreateFileW(nativeFullPath,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
continue;
}
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
/*
* But [4f0b5767ac]. Likely a App Execution Alias. This can only
* be a Win32 APP. Attempt to ReadFile below will fail. We assume
* that if it is on the PATH, and it is a reparse point, it is an
* App Execution Alias.
*/
CloseHandle(hFile);
applType = APPL_WIN32;
break;
}
header.e_magic = 0;
ReadFile(hFile, (void *)&header, sizeof(header), &read, NULL);
if (header.e_magic != IMAGE_DOS_SIGNATURE) {
/*
* Doesn't have the magic number for relocatable executables. If
* filename ends with .com, assume it's a DOS application anyhow.
* Note that we didn't make this assumption at first, because some
* supposed .com files are really 32-bit executables with all the
* magic numbers and everything.
*/
CloseHandle(hFile);
if ((ext != NULL) && (strcasecmp(ext, ".com") == 0)) {
applType = APPL_DOS;
break;
}
continue;
}
if (header.e_lfarlc != sizeof(header)) {
/*
* All Windows 3.X and Win32 and some DOS programs have this value
* set here. If it doesn't, assume that since it already had the
* other magic number it was a DOS application.
*/
CloseHandle(hFile);
applType = APPL_DOS;
break;
}
/*
* The DWORD at header.e_lfanew points to yet another magic number.
*/
buf[0] = '\0';
SetFilePointer(hFile, header.e_lfanew, NULL, FILE_BEGIN);
ReadFile(hFile, (void *)buf, 2, &read, NULL);
CloseHandle(hFile);
if ((buf[0] == 'N') && (buf[1] == 'E')) {
applType = APPL_WIN3X;
} else if ((buf[0] == 'P') && (buf[1] == 'E')) {
applType = APPL_WIN32;
} else {
/*
* Strictly speaking, there should be a test that there is an 'L'
* and 'E' at buf[0..1], to identify the type as DOS, but of
* course we ran into a DOS executable that _doesn't_ have the
* magic number - specifically, one compiled using the Lahey
* Fortran90 compiler.
*/
applType = APPL_DOS;
}
break;
}
Tcl_DStringFree(&nameBuf);
if (applType == APPL_NONE) {
Tcl_WinConvertError(GetLastError());
Tcl_SetObjResult(interp, Tcl_ObjPrintf("couldn't execute \"%s\": %s",
originalName, Tcl_PosixError(interp)));
return APPL_NONE;
}
if (applType == APPL_WIN3X) {
/*
* Replace long path name of executable with short path name for
* 16-bit applications. Otherwise the application may not be able to
* correctly parse its own command line to separate off the
* application name from the arguments.
*/
GetShortPathNameW(nativeFullPath, nativeFullPath, MAX_PATH);
Tcl_DStringInit(&ds);
strcpy(fullName, Tcl_WCharToUtfDString(nativeFullPath, TCL_INDEX_NONE, &ds));
Tcl_DStringFree(&ds);
}
return applType;
}
/*
*----------------------------------------------------------------------
*
* BuildCommandLine --
|
| ︙ | ︙ | |||
1775 1776 1777 1778 1779 1780 1781 |
return special;
}
static void
BuildCommandLine(
const char *executable, /* Full path of executable (including
* extension). Replacement for argv[0]. */
| | | 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 |
return special;
}
static void
BuildCommandLine(
const char *executable, /* Full path of executable (including
* extension). Replacement for argv[0]. */
size_t argc, /* Number of arguments. */
const char **argv, /* Argument strings in UTF. */
Tcl_DString *linePtr) /* Initialized Tcl_DString that receives the
* command line (WCHAR). */
{
const char *arg, *start, *special, *bspos;
int quote = 0;
size_t i;
|
| ︙ | ︙ | |||
2040 2041 2042 2043 2044 2045 2046 |
if (readFile != NULL) {
/*
* Start the background reader thread.
*/
infoPtr->readable = CreateEventW(NULL, TRUE, TRUE, NULL);
infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
| | | | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 |
if (readFile != NULL) {
/*
* Start the background reader thread.
*/
infoPtr->readable = CreateEventW(NULL, TRUE, TRUE, NULL);
infoPtr->readThread = CreateThread(NULL, 256, PipeReaderThread,
TclPipeThreadCreateTI(&infoPtr->readTI, infoPtr), 0, NULL);
SetThreadPriority(infoPtr->readThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_READABLE;
} else {
infoPtr->readTI = NULL;
infoPtr->readThread = 0;
}
if (writeFile != NULL) {
/*
* Start the background writer thread.
*/
infoPtr->writable = CreateEventW(NULL, TRUE, TRUE, NULL);
infoPtr->writeThread = CreateThread(NULL, 256, PipeWriterThread,
TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr), 0, NULL);
SetThreadPriority(infoPtr->writeThread, THREAD_PRIORITY_HIGHEST);
infoPtr->validMask |= TCL_WRITABLE;
} else {
infoPtr->writeTI = NULL;
infoPtr->writeThread = 0;
}
|
| ︙ | ︙ | |||
2190 2191 2192 2193 2194 2195 2196 | * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */ static int PipeBlockModeProc( | | | 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 |
* Sets the device into blocking or non-blocking mode.
*
*----------------------------------------------------------------------
*/
static int
PipeBlockModeProc(
void *instanceData, /* Instance data for channel. */
int mode) /* TCL_MODE_BLOCKING or
* TCL_MODE_NONBLOCKING. */
{
PipeInfo *infoPtr = (PipeInfo *) instanceData;
/*
* Pipes on Windows can not be switched between blocking and nonblocking,
|
| ︙ | ︙ | |||
2229 2230 2231 2232 2233 2234 2235 | * Closes the physical channel. * *---------------------------------------------------------------------- */ static int PipeClose2Proc( | | | > > > > > > | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 |
* Closes the physical channel.
*
*----------------------------------------------------------------------
*/
static int
PipeClose2Proc(
void *instanceData, /* Pointer to PipeInfo structure. */
Tcl_Interp *interp, /* For error reporting. */
int flags) /* Flags that indicate which side to close. */
{
PipeInfo *pipePtr = (PipeInfo *) instanceData;
Tcl_Channel errChan;
int errorCode, result;
PipeInfo *infoPtr, **nextPtrPtr;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int inExit = (TclInExit() || TclInThreadExit());
errorCode = 0;
result = 0;
if ((!flags || flags & TCL_CLOSE_READ) && (pipePtr->readFile != NULL)) {
/*
* Clean up the background thread if necessary. Note that this must be
* done before we can close the file, since the thread may be blocking
* trying to read from the pipe.
*/
if (pipePtr->readThread) {
TclPipeThreadStop(&pipePtr->readTI, pipePtr->readThread);
CloseHandle(pipePtr->readThread);
CloseHandle(pipePtr->readable);
pipePtr->readThread = NULL;
}
if (TclpCloseFile(pipePtr->readFile) != 0) {
errorCode = errno;
}
pipePtr->validMask &= ~TCL_READABLE;
pipePtr->readFile = NULL;
}
if ((!flags || flags & TCL_CLOSE_WRITE) && (pipePtr->writeFile != NULL)) {
if (pipePtr->writeThread) {
/*
* Wait for the writer thread to finish the current buffer, then
* terminate the thread and close the handles. If the channel is
* nonblocking or may block during exit, bail out since the worker
* thread is not interruptible and we want TIP#398-fast-exit.
*/
if ((pipePtr->flags & PIPE_ASYNC) && inExit) {
/* give it a chance to leave honorably */
TclPipeThreadStopSignal(&pipePtr->writeTI);
if (WaitForSingleObject(pipePtr->writable, 20) == WAIT_TIMEOUT) {
return EWOULDBLOCK;
}
} else {
WaitForSingleObject(pipePtr->writable, inExit ? 5000 : INFINITE);
}
TclPipeThreadStop(&pipePtr->writeTI, pipePtr->writeThread);
CloseHandle(pipePtr->writable);
CloseHandle(pipePtr->writeThread);
pipePtr->writeThread = NULL;
|
| ︙ | ︙ | |||
2394 2395 2396 2397 2398 2399 2400 | * Reads input from the actual channel. * *---------------------------------------------------------------------- */ static int PipeInputProc( | | | 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 |
* Reads input from the actual channel.
*
*----------------------------------------------------------------------
*/
static int
PipeInputProc(
void *instanceData, /* Pipe state. */
char *buf, /* Where to store data read. */
int bufSize, /* How much space is available in the
* buffer? */
int *errorCode) /* Where to store error code. */
{
PipeInfo *infoPtr = (PipeInfo *) instanceData;
WinFile *filePtr = (WinFile*) infoPtr->readFile;
|
| ︙ | ︙ | |||
2488 2489 2490 2491 2492 2493 2494 | * Writes output on the actual channel. * *---------------------------------------------------------------------- */ static int PipeOutputProc( | | | 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 |
* Writes output on the actual channel.
*
*----------------------------------------------------------------------
*/
static int
PipeOutputProc(
void *instanceData, /* Pipe state. */
const char *buf, /* The data buffer. */
int toWrite, /* How many bytes to write? */
int *errorCode) /* Where to store error code. */
{
PipeInfo *infoPtr = (PipeInfo *) instanceData;
WinFile *filePtr = (WinFile*) infoPtr->writeFile;
DWORD bytesWritten, timeout;
|
| ︙ | ︙ | |||
2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 |
}
}
return bytesWritten;
error:
*errorCode = errno;
return -1;
}
/*
*----------------------------------------------------------------------
*
* PipeEventProc --
*
| > | 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 |
}
}
return bytesWritten;
error:
*errorCode = errno;
return -1;
}
/*
*----------------------------------------------------------------------
*
* PipeEventProc --
*
|
| ︙ | ︙ | |||
2669 2670 2671 2672 2673 2674 2675 | * None. * *---------------------------------------------------------------------- */ static void PipeWatchProc( | | > | | 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 |
* None.
*
*----------------------------------------------------------------------
*/
static void
PipeWatchProc(
void *instanceData, /* Pipe state. */
int mask) /* What events to watch for, OR-ed combination
* of TCL_READABLE, TCL_WRITABLE and
* TCL_EXCEPTION. */
{
PipeInfo **nextPtrPtr, *ptr;
PipeInfo *infoPtr = (PipeInfo *) instanceData;
int oldMask = infoPtr->watchMask;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* Since most of the work is handled by the background threads, we just
* need to update the watchMask and then force the notifier to poll once.
*/
infoPtr->watchMask = mask & infoPtr->validMask;
if (infoPtr->watchMask) {
Tcl_Time blockTime = { 0, 0 };
if (!oldMask) {
infoPtr->nextPtr = tsdPtr->firstPipePtr;
tsdPtr->firstPipePtr = infoPtr;
}
Tcl_SetMaxBlockTime(&blockTime);
} else {
if (oldMask) {
/*
* Remove the pipe from the list of watched pipes.
*/
for (nextPtrPtr = &(tsdPtr->firstPipePtr), ptr = *nextPtrPtr;
|
| ︙ | ︙ | |||
2730 2731 2732 2733 2734 2735 2736 | * None. * *---------------------------------------------------------------------- */ static int PipeGetHandleProc( | | | | 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 |
* None.
*
*----------------------------------------------------------------------
*/
static int
PipeGetHandleProc(
void *instanceData, /* The pipe state. */
int direction, /* TCL_READABLE or TCL_WRITABLE */
void **handlePtr) /* Where to store the handle. */
{
PipeInfo *infoPtr = (PipeInfo *) instanceData;
WinFile *filePtr;
if (direction == TCL_READABLE && infoPtr->readFile) {
filePtr = (WinFile*) infoPtr->readFile;
*handlePtr = (void *)filePtr->handle;
|
| ︙ | ︙ | |||
2798 2799 2800 2801 2802 2803 2804 |
* Find the process and cut it from the process list.
*/
Tcl_MutexLock(&pipeMutex);
prevPtrPtr = &procList;
for (infoPtr = procList; infoPtr != NULL;
prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) {
| | | 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 |
* Find the process and cut it from the process list.
*/
Tcl_MutexLock(&pipeMutex);
prevPtrPtr = &procList;
for (infoPtr = procList; infoPtr != NULL;
prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) {
if (infoPtr->dwProcessId == (Tcl_Size)pid) {
*prevPtrPtr = infoPtr->nextPtr;
break;
}
}
Tcl_MutexUnlock(&pipeMutex);
/*
|
| ︙ | ︙ | |||
2949 2950 2951 2952 2953 2954 2955 |
Tcl_Size id) /* Global process identifier */
{
ProcInfo *procPtr = (ProcInfo *)Tcl_Alloc(sizeof(ProcInfo));
PipeInit();
procPtr->hProcess = hProcess;
| | | 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 |
Tcl_Size id) /* Global process identifier */
{
ProcInfo *procPtr = (ProcInfo *)Tcl_Alloc(sizeof(ProcInfo));
PipeInit();
procPtr->hProcess = hProcess;
procPtr->dwProcessId = id;
Tcl_MutexLock(&pipeMutex);
procPtr->nextPtr = procList;
procList = procPtr;
Tcl_MutexUnlock(&pipeMutex);
}
/*
|
| ︙ | ︙ | |||
2977 2978 2979 2980 2981 2982 2983 |
*----------------------------------------------------------------------
*/
int
Tcl_PidObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 |
*----------------------------------------------------------------------
*/
int
Tcl_PidObjCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const *objv) /* Argument strings. */
{
Tcl_Channel chan;
const Tcl_ChannelType *chanTypePtr;
PipeInfo *pipePtr;
size_t i;
Tcl_Obj *resultPtr;
|
| ︙ | ︙ | |||
3156 3157 3158 3159 3160 3161 3162 |
*/
static DWORD WINAPI
PipeReaderThread(
LPVOID arg)
{
TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *) arg;
| | | 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 |
*/
static DWORD WINAPI
PipeReaderThread(
LPVOID arg)
{
TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *) arg;
PipeInfo *infoPtr = NULL; /* access info only after success init/wait */
HANDLE handle = NULL;
DWORD count, err;
int done = 0;
while (!done) {
/*
* Wait for the main thread to signal before attempting to wait on the
|
| ︙ | ︙ | |||
3279 3280 3281 3282 3283 3284 3285 |
*/
static DWORD WINAPI
PipeWriterThread(
LPVOID arg)
{
TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *)arg;
| | | 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 |
*/
static DWORD WINAPI
PipeWriterThread(
LPVOID arg)
{
TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *)arg;
PipeInfo *infoPtr = NULL; /* access info only after success init/wait */
HANDLE handle = NULL;
DWORD count, toWrite;
char *buf;
int done = 0;
while (!done) {
/*
|
| ︙ | ︙ | |||
3459 3460 3461 3462 3463 3464 3465 |
} else {
const WCHAR *baseStr = L"TCL";
length = 3 * sizeof(WCHAR);
memcpy(namePtr, baseStr, length);
namePtr += length;
}
| | | 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 |
} else {
const WCHAR *baseStr = L"TCL";
length = 3 * sizeof(WCHAR);
memcpy(namePtr, baseStr, length);
namePtr += length;
}
counter = TclpGetClicks() % 65533;
counter2 = 1024; /* Only try this many times! Prevents
* an infinite loop. */
do {
char number[TCL_INTEGER_SPACE + 4];
snprintf(number, sizeof(number), "%d.TMP", counter);
|
| ︙ | ︙ | |||
3782 3783 3784 3785 3786 3787 3788 |
* The thread may already have closed on its own. Check its exit
* code.
*/
GetExitCodeThread(hThread, &exitCode);
if (exitCode == STILL_ACTIVE) {
| | | 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 |
* The thread may already have closed on its own. Check its exit
* code.
*/
GetExitCodeThread(hThread, &exitCode);
if (exitCode == STILL_ACTIVE) {
int inExit = (TclInExit() || TclInThreadExit());
/*
* Set the stop event so that if the pipe thread is blocked
* somewhere, it may hereafter sane exit cleanly.
*/
SetEvent(evControl);
|
| ︙ | ︙ |
Changes to win/tclWinPort.h.
1 2 3 4 5 6 7 | /* * tclWinPort.h -- * * This header file handles porting issues that occur because of * differences between Windows and Unix. It should be the only * file that contains #ifdefs to handle different flavors of OS. * | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | /* * tclWinPort.h -- * * This header file handles porting issues that occur because of * differences between Windows and Unix. It should be the only * file that contains #ifdefs to handle different flavors of OS. * * Copyright (c) 1994-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef _TCLWINPORT #define _TCLWINPORT #if !defined(_WIN64) && !defined(__MINGW_USE_VC2005_COMPAT) /* See [Bug 3354324]: file mtime sets wrong time */ # define __MINGW_USE_VC2005_COMPAT #endif #if defined(_MSC_VER) && defined(_WIN64) && !defined(STATIC_BUILD) \ && !defined(MP_32BIT) && !defined(MP_64BIT) # define MP_64BIT #endif /* * We must specify the lower version we intend to support. * * WINVER = 0x0601 means Windows 7 and above */ #ifndef WINVER # define WINVER 0x0601 #endif #ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0601 #endif #define WIN32_LEAN_AND_MEAN #include <windows.h> #undef WIN32_LEAN_AND_MEAN /* Compatibility to older visual studio / windows platform SDK */ |
| ︙ | ︙ | |||
55 56 57 58 59 60 61 | #include <winsock2.h> #include <ws2tcpip.h> #ifdef HAVE_WSPIAPI_H # include <wspiapi.h> #endif /* | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
#include <winsock2.h>
#include <ws2tcpip.h>
#ifdef HAVE_WSPIAPI_H
# include <wspiapi.h>
#endif
/*
* Pull in the typedef of TCHAR for windows.
*/
#include <tchar.h>
#ifndef _TCHAR_DEFINED
/* Borland seems to forget to set this. */
typedef _TCHAR TCHAR;
# define _TCHAR_DEFINED
#endif
|
| ︙ | ︙ | |||
350 351 352 353 354 355 356 | /* * Define macros to query file type bits, if they're not already * defined. */ #ifndef S_IFLNK | | | 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | /* * Define macros to query file type bits, if they're not already * defined. */ #ifndef S_IFLNK # define S_IFLNK 0120000 /* Symbolic Link */ #endif /* * Windows compilers do not define S_IFBLK. However, Tcl uses it in * GetTypeFromMode to identify blockSpecial devices based on the * value in the statsbuf st_mode field. We have no other way to pass this * from NativeStat on Windows so are forced to define it here. |
| ︙ | ︙ | |||
509 510 511 512 513 514 515 | #endif /* * The following defines wrap the system memory allocation routines for * use by tclAlloc.c. */ | | | | | | | | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | #endif /* * The following defines wrap the system memory allocation routines for * use by tclAlloc.c. */ #define TclpSysAlloc(size) ((void*)HeapAlloc(GetProcessHeap(), \ 0, size)) #define TclpSysFree(ptr) (HeapFree(GetProcessHeap(), \ 0, (HGLOBAL)ptr)) #define TclpSysRealloc(ptr, size) ((void*)HeapReAlloc(GetProcessHeap(), \ 0, (LPVOID)ptr, size)) /* This type is not defined in the Windows headers */ #define socklen_t int /* * The following macros have trivial definitions, allowing generic code to * address platform-specific issues. |
| ︙ | ︙ |
Changes to win/tclWinReg.c.
1 2 3 4 5 6 7 | /* * tclWinReg.c -- * * This file contains the implementation of the "registry" Tcl built-in * command. This command is built as a dynamically loadable extension in * a separate DLL. * | | | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* * tclWinReg.c -- * * This file contains the implementation of the "registry" Tcl built-in * command. This command is built as a dynamically loadable extension in * a separate DLL. * * Copyright (c) 1997 by Sun Microsystems, Inc. * Copyright (c) 1998-1999 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #undef STATIC_BUILD #ifndef USE_TCL_STUBS # define USE_TCL_STUBS #endif #include "tclInt.h" #ifdef _MSC_VER # pragma comment (lib, "advapi32.lib") #endif #include <stdlib.h> #if defined (__clang__) && (__clang_major__ > 20) #pragma clang diagnostic ignored "-Wc++-keyword" #endif |
| ︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
};
static const HKEY rootKeys[] = {
HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER,
HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, HKEY_DYN_DATA
};
/*
* The following table maps from registry types to strings. Note that the
* indices for this array are the same as the constants for the known registry
* types so we don't need a separate table to hold the mapping.
*/
static const char *const typeNames[] = {
"none", "sz", "expand_sz", "binary", "dword",
"dword_big_endian", "link", "multi_sz", "resource_list", NULL
};
static DWORD lastType = REG_RESOURCE_LIST;
/*
* Declarations for functions defined in this file.
*/
static int BroadcastValue(Tcl_Interp *interp, Tcl_Size objc,
| > > > > > > > > > > > > > > > > > > > | > | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
};
static const HKEY rootKeys[] = {
HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER,
HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, HKEY_DYN_DATA
};
static const char REGISTRY_ASSOC_KEY[] = "registry::command";
/*
* The following table maps from registry types to strings. Note that the
* indices for this array are the same as the constants for the known registry
* types so we don't need a separate table to hold the mapping.
*/
static const char *const typeNames[] = {
"none", "sz", "expand_sz", "binary", "dword",
"dword_big_endian", "link", "multi_sz", "resource_list", NULL
};
static DWORD lastType = REG_RESOURCE_LIST;
#if TCL_MAJOR_VERSION < 9
# if TCL_UTF_MAX > 3
# define Tcl_WCharToUtfDString(a,b,c) Tcl_WinTCharToUtf((TCHAR *)(a),(b)*sizeof(WCHAR),c)
# define Tcl_UtfToWCharDString(a,b,c) (WCHAR *)Tcl_WinUtfToTChar(a,b,c)
# else
# define Tcl_WCharToUtfDString(a,b,c) Tcl_UniCharToUtfDString((Tcl_UniChar *)(a),b,c)
# define Tcl_UtfToWCharDString(a,b,c) (WCHAR *)Tcl_UtfToUniCharDString(a,b,c)
# endif
#ifndef Tcl_Size
# define Tcl_Size int
#endif
#ifndef Tcl_CreateObjCommand2
# define Tcl_CreateObjCommand2 Tcl_CreateObjCommand
#endif
#endif
/*
* Declarations for functions defined in this file.
*/
static void AppendSystemError(Tcl_Interp *interp, DWORD error);
static int BroadcastValue(Tcl_Interp *interp, Tcl_Size objc,
Tcl_Obj *const objv[]);
static DWORD ConvertDWORD(DWORD type, DWORD value);
static void DeleteCmd(void *clientData);
static int DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
REGSAM mode);
static int DeleteValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
Tcl_Obj *valueNameObj, REGSAM mode);
static int GetKeyNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
Tcl_Obj *patternObj, REGSAM mode);
static int GetType(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
|
| ︙ | ︙ | |||
111 112 113 114 115 116 117 | static int ParseKeyName(Tcl_Interp *interp, char *name, char **hostNamePtr, HKEY *rootKeyPtr, char **keyNamePtr); static DWORD RecursiveDeleteKey(HKEY hStartKey, const WCHAR * pKeyName, REGSAM mode); static int RegistryObjCmd(void *clientData, Tcl_Interp *interp, Tcl_Size objc, | | > > > > > > > > > > > > > > | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
static int ParseKeyName(Tcl_Interp *interp, char *name,
char **hostNamePtr, HKEY *rootKeyPtr,
char **keyNamePtr);
static DWORD RecursiveDeleteKey(HKEY hStartKey,
const WCHAR * pKeyName, REGSAM mode);
static int RegistryObjCmd(void *clientData,
Tcl_Interp *interp, Tcl_Size objc,
Tcl_Obj *const objv[]);
static int SetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
Tcl_Obj *valueNameObj, Tcl_Obj *dataObj,
Tcl_Obj *typeObj, REGSAM mode);
#ifdef __cplusplus
extern "C" {
#endif
DLLEXPORT int Registry_Init(Tcl_Interp *interp);
DLLEXPORT int Registry_Unload(Tcl_Interp *interp, int flags);
#if TCL_MAJOR_VERSION < 9
/* With those additional entries, "load tclregistry13.dll" works without 3th argument */
DLLEXPORT int Tclregistry_Init(Tcl_Interp *interp);
DLLEXPORT int Tclregistry_Unload(Tcl_Interp *interp, int flags);
#endif
#ifdef __cplusplus
}
#endif
/*
*----------------------------------------------------------------------
*
* Registry_Init --
*
* This function initializes the registry command.
|
| ︙ | ︙ | |||
136 137 138 139 140 141 142 |
*----------------------------------------------------------------------
*/
int
Registry_Init(
Tcl_Interp *interp)
{
| > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
*----------------------------------------------------------------------
*/
int
Registry_Init(
Tcl_Interp *interp)
{
Tcl_Command cmd;
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
return TCL_ERROR;
}
cmd = Tcl_CreateObjCommand2(interp, "registry", RegistryObjCmd,
interp, DeleteCmd);
Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, cmd);
return Tcl_PkgProvideEx(interp, "registry", "1.3.7", NULL);
}
#if TCL_MAJOR_VERSION < 9
int
Tclregistry_Init(
Tcl_Interp *interp)
{
return Registry_Init(interp);
}
#endif
/*
*----------------------------------------------------------------------
*
* Registry_Unload --
*
* This function removes the registry command.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* The registry command is deleted and the dll may be unloaded.
*
*----------------------------------------------------------------------
*/
int
Registry_Unload(
Tcl_Interp *interp, /* Interpreter for unloading */
int flags) /* Flags passed by the unload system */
{
Tcl_Command cmd;
Tcl_Obj *objv[3];
(void)flags;
/*
* Unregister the registry package. There is no Tcl_PkgForget()
*/
objv[0] = Tcl_NewStringObj("package", -1);
objv[1] = Tcl_NewStringObj("forget", -1);
objv[2] = Tcl_NewStringObj("registry", -1);
Tcl_EvalObjv(interp, 3, objv, TCL_EVAL_GLOBAL);
/*
* Delete the originally registered command.
*/
cmd = (Tcl_Command)Tcl_GetAssocData(interp, REGISTRY_ASSOC_KEY, NULL);
if (cmd != NULL) {
Tcl_DeleteCommandFromToken(interp, cmd);
}
return TCL_OK;
}
#if TCL_MAJOR_VERSION < 9
int
Tclregistry_Unload(
Tcl_Interp *interp,
int flags)
{
return Registry_Unload(interp, flags);
}
#endif
/*
*----------------------------------------------------------------------
*
* DeleteCmd --
*
* Cleanup the interp command token so that unloading doesn't try to
* re-delete the command (which will crash).
*
* Results:
* None.
*
* Side effects:
* The unload command will not attempt to delete this command.
*
*----------------------------------------------------------------------
*/
static void
DeleteCmd(
void *clientData)
{
Tcl_Interp *interp = (Tcl_Interp *)clientData;
Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, NULL);
}
/*
*----------------------------------------------------------------------
*
* RegistryObjCmd --
*
* This function implements the Tcl "registry" command.
|
| ︙ | ︙ | |||
162 163 164 165 166 167 168 |
*/
static int
RegistryObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
| | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
*/
static int
RegistryObjCmd(
void *dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument values. */
{
Tcl_Size n = 1, argc;
int index;
REGSAM mode = 0;
const char *errString = NULL;
static const char *const subcommands[] = {
|
| ︙ | ︙ | |||
330 331 332 333 334 335 336 |
if (ParseKeyName(interp, buffer, &hostName, &rootKey,
&keyName) != TCL_OK) {
Tcl_Free(buffer);
return TCL_ERROR;
}
if (*keyName == '\0') {
| | | | | | | | | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 |
if (ParseKeyName(interp, buffer, &hostName, &rootKey,
&keyName) != TCL_OK) {
Tcl_Free(buffer);
return TCL_ERROR;
}
if (*keyName == '\0') {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("bad key: cannot delete root keys", -1));
Tcl_SetErrorCode(interp, "WIN_REG", "DEL_ROOT_KEY", (char *)NULL);
Tcl_Free(buffer);
return TCL_ERROR;
}
tail = strrchr(keyName, '\\');
if (tail) {
*tail++ = '\0';
} else {
tail = keyName;
keyName = NULL;
}
mode |= KEY_ENUMERATE_SUB_KEYS | DELETE;
result = OpenSubKey(hostName, rootKey, keyName, mode, 0, &subkey);
if (result != ERROR_SUCCESS) {
Tcl_Free(buffer);
if (result == ERROR_FILE_NOT_FOUND) {
return TCL_OK;
}
Tcl_SetObjResult(interp,
Tcl_NewStringObj("unable to delete key: ", -1));
AppendSystemError(interp, result);
return TCL_ERROR;
}
/*
* Now we recursively delete the key and everything below it.
*/
Tcl_DStringInit(&buf);
nativeTail = Tcl_UtfToWCharDString(tail, -1, &buf);
result = RecursiveDeleteKey(subkey, nativeTail, saveMode);
Tcl_DStringFree(&buf);
if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("unable to delete key: ", -1));
AppendSystemError(interp, result);
result = TCL_ERROR;
} else {
result = TCL_OK;
}
RegCloseKey(subkey);
Tcl_Free(buffer);
|
| ︙ | ︙ | |||
428 429 430 431 432 433 434 |
Tcl_UtfToWCharDString(valueName, len, &ds);
result = RegDeleteValueW(key, (const WCHAR *)Tcl_DStringValue(&ds));
Tcl_DStringFree(&ds);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to delete value \"%s\" from key \"%s\": ",
Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
| | | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 |
Tcl_UtfToWCharDString(valueName, len, &ds);
result = RegDeleteValueW(key, (const WCHAR *)Tcl_DStringValue(&ds));
Tcl_DStringFree(&ds);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to delete value \"%s\" from key \"%s\": ",
Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
AppendSystemError(interp, result);
result = TCL_ERROR;
} else {
result = TCL_OK;
}
RegCloseKey(key);
return result;
}
|
| ︙ | ︙ | |||
505 506 507 508 509 510 511 |
if (result != ERROR_SUCCESS) {
if (result == ERROR_NO_MORE_ITEMS) {
result = TCL_OK;
} else {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to enumerate subkeys of \"%s\": ",
Tcl_GetString(keyNameObj)));
| | | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 |
if (result != ERROR_SUCCESS) {
if (result == ERROR_NO_MORE_ITEMS) {
result = TCL_OK;
} else {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to enumerate subkeys of \"%s\": ",
Tcl_GetString(keyNameObj)));
AppendSystemError(interp, result);
result = TCL_ERROR;
}
break;
}
Tcl_DStringInit(&ds);
name = Tcl_WCharToUtfDString(buffer, bufSize, &ds);
if (pattern && !Tcl_StringMatch(name, pattern)) {
|
| ︙ | ︙ | |||
589 590 591 592 593 594 595 |
Tcl_DStringFree(&ds);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to get type of value \"%s\" from key \"%s\": ",
Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
| | | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 |
Tcl_DStringFree(&ds);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to get type of value \"%s\" from key \"%s\": ",
Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
AppendSystemError(interp, result);
return TCL_ERROR;
}
/*
* Set the type into the result. Watch out for unknown types. If we don't
* know about the type, just use the numeric value.
*/
|
| ︙ | ︙ | |||
684 685 686 687 688 689 690 |
}
Tcl_DStringFree(&buf);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to get value \"%s\" from key \"%s\": ",
Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
| | | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 |
}
Tcl_DStringFree(&buf);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"unable to get value \"%s\" from key \"%s\": ",
Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
AppendSystemError(interp, result);
Tcl_DStringFree(&data);
return TCL_ERROR;
}
/*
* If the data is a 32-bit quantity, store it as an integer object. If it
* is a multi-string, store it as a list of strings. For null-terminated
|
| ︙ | ︙ | |||
714 715 716 717 718 719 720 |
* we get bogus data.
*/
while ((p < end) && *((WCHAR *) p) != 0) {
WCHAR *wp = (WCHAR *) p;
Tcl_DStringInit(&buf);
| | | < < | | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 |
* we get bogus data.
*/
while ((p < end) && *((WCHAR *) p) != 0) {
WCHAR *wp = (WCHAR *) p;
Tcl_DStringInit(&buf);
Tcl_WCharToUtfDString(wp, wcslen(wp), &buf);
Tcl_ListObjAppendElement(interp, resultPtr,
Tcl_NewStringObj(Tcl_DStringValue(&buf),
Tcl_DStringLength(&buf)));
while (*wp++ != 0); /* empty loop body */
p = (char *) wp;
Tcl_DStringFree(&buf);
}
Tcl_SetObjResult(interp, resultPtr);
} else if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) {
WCHAR *wp = (WCHAR *) Tcl_DStringValue(&data);
Tcl_DStringInit(&buf);
Tcl_WCharToUtfDString((const WCHAR *)Tcl_DStringValue(&data), wcslen(wp), &buf);
Tcl_DStringResult(interp, &buf);
} else {
/*
* Save binary data as a byte array.
*/
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
|
| ︙ | ︙ | |||
865 866 867 868 869 870 871 |
buffer = (char *)Tcl_Alloc(len + 1);
strcpy(buffer, keyName);
result = ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName);
if (result == TCL_OK) {
result = OpenSubKey(hostName, rootKey, keyName, mode, flags, keyPtr);
if (result != ERROR_SUCCESS) {
| | | | | 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 |
buffer = (char *)Tcl_Alloc(len + 1);
strcpy(buffer, keyName);
result = ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName);
if (result == TCL_OK) {
result = OpenSubKey(hostName, rootKey, keyName, mode, flags, keyPtr);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("unable to open key: ", -1));
AppendSystemError(interp, result);
result = TCL_ERROR;
} else {
result = TCL_OK;
}
}
Tcl_Free(buffer);
|
| ︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 |
* encoding, not UTF. */
REGSAM mode) /* Mode flags to pass. */
{
DWORD result, size;
Tcl_DString subkey;
HKEY hKey;
REGSAM saveMode = mode;
/*
* Do not allow NULL or empty key name.
*/
if (!keyName || *keyName == '\0') {
return ERROR_BADKEY;
| > > > > > > | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 |
* encoding, not UTF. */
REGSAM mode) /* Mode flags to pass. */
{
DWORD result, size;
Tcl_DString subkey;
HKEY hKey;
REGSAM saveMode = mode;
static int checkExProc = 0;
typedef LONG (* regDeleteKeyExProc) (HKEY, LPCWSTR, REGSAM, DWORD);
static regDeleteKeyExProc regDeleteKeyEx = (regDeleteKeyExProc) NULL;
/* Really RegDeleteKeyExW() but that's not
* available on all versions of Windows
* supported by Tcl. */
/*
* Do not allow NULL or empty key name.
*/
if (!keyName || *keyName == '\0') {
return ERROR_BADKEY;
|
| ︙ | ︙ | |||
1102 1103 1104 1105 1106 1107 1108 |
* Always get index 0 because key deletion changes ordering.
*/
size = MAX_KEY_LENGTH;
result = RegEnumKeyExW(hKey, 0, (WCHAR *)Tcl_DStringValue(&subkey),
&size, NULL, NULL, NULL, NULL);
if (result == ERROR_NO_MORE_ITEMS) {
| > > > > > > | > > > > > > > > | | 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 |
* Always get index 0 because key deletion changes ordering.
*/
size = MAX_KEY_LENGTH;
result = RegEnumKeyExW(hKey, 0, (WCHAR *)Tcl_DStringValue(&subkey),
&size, NULL, NULL, NULL, NULL);
if (result == ERROR_NO_MORE_ITEMS) {
/*
* RegDeleteKeyEx doesn't exist on non-64bit XP platforms, so we
* can't compile with it in. We need to check for it at runtime
* and use it if we find it.
*/
if (mode && !checkExProc) {
HMODULE handle;
checkExProc = 1;
handle = GetModuleHandleW(L"ADVAPI32");
regDeleteKeyEx = (regDeleteKeyExProc) (void *)
GetProcAddress(handle, "RegDeleteKeyExW");
}
if (mode && regDeleteKeyEx) {
result = regDeleteKeyEx(startKey, keyName, mode, 0);
} else {
result = RegDeleteKeyW(startKey, keyName);
}
break;
} else if (result == ERROR_SUCCESS) {
result = RecursiveDeleteKey(hKey,
(const WCHAR *) Tcl_DStringValue(&subkey), mode);
|
| ︙ | ︙ | |||
1253 1254 1255 1256 1257 1258 1259 |
(DWORD) type, data, (DWORD) bytelength);
}
Tcl_DStringFree(&nameBuf);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
| | | | | 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 |
(DWORD) type, data, (DWORD) bytelength);
}
Tcl_DStringFree(&nameBuf);
RegCloseKey(key);
if (result != ERROR_SUCCESS) {
Tcl_SetObjResult(interp,
Tcl_NewStringObj("unable to set value: ", -1));
AppendSystemError(interp, result);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
|
| ︙ | ︙ | |||
1282 1283 1284 1285 1286 1287 1288 |
*----------------------------------------------------------------------
*/
static int
BroadcastValue(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
| | | 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 |
*----------------------------------------------------------------------
*/
static int
BroadcastValue(
Tcl_Interp *interp, /* Current interpreter. */
Tcl_Size objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument values. */
{
LRESULT result;
DWORD_PTR sendResult;
int timeout = 3000;
Tcl_Size len;
const char *str;
Tcl_Obj *objPtr;
|
| ︙ | ︙ | |||
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 |
objPtr = Tcl_NewObj();
Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) result));
Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) sendResult));
Tcl_SetObjResult(interp, objPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ConvertDWORD --
*
* Determines whether a DWORD needs to be byte swapped, and
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 |
objPtr = Tcl_NewObj();
Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) result));
Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) sendResult));
Tcl_SetObjResult(interp, objPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* AppendSystemError --
*
* Formats a Windows system error message and places it into
* the interpreter result.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
AppendSystemError(
Tcl_Interp *interp, /* Current interpreter. */
DWORD error) /* Result code from error. */
{
Tcl_Size length;
WCHAR *tMsgPtr, **tMsgPtrPtr = &tMsgPtr;
const char *msg;
char id[TCL_INTEGER_SPACE], msgBuf[24 + TCL_INTEGER_SPACE];
Tcl_DString ds;
Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
if (Tcl_IsShared(resultPtr)) {
resultPtr = Tcl_DuplicateObj(resultPtr);
}
length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (WCHAR *) tMsgPtrPtr,
0, NULL);
if (length == 0) {
snprintf(msgBuf, sizeof(msgBuf), "unknown error: %ld", error);
msg = msgBuf;
} else {
char *msgPtr;
Tcl_DStringInit(&ds);
Tcl_WCharToUtfDString(tMsgPtr, wcslen(tMsgPtr), &ds);
LocalFree(tMsgPtr);
msgPtr = Tcl_DStringValue(&ds);
length = Tcl_DStringLength(&ds);
/*
* Trim the trailing CR/LF from the system message.
*/
if (msgPtr[length-1] == '\n') {
--length;
}
if (msgPtr[length-1] == '\r') {
--length;
}
msgPtr[length] = 0;
msg = msgPtr;
}
snprintf(id, sizeof(id), "%ld", error);
Tcl_SetErrorCode(interp, "WINDOWS", id, msg, (char *)NULL);
Tcl_AppendToObj(resultPtr, msg, length);
Tcl_SetObjResult(interp, resultPtr);
if (length != 0) {
Tcl_DStringFree(&ds);
}
}
/*
*----------------------------------------------------------------------
*
* ConvertDWORD --
*
* Determines whether a DWORD needs to be byte swapped, and
|
| ︙ | ︙ |
Changes to win/tclWinSerial.c.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | * Serial functionality implemented by Rolf.Schroedter@dlr.de */ #include "tclWinInt.h" #if defined (__clang__) && (__clang_major__ > 20) #pragma clang diagnostic ignored "-Wc++-keyword" #endif /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | * Serial functionality implemented by Rolf.Schroedter@dlr.de */ #include "tclWinInt.h" #if defined (__clang__) && (__clang_major__ > 20) #pragma clang diagnostic ignored "-Wc++-keyword" #endif /* * The following variable is used to tell whether this module has been * initialized. */ static int initialized = 0; |
| ︙ | ︙ | |||
87 88 89 90 91 92 93 |
int watchMask; /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION: indicates
* which events should be reported. */
int flags; /* State flags, see above for a list. */
int readable; /* Flag that the channel is readable. */
int writable; /* Flag that the channel is writable. */
int blockTime; /* Maximum blocktime in msec. */
| | | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
int watchMask; /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, or TCL_EXCEPTION: indicates
* which events should be reported. */
int flags; /* State flags, see above for a list. */
int readable; /* Flag that the channel is readable. */
int writable; /* Flag that the channel is writable. */
int blockTime; /* Maximum blocktime in msec. */
unsigned long long lastEventTime;
/* Time in milliseconds since last readable
* event. */
/* Next readable event only after blockTime */
DWORD error; /* pending error code returned by
* ClearCommError() */
DWORD lastError; /* last error code, can be fetched with
* fconfigure chan -lasterror */
DWORD sysBufRead; /* Win32 system buffer size for read ops,
|
| ︙ | ︙ | |||
353 354 355 356 357 358 359 |
*----------------------------------------------------------------------
*/
static void
SerialBlockTime(
int msec) /* milli-seconds */
{
| > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
*----------------------------------------------------------------------
*/
static void
SerialBlockTime(
int msec) /* milli-seconds */
{
Tcl_Time blockTime;
blockTime.sec = msec / 1000;
blockTime.usec = (msec % 1000) * 1000;
Tcl_SetMaxBlockTime(&blockTime);
}
/*
*----------------------------------------------------------------------
*
* SerialGetMilliseconds --
*
* Get current time in milliseconds,ignoring integer overruns.
*
* Results:
* The current time.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static unsigned long long
SerialGetMilliseconds(void)
{
Tcl_Time time;
Tcl_GetTime(&time);
return (unsigned long long)time.sec * 1000
+ (unsigned long)time.usec / 1000;
}
/*
*----------------------------------------------------------------------
*
* SerialSetupProc --
*
|
| ︙ | ︙ | |||
377 378 379 380 381 382 383 | *---------------------------------------------------------------------- */ #ifdef __cplusplus #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif | | | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
*----------------------------------------------------------------------
*/
#ifdef __cplusplus
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
void
SerialSetupProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
SerialInfo *infoPtr;
int block = 1;
int msec = INT_MAX; /* min. found block time */
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 |
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
SerialInfo *infoPtr;
SerialEvent *evPtr;
int needEvent;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
COMSTAT cStat;
| | | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
SerialInfo *infoPtr;
SerialEvent *evPtr;
int needEvent;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
COMSTAT cStat;
unsigned long long time;
if (!(flags & TCL_FILE_EVENTS)) {
return;
}
/*
* Queue events for any ready serials that don't already have events
|
| ︙ | ︙ | |||
491 492 493 494 495 496 497 |
/*
* Force fileevent after serial read error.
*/
if ((cStat.cbInQue > 0) ||
(infoPtr->error & SERIAL_READ_ERRORS)) {
infoPtr->readable = 1;
| | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
/*
* Force fileevent after serial read error.
*/
if ((cStat.cbInQue > 0) ||
(infoPtr->error & SERIAL_READ_ERRORS)) {
infoPtr->readable = 1;
time = SerialGetMilliseconds();
if ((time - infoPtr->lastEventTime)
>= (unsigned long long) infoPtr->blockTime) {
needEvent = 1;
infoPtr->lastEventTime = time;
}
}
}
}
}
|
| ︙ | ︙ | |||
680 681 682 683 684 685 686 |
SerialInfo *infoPtr, /* Serial info structure */
LPVOID buf, /* The input buffer pointer */
DWORD bufSize, /* The number of bytes to read */
LPDWORD lpRead, /* Returns number of bytes read */
LPOVERLAPPED osPtr) /* OVERLAPPED structure */
{
/*
| | | | | | 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
SerialInfo *infoPtr, /* Serial info structure */
LPVOID buf, /* The input buffer pointer */
DWORD bufSize, /* The number of bytes to read */
LPDWORD lpRead, /* Returns number of bytes read */
LPOVERLAPPED osPtr) /* OVERLAPPED structure */
{
/*
* Perform overlapped blocking read.
* 1. Reset the overlapped event
* 2. Start overlapped read operation
* 3. Wait for completion
*/
/*
* Set Offset to ZERO, otherwise NT4.0 may report an error.
*/
osPtr->Offset = osPtr->OffsetHigh = 0;
|
| ︙ | ︙ | |||
746 747 748 749 750 751 752 |
LPDWORD lpWritten, /* Returns number of bytes written */
LPOVERLAPPED osPtr) /* OVERLAPPED structure */
{
int result;
/*
* Perform overlapped blocking write.
| | | | | | | | 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 |
LPDWORD lpWritten, /* Returns number of bytes written */
LPOVERLAPPED osPtr) /* OVERLAPPED structure */
{
int result;
/*
* Perform overlapped blocking write.
* 1. Reset the overlapped event
* 2. Remove these bytes from the output queue counter
* 3. Start overlapped write operation
* 3. Remove these bytes from the output queue counter
* 4. Wait for completion
* 5. Adjust the output queue counter
*/
ResetEvent(osPtr->hEvent);
EnterCriticalSection(&infoPtr->csWrite);
infoPtr->writeQueue -= bufSize;
|
| ︙ | ︙ | |||
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 |
infoPtr->writeBuf = (char *)Tcl_Alloc(toWrite);
}
memcpy(infoPtr->writeBuf, buf, toWrite);
infoPtr->toWrite = toWrite;
ResetEvent(infoPtr->evWritable);
TclPipeThreadSignal(&infoPtr->writeTI);
bytesWritten = (DWORD) toWrite;
} else {
/*
* In the blocking case, just try to write the buffer directly. This
* avoids an unnecessary copy.
*/
if (!SerialBlockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite,
| > | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 |
infoPtr->writeBuf = (char *)Tcl_Alloc(toWrite);
}
memcpy(infoPtr->writeBuf, buf, toWrite);
infoPtr->toWrite = toWrite;
ResetEvent(infoPtr->evWritable);
TclPipeThreadSignal(&infoPtr->writeTI);
bytesWritten = (DWORD) toWrite;
} else {
/*
* In the blocking case, just try to write the buffer directly. This
* avoids an unnecessary copy.
*/
if (!SerialBlockingWrite(infoPtr, (LPVOID) buf, (DWORD) toWrite,
|
| ︙ | ︙ | |||
1761 1762 1763 1764 1765 1766 1767 |
* hex/octal value rather than the printable form.
*/
dcb.XonChar = argv[0][0];
dcb.XoffChar = argv[1][0];
if (argv[0][0] & 0x80 || argv[1][0] & 0x80) {
Tcl_UniChar character = 0;
| | | 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 |
* hex/octal value rather than the printable form.
*/
dcb.XonChar = argv[0][0];
dcb.XoffChar = argv[1][0];
if (argv[0][0] & 0x80 || argv[1][0] & 0x80) {
Tcl_UniChar character = 0;
int charLen;
charLen = TclUtfToUniChar(argv[0], &character);
if ((character > 0xFF) || argv[0][charLen]) {
goto badXchar;
}
dcb.XonChar = (char) character;
charLen = TclUtfToUniChar(argv[1], &character);
|
| ︙ | ︙ | |||
1872 1873 1874 1875 1876 1877 1878 |
*/
if ((len > 1) && (strncmp(optionName, "-sysbuffer", len) == 0)) {
/*
* -sysbuffer 4096 or -sysbuffer {64536 4096}
*/
| | | | < | < | < | 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 |
*/
if ((len > 1) && (strncmp(optionName, "-sysbuffer", len) == 0)) {
/*
* -sysbuffer 4096 or -sysbuffer {64536 4096}
*/
int inSize = -1, outSize = -1;
if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) {
return TCL_ERROR;
}
if (argc == 1) {
inSize = atoi(argv[0]);
outSize = infoPtr->sysBufWrite;
} else if (argc == 2) {
inSize = atoi(argv[0]);
outSize = atoi(argv[1]);
}
Tcl_Free((void *)argv);
if ((argc < 1) || (argc > 2) || (inSize <= 0) || (outSize <= 0)) {
if (interp != NULL) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"bad value \"%s\" for -sysbuffer: should be "
"a list of one or two integers > 0", value));
Tcl_SetErrorCode(interp, "TCL", "VALUE", "SYS_BUFFER", (char *)NULL);
}
return TCL_ERROR;
|
| ︙ | ︙ |
Changes to win/tclWinSock.c.
| ︙ | ︙ | |||
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
int operation, /* Whether to add or remove from the mask. */
TcpState *payload) /* What socket to add/remove. */
{
SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) operation,
(LPARAM) payload);
}
/*
*----------------------------------------------------------------------
*
* InitializeHostName --
*
* This routine sets the process global value of the name of the local
* host on which the process is running.
*
* Results:
* None.
*
*----------------------------------------------------------------------
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 |
int operation, /* Whether to add or remove from the mask. */
TcpState *payload) /* What socket to add/remove. */
{
SendMessageW(tsdPtr->hwnd, SOCKET_SELECT, (WPARAM) operation,
(LPARAM) payload);
}
/*
* Address print debug functions
*/
#if 0
static inline void
printaddrinfo(
struct addrinfo *ai,
char *prefix)
{
char host[NI_MAXHOST], port[NI_MAXSERV];
getnameinfo(ai->ai_addr, ai->ai_addrlen,
host, sizeof(host), port, sizeof(port),
NI_NUMERICHOST | NI_NUMERICSERV);
}
static void
printaddrinfolist(
struct addrinfo *addrlist,
char *prefix)
{
struct addrinfo *ai;
for (ai = addrlist; ai != NULL; ai = ai->ai_next) {
printaddrinfo(ai, prefix);
}
}
#endif
/*
*----------------------------------------------------------------------
*
* InitializeHostName --
*
* This routine sets the process global value of the name of the local
* host on which the process is running.
*
* Results:
* None.
*
*----------------------------------------------------------------------
*/
void
InitializeHostName(
char **valuePtr,
size_t *lengthPtr,
Tcl_Encoding *encodingPtr)
{
WCHAR wbuf[256];
DWORD length = sizeof(wbuf) / sizeof(WCHAR);
|
| ︙ | ︙ | |||
362 363 364 365 366 367 368 | /* * The buffer size of 256 is recommended by the MSDN page that * documents gethostname() as being always adequate. */ Tcl_DStringInit(&ds); Tcl_DStringSetLength(&ds, 256); | | | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
/*
* The buffer size of 256 is recommended by the MSDN page that
* documents gethostname() as being always adequate.
*/
Tcl_DStringInit(&ds);
Tcl_DStringSetLength(&ds, 256);
gethostname(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds));
Tcl_DStringSetLength(&ds, strlen(Tcl_DStringValue(&ds)));
}
*encodingPtr = Tcl_GetEncoding(NULL, NULL);
*lengthPtr = Tcl_DStringLength(&ds);
*valuePtr = (char *)Tcl_Alloc(*lengthPtr + 1);
memcpy(*valuePtr, Tcl_DStringValue(&ds), *lengthPtr + 1);
|
| ︙ | ︙ | |||
957 958 959 960 961 962 963 964 |
/*
* Since Windows won't generate a new write event until we hit an
* overflow condition, we need to force the event loop to poll
* until the condition changes.
*/
if (GOT_BITS(statePtr->watchEvents, FD_WRITE)) {
| > | | 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 |
/*
* Since Windows won't generate a new write event until we hit an
* overflow condition, we need to force the event loop to poll
* until the condition changes.
*/
if (GOT_BITS(statePtr->watchEvents, FD_WRITE)) {
Tcl_Time blockTime = { 0, 0 };
Tcl_SetMaxBlockTime(&blockTime);
}
break;
}
/*
* Check for error condition or overflow. In the event of overflow, we
* need to clear the FD_WRITE flag so we can detect the next writable
|
| ︙ | ︙ | |||
1564 1565 1566 1567 1568 1569 1570 1571 |
/*
* If there are any conditions already set, then tell the notifier to
* poll rather than block.
*/
if (statePtr->readyEvents & statePtr->watchEvents) {
| > | | 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 |
/*
* If there are any conditions already set, then tell the notifier to
* poll rather than block.
*/
if (statePtr->readyEvents & statePtr->watchEvents) {
Tcl_Time blockTime = { 0, 0 };
Tcl_SetMaxBlockTime(&blockTime);
}
}
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 | TCP_BUFFER_SIZE); /* * Try to bind to a local port. */ if (bind(statePtr->sockets->fd, statePtr->myaddr->ai_addr, | | | 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 |
TCP_BUFFER_SIZE);
/*
* Try to bind to a local port.
*/
if (bind(statePtr->sockets->fd, statePtr->myaddr->ai_addr,
statePtr->myaddr->ai_addrlen) == SOCKET_ERROR) {
Tcl_WinConvertError((DWORD) WSAGetLastError());
continue;
}
/*
* For asynchronous connect set the socket in nonblocking mode
* and activate connect notification
|
| ︙ | ︙ | |||
1799 1800 1801 1802 1803 1804 1805 | } /* * Attempt to connect to the remote socket. */ connect(statePtr->sockets->fd, statePtr->addr->ai_addr, | | | 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 |
}
/*
* Attempt to connect to the remote socket.
*/
connect(statePtr->sockets->fd, statePtr->addr->ai_addr,
statePtr->addr->ai_addrlen);
error = WSAGetLastError();
Tcl_WinConvertError(error);
if (async_connect && error == WSAEWOULDBLOCK) {
/*
* Asynchronous connect
|
| ︙ | ︙ | |||
2186 2187 2188 2189 2190 2191 2192 | * * Bind should not be affected by the socket having already been * set into nonblocking mode. If there is trouble, this is one * place to look for bugs. */ if (bind(sock, addrPtr->ai_addr, | | | 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 |
*
* Bind should not be affected by the socket having already been
* set into nonblocking mode. If there is trouble, this is one
* place to look for bugs.
*/
if (bind(sock, addrPtr->ai_addr,
addrPtr->ai_addrlen) == SOCKET_ERROR) {
Tcl_WinConvertError((DWORD) WSAGetLastError());
closesocket(sock);
sock = INVALID_SOCKET; /* Bug [40b1814b93] */
continue;
}
if (port == 0 && chosenport == 0) {
address sockname;
|
| ︙ | ︙ | |||
2284 2285 2286 2287 2288 2289 2290 |
return NULL;
}
/*
*----------------------------------------------------------------------
*
* TcpAccept --
| < | | 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 |
return NULL;
}
/*
*----------------------------------------------------------------------
*
* TcpAccept --
* Accept a TCP socket connection. This is called by the event loop.
*
* Results:
* None.
*
* Side effects:
* Creates a new connection socket. Calls the registered callback for the
* connection acceptance mechanism.
|
| ︙ | ︙ | |||
2467 2468 2469 2470 2471 2472 2473 | * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */ | | > | | | 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 |
*
* Side effects:
* Adjusts the block time if needed.
*
*----------------------------------------------------------------------
*/
void
SocketSetupProc(
TCL_UNUSED(void *),
int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
TcpState *statePtr;
Tcl_Time blockTime = { 0, 0 };
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!GOT_BITS(flags, TCL_FILE_EVENTS)) {
return;
}
/*
* Check to see if there is a ready socket. If so, poll.
*/
WaitForSingleObject(tsdPtr->socketListLock, INFINITE);
for (statePtr = tsdPtr->socketList; statePtr != NULL;
statePtr = statePtr->nextPtr) {
if (GOT_BITS(statePtr->readyEvents,
statePtr->watchEvents | FD_CONNECT | FD_ACCEPT)) {
Tcl_SetMaxBlockTime(&blockTime);
break;
}
}
SetEvent(tsdPtr->socketListLock);
}
/*
|
| ︙ | ︙ | |||
2726 2727 2728 2729 2730 2731 2732 | * event until someone does something with the channel. Note that we * do this before calling Tcl_NotifyChannel so we don't have to watch * out for the channel being deleted out from under us. This may cause * a redundant trip through the event loop, but it's simpler than * trying to do unwind protection. */ | > > | | 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 |
* event until someone does something with the channel. Note that we
* do this before calling Tcl_NotifyChannel so we don't have to watch
* out for the channel being deleted out from under us. This may cause
* a redundant trip through the event loop, but it's simpler than
* trying to do unwind protection.
*/
Tcl_Time blockTime = { 0, 0 };
Tcl_SetMaxBlockTime(&blockTime);
SET_BITS(mask, TCL_READABLE | TCL_WRITABLE);
} else if (GOT_BITS(events, FD_READ)) {
/*
* Throw the readable event if an async connect failed.
*/
if (GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
|
| ︙ | ︙ | |||
3022 3023 3024 3025 3026 3027 3028 |
/*
* This releases waiters on thread exit in TclpFinalizeSockets()
*/
SetEvent(tsdPtr->readyEvent);
| | | 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 |
/*
* This releases waiters on thread exit in TclpFinalizeSockets()
*/
SetEvent(tsdPtr->readyEvent);
return msg.wParam;
}
/*
*----------------------------------------------------------------------
*
* SocketProc --
*
|
| ︙ | ︙ |
Changes to win/tclWinTest.c.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 | #define INHERITED_ACE (0x10) #endif /* * Forward declarations of functions defined later in this file: */ | | | | | | | < | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #define INHERITED_ACE (0x10) #endif /* * Forward declarations of functions defined later in this file: */ static Tcl_ObjCmdProc TesteventloopCmd; static Tcl_ObjCmdProc TestvolumetypeCmd; static Tcl_ObjCmdProc TestwinclockCmd; static Tcl_ObjCmdProc TestwinsleepCmd; static Tcl_ObjCmdProc TestExceptionCmd; static int TestplatformChmod(const char *nativePath, int pmode); static Tcl_ObjCmdProc TestchmodCmd; static Tcl_ObjCmdProc TestfilesddlCmd; /* *---------------------------------------------------------------------- * * TclplatformtestInit -- * * Defines commands that test platform specific functionality for Windows |
| ︙ | ︙ | |||
69 70 71 72 73 74 75 |
TclplatformtestInit(
Tcl_Interp *interp) /* Interpreter to add commands to. */
{
/*
* Add commands for platform specific tests for Windows here.
*/
| | | | | | | < < < | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
TclplatformtestInit(
Tcl_Interp *interp) /* Interpreter to add commands to. */
{
/*
* Add commands for platform specific tests for Windows here.
*/
Tcl_CreateObjCommand(interp, "testchmod", TestchmodCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testeventloop", TesteventloopCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testvolumetype", TestvolumetypeCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testwinclock", TestwinclockCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testwinsleep", TestwinsleepCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testexcept", TestExceptionCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testfilesddl", TestfilesddlCmd, NULL, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TesteventloopCmd --
|
| ︙ | ︙ | |||
105 106 107 108 109 110 111 |
*----------------------------------------------------------------------
*/
static int
TesteventloopCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
*----------------------------------------------------------------------
*/
static int
TesteventloopCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static int *framePtr = NULL;/* Pointer to integer on stack frame of
* innermost invocation of the "wait"
* subcommand. */
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "done|wait");
|
| ︙ | ︙ | |||
181 182 183 184 185 186 187 |
*----------------------------------------------------------------------
*/
static int
TestvolumetypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
*----------------------------------------------------------------------
*/
static int
TestvolumetypeCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
#define VOL_BUF_SIZE 32
int found;
char volType[VOL_BUF_SIZE];
const char *path;
if (objc > 2) {
|
| ︙ | ︙ | |||
246 247 248 249 250 251 252 |
*
*----------------------------------------------------------------------
*/
static int
TestwinclockCmd(
TCL_UNUSED(void *),
| | | | | | | | | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
*
*----------------------------------------------------------------------
*/
static int
TestwinclockCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Argument count */
Tcl_Obj *const objv[]) /* Argument vector */
{
static const FILETIME posixEpoch = { 0xD53E8000, 0x019DB1DE };
/* The Posix epoch, expressed as a Windows
* FILETIME */
Tcl_Time tclTime; /* Tcl clock */
FILETIME sysTime; /* System clock */
Tcl_Obj *result; /* Result of the command */
LARGE_INTEGER t1, t2;
LARGE_INTEGER p1, p2;
if (objc != 1) {
Tcl_WrongNumArgs(interp, 1, objv, "");
return TCL_ERROR;
}
QueryPerformanceCounter(&p1);
Tcl_GetTime(&tclTime);
GetSystemTimeAsFileTime(&sysTime);
t1.LowPart = posixEpoch.dwLowDateTime;
t1.HighPart = posixEpoch.dwHighDateTime;
t2.LowPart = sysTime.dwLowDateTime;
t2.HighPart = sysTime.dwHighDateTime;
t2.QuadPart -= t1.QuadPart;
QueryPerformanceCounter(&p2);
result = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, result,
Tcl_NewWideIntObj(t2.QuadPart / 10000000));
Tcl_ListObjAppendElement(interp, result,
Tcl_NewWideIntObj((t2.QuadPart / 10) % 1000000));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(tclTime.sec));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(tclTime.usec));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(p1.QuadPart));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(p2.QuadPart));
Tcl_SetObjResult(interp, result);
return TCL_OK;
}
static int
TestwinsleepCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const * objv) /* Parameter vector */
{
int ms;
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "ms");
return TCL_ERROR;
|
| ︙ | ︙ | |||
338 339 340 341 342 343 344 |
*
*----------------------------------------------------------------------
*/
static int
TestExceptionCmd(
TCL_UNUSED(void *),
| | | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
*
*----------------------------------------------------------------------
*/
static int
TestExceptionCmd(
TCL_UNUSED(void *),
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Argument count */
Tcl_Obj *const objv[]) /* Argument vector */
{
static const char *const cmds[] = {
"access_violation", "datatype_misalignment", "array_bounds",
"float_denormal", "float_divbyzero", "float_inexact",
"float_invalidop", "float_overflow", "float_stack", "float_underflow",
"int_divbyzero", "int_overflow", "private_instruction", "inpageerror",
"illegal_instruction", "noncontinue", "stack_overflow",
|
| ︙ | ︙ | |||
394 395 396 397 398 399 400 |
/* SMASH! */
RaiseException(exceptions[cmd], EXCEPTION_NONCONTINUABLE, 0, NULL);
return TCL_OK;
}
/*
| < < < < | | < < < | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 |
/* SMASH! */
RaiseException(exceptions[cmd], EXCEPTION_NONCONTINUABLE, 0, NULL);
return TCL_OK;
}
/*
* This "chmod" works sufficiently for test script purposes. Do not expect
* it to be exact emulation of Unix chmod (not sure if that's even possible)
*/
static int
TestplatformChmod(
const char *nativePath,
int pmode)
{
/*
|
| ︙ | ︙ | |||
446 447 448 449 450 451 452 |
int nSids = 0;
struct {
PSID pSid;
DWORD mask;
DWORD sidLen;
} aceEntry[3];
DWORD dw;
| | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
int nSids = 0;
struct {
PSID pSid;
DWORD mask;
DWORD sidLen;
} aceEntry[3];
DWORD dw;
int isDir;
TOKEN_USER *pTokenUser = NULL;
Tcl_DString ds;
res = -1; /* Assume failure */
Tcl_DStringInit(&ds);
Tcl_UtfToChar16DString(nativePath, -1, &ds);
|
| ︙ | ︙ | |||
486 487 488 489 490 491 492 |
Tcl_Free(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
goto done;
}
/*
* Always include DACL modify rights so we don't get locked out
*/
aceEntry[nSids].mask = READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE |
| | | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 |
Tcl_Free(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
goto done;
}
/*
* Always include DACL modify rights so we don't get locked out
*/
aceEntry[nSids].mask = READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE |
FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
if (pmode & 0700) {
/* Owner permissions. Assumes current process is owner */
if (pmode & 0400) {
aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
}
if (pmode & 0200) {
aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
|
| ︙ | ︙ | |||
519 520 521 522 523 524 525 |
pTokenGroup = (TOKEN_PRIMARY_GROUP *)Tcl_Alloc(dw);
if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dw, &dw)) {
Tcl_Free(pTokenGroup);
goto done;
}
aceEntry[nSids].sidLen = GetLengthSid(pTokenGroup->PrimaryGroup);
aceEntry[nSids].pSid = (PSID)Tcl_Alloc(aceEntry[nSids].sidLen);
| | < | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
pTokenGroup = (TOKEN_PRIMARY_GROUP *)Tcl_Alloc(dw);
if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dw, &dw)) {
Tcl_Free(pTokenGroup);
goto done;
}
aceEntry[nSids].sidLen = GetLengthSid(pTokenGroup->PrimaryGroup);
aceEntry[nSids].pSid = (PSID)Tcl_Alloc(aceEntry[nSids].sidLen);
if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid, pTokenGroup->PrimaryGroup)) {
Tcl_Free(pTokenGroup);
Tcl_Free(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
goto done;
}
Tcl_Free(pTokenGroup);
/* Generate mask for group ACL */
|
| ︙ | ︙ | |||
577 578 579 580 581 582 583 |
}
/* Allocate memory and initialize the new ACL. */
newAclSize = sizeof(ACL);
/* Add in size required for each ACE entry in the ACL */
for (i = 0; i < nSids; ++i) {
| | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 |
}
/* Allocate memory and initialize the new ACL. */
newAclSize = sizeof(ACL);
/* Add in size required for each ACE entry in the ACL */
for (i = 0; i < nSids; ++i) {
newAclSize +=
offsetof(ACCESS_ALLOWED_ACE, SidStart) + aceEntry[i].sidLen;
}
newAcl = (PACL)Tcl_Alloc(newAclSize);
if (!InitializeAcl(newAcl, newAclSize, ACL_REVISION)) {
goto done;
}
for (i = 0; i < nSids; ++i) {
|
| ︙ | ︙ | |||
647 648 649 650 651 652 653 |
*---------------------------------------------------------------------------
*/
static int
TestchmodCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | < | | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 |
*---------------------------------------------------------------------------
*/
static int
TestchmodCmd(
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Parameter count */
Tcl_Obj *const * objv) /* Parameter vector */
{
int i, mode;
if (objc < 2) {
Tcl_WrongNumArgs(interp, 1, objv, "mode file ?file ...?");
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[1], &mode) != TCL_OK) {
|
| ︙ | ︙ | |||
679 680 681 682 683 684 685 |
(char *)NULL);
return TCL_ERROR;
}
Tcl_DStringFree(&buffer);
}
return TCL_OK;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
(char *)NULL);
return TCL_ERROR;
}
Tcl_DStringFree(&buffer);
}
return TCL_OK;
}
/*
*------------------------------------------------------------------------
*
* TestfilesddlCmd --
*
* Implements the Tcl command testfilesddl
|
| ︙ | ︙ | |||
741 742 743 744 745 746 747 |
*
*------------------------------------------------------------------------
*/
int
TestfilesddlCmd (
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
| | | 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
*
*------------------------------------------------------------------------
*/
int
TestfilesddlCmd (
TCL_UNUSED(void *),
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
if (objc < 2 || objc > 3) {
Tcl_WrongNumArgs(interp, 1, objv, "PATH ?SDDL?");
return TCL_ERROR;
}
|
| ︙ | ︙ | |||
771 772 773 774 775 776 777 |
goto vamoose;
}
if (!ConvertSecurityDescriptorToStringSecurityDescriptorW(secdPtr,
SDDL_REVISION_1, secInfo, &sddlPtr, NULL)) {
err = GetLastError();
errorMessage = "Failed to convert security descriptor to SDDL";
| | | 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 |
goto vamoose;
}
if (!ConvertSecurityDescriptorToStringSecurityDescriptorW(secdPtr,
SDDL_REVISION_1, secInfo, &sddlPtr, NULL)) {
err = GetLastError();
errorMessage = "Failed to convert security descriptor to SDDL";
goto vamoose;
}
(void)Tcl_Char16ToUtfDString(sddlPtr, -1, &ds);
/* The original sddl is returned in all cases */
Tcl_DStringResult(interp, &ds);
if (objc == 3) {
|
| ︙ | ︙ |
Changes to win/tclWinThrd.c.
| ︙ | ︙ | |||
11 12 13 14 15 16 17 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" /* Workaround for mingw versions which don't provide this in float.h */ #ifndef _MCW_EM | | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tclWinInt.h" /* Workaround for mingw versions which don't provide this in float.h */ #ifndef _MCW_EM # define _MCW_EM 0x0008001F /* Error masks */ # define _MCW_RC 0x00000300 /* Rounding */ # define _MCW_PC 0x00030000 /* Precision */ _CRTIMP unsigned int __cdecl _controlfp (unsigned int unNew, unsigned int unMask); #endif /* * This is the global lock used to serialize access to other serialization * data structures. */ |
| ︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | * prevent a race where a new joinable thread exits before the creating thread * had the time to create the necessary data structures in the emulation * layer. */ static CRITICAL_SECTION joinLock; /* * Additions by AOL for specialized thread memory allocator. */ #ifdef USE_THREAD_ALLOC static DWORD tlsKey; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
* prevent a race where a new joinable thread exits before the creating thread
* had the time to create the necessary data structures in the emulation
* layer.
*/
static CRITICAL_SECTION joinLock;
/*
* Condition variables are implemented with a combination of a per-thread
* Windows Event and a per-condition waiting queue. The idea is that each
* thread has its own Event that it waits on when it is doing a ConditionWait;
* it uses the same event for all condition variables because it only waits on
* one at a time. Each condition variable has a queue of waiting threads, and
* a mutex used to serialize access to this queue.
*
* Special thanks to David Nichols and Jim Davidson for advice on the
* Condition Variable implementation.
*/
/*
* The per-thread event and queue pointers.
*/
#if TCL_THREADS
typedef struct ThreadSpecificData {
HANDLE condEvent; /* Per-thread condition event */
struct ThreadSpecificData *nextPtr; /* Queue pointers */
struct ThreadSpecificData *prevPtr;
int flags; /* See ThreadStateFlags below */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
#endif /* TCL_THREADS */
/*
* State bits for the thread.
*/
enum ThreadStateFlags {
WIN_THREAD_UNINIT = 0x0, /* Uninitialized. Must be zero because of the
* way ThreadSpecificData is created. */
WIN_THREAD_RUNNING = 0x1, /* Running, not waiting. */
WIN_THREAD_BLOCKED = 0x2 /* Waiting, or trying to wait. */
};
/*
* The per condition queue pointers and the Mutex used to serialize access to
* the queue.
*/
typedef struct {
CRITICAL_SECTION condLock; /* Lock to serialize queuing on the
* condition. */
ThreadSpecificData *firstPtr; /* Queue pointers */
ThreadSpecificData *lastPtr;
} WinCondition;
/*
* Additions by AOL for specialized thread memory allocator.
*/
#ifdef USE_THREAD_ALLOC
static DWORD tlsKey;
|
| ︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
*/
CloseHandle(tHandle);
LeaveCriticalSection(&joinLock);
return TCL_OK;
}
}
/*
*----------------------------------------------------------------------
*
* TclpThreadExit --
*
* This procedure terminates the current thread.
| > > > > > > > > > > > > > > > > > > > > > > > > > > | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
*/
CloseHandle(tHandle);
LeaveCriticalSection(&joinLock);
return TCL_OK;
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_JoinThread --
*
* This procedure waits upon the exit of the specified thread.
*
* Results:
* TCL_OK if the wait was successful, TCL_ERROR else.
*
* Side effects:
* The result area is set to the exit code of the thread we
* waited upon.
*
*----------------------------------------------------------------------
*/
int
Tcl_JoinThread(
Tcl_ThreadId threadId, /* Id of the thread to wait upon */
int *result) /* Reference to the storage the result of the
* thread we wait upon will be written into. */
{
return TclJoinThread(threadId, result);
}
/*
*----------------------------------------------------------------------
*
* TclpThreadExit --
*
* This procedure terminates the current thread.
|
| ︙ | ︙ | |||
509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
// It's recursive
wmPtr->counter--;
} else {
wmPtr->thread = 0;
LeaveCriticalSection(&wmPtr->crit);
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_MutexLock --
*
* This procedure is invoked to lock a mutex. This is a self initializing
| > > > | 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
// It's recursive
wmPtr->counter--;
} else {
wmPtr->thread = 0;
LeaveCriticalSection(&wmPtr->crit);
}
}
/* locally used prototype */
static void FinalizeConditionEvent(void *data);
/*
*----------------------------------------------------------------------
*
* Tcl_MutexLock --
*
* This procedure is invoked to lock a mutex. This is a self initializing
|
| ︙ | ︙ | |||
609 610 611 612 613 614 615 |
*mutexPtr = NULL;
}
}
/*
*----------------------------------------------------------------------
*
| | | | | | | > > > > > > > > | > > | > > > | > > > > > > > > > | > > > > > > > > > > > > > > > | | > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > | > > > > | > > > > | > > > > > > > > | > | > > > > | > > > > | > > > > > > | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
*mutexPtr = NULL;
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_ConditionWait --
*
* This procedure is invoked to wait on a condition variable. The mutex
* is atomically released as part of the wait, and automatically grabbed
* when the condition is signaled.
*
* The mutex must be held when this procedure is called.
*
* Results:
* None.
*
* Side effects:
* May block the current thread. The mutex is acquired when this returns.
* Will allocate memory for a HANDLE and initialize this the first time
* this Tcl_Condition is used.
*
*----------------------------------------------------------------------
*/
void
Tcl_ConditionWait(
Tcl_Condition *condPtr, /* Really (WinCondition **) */
Tcl_Mutex *mutexPtr, /* Really (CRITICAL_SECTION **) */
const Tcl_Time *timePtr) /* Timeout on waiting period */
{
WinCondition *winCondPtr; /* Per-condition queue head */
WMutex *wmPtr; /* Caller's Mutex, after casting */
DWORD wtime; /* Windows time value */
int timeout; /* True if we got a timeout */
int counter; /* Caller's Mutex counter */
int doExit = 0; /* True if we need to do exit setup */
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
/*
* Self initialize the two parts of the condition. The per-condition and
* per-thread parts need to be handled independently.
*/
if (tsdPtr->flags == WIN_THREAD_UNINIT) {
TclpGlobalLock();
/*
* Create the per-thread event and queue pointers.
*/
if (tsdPtr->flags == WIN_THREAD_UNINIT) {
tsdPtr->condEvent = CreateEventW(NULL, TRUE /* manual reset */,
FALSE /* non signaled */, NULL);
tsdPtr->nextPtr = NULL;
tsdPtr->prevPtr = NULL;
tsdPtr->flags = WIN_THREAD_RUNNING;
doExit = 1;
}
TclpGlobalUnlock();
if (doExit) {
/*
* Create a per-thread exit handler to clean up the condEvent. We
* must be careful to do this outside the Global Lock because
* Tcl_CreateThreadExitHandler uses its own ThreadSpecificData,
* and initializing that may drop back into the Global Lock.
*/
Tcl_CreateThreadExitHandler(FinalizeConditionEvent, tsdPtr);
}
}
if (*condPtr == NULL) {
TclpGlobalLock();
/*
* Initialize the per-condition queue pointers and Mutex.
*/
if (*condPtr == NULL) {
winCondPtr = (WinCondition *)Tcl_Alloc(sizeof(WinCondition));
InitializeCriticalSection(&winCondPtr->condLock);
winCondPtr->firstPtr = NULL;
winCondPtr->lastPtr = NULL;
*condPtr = (Tcl_Condition) winCondPtr;
TclRememberCondition(condPtr);
}
TclpGlobalUnlock();
}
wmPtr = *((WMutex **)mutexPtr);
winCondPtr = *((WinCondition **)condPtr);
if (timePtr == NULL) {
wtime = INFINITE;
} else {
wtime = (DWORD)timePtr->sec * 1000 + (DWORD)timePtr->usec / 1000;
}
/*
* Queue the thread on the condition, using the per-condition lock for
* serialization.
*/
tsdPtr->flags = WIN_THREAD_BLOCKED;
tsdPtr->nextPtr = NULL;
EnterCriticalSection(&winCondPtr->condLock);
tsdPtr->prevPtr = winCondPtr->lastPtr; /* A: */
winCondPtr->lastPtr = tsdPtr;
if (tsdPtr->prevPtr != NULL) {
tsdPtr->prevPtr->nextPtr = tsdPtr;
}
if (winCondPtr->firstPtr == NULL) {
winCondPtr->firstPtr = tsdPtr;
}
/*
* Unlock the caller's mutex and wait for the condition, or a timeout.
* There is a minor issue here in that we don't count down the timeout if
* we get notified, but another thread grabs the condition before we do.
* In that race condition we'll wait again for the full timeout. Timed
* waits are dubious anyway. Either you have the locking protocol wrong
* and are masking a deadlock, or you are using conditions to pause your
* thread.
*/
counter = wmPtr->counter;
wmPtr->counter = 0;
DWORD mythread = GetCurrentThreadId();
assert(wmPtr->thread == mythread);
wmPtr->thread = 0;
LeaveCriticalSection(&wmPtr->crit);
timeout = 0;
while (!timeout && (tsdPtr->flags & WIN_THREAD_BLOCKED)) {
ResetEvent(tsdPtr->condEvent);
LeaveCriticalSection(&winCondPtr->condLock);
if (WaitForSingleObjectEx(tsdPtr->condEvent, wtime,
TRUE) == WAIT_TIMEOUT) {
timeout = 1;
}
EnterCriticalSection(&winCondPtr->condLock);
}
/*
* Be careful on timeouts because the signal might arrive right around the
* time limit and someone else could have taken us off the queue.
*/
if (timeout) {
if (tsdPtr->flags & WIN_THREAD_RUNNING) {
timeout = 0;
} else {
/*
* When dequeueing, we can leave the tsdPtr->nextPtr and
* tsdPtr->prevPtr with dangling pointers because they are
* reinitialized w/out reading them when the thread is enqueued
* later.
*/
if (winCondPtr->firstPtr == tsdPtr) {
winCondPtr->firstPtr = tsdPtr->nextPtr;
} else {
tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
}
if (winCondPtr->lastPtr == tsdPtr) {
winCondPtr->lastPtr = tsdPtr->prevPtr;
} else {
tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
}
tsdPtr->flags = WIN_THREAD_RUNNING;
}
}
LeaveCriticalSection(&winCondPtr->condLock);
EnterCriticalSection(&wmPtr->crit);
wmPtr->counter = counter;
wmPtr->thread = mythread;
}
/*
*----------------------------------------------------------------------
*
|
| ︙ | ︙ | |||
698 699 700 701 702 703 704 |
*----------------------------------------------------------------------
*/
void
Tcl_ConditionNotify(
Tcl_Condition *condPtr)
{
| | > < > | > > | | > > > > > | > > > > > > | > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 |
*----------------------------------------------------------------------
*/
void
Tcl_ConditionNotify(
Tcl_Condition *condPtr)
{
WinCondition *winCondPtr;
ThreadSpecificData *tsdPtr;
if (*condPtr != NULL) {
winCondPtr = *((WinCondition **)condPtr);
if (winCondPtr == NULL) {
return;
}
/*
* Loop through all the threads waiting on the condition and notify
* them (i.e., broadcast semantics). The queue manipulation is guarded
* by the per-condition coordinating mutex.
*/
EnterCriticalSection(&winCondPtr->condLock);
while (winCondPtr->firstPtr != NULL) {
tsdPtr = winCondPtr->firstPtr;
winCondPtr->firstPtr = tsdPtr->nextPtr;
if (winCondPtr->lastPtr == tsdPtr) {
winCondPtr->lastPtr = NULL;
}
tsdPtr->flags = WIN_THREAD_RUNNING;
tsdPtr->nextPtr = NULL;
tsdPtr->prevPtr = NULL; /* Not strictly necessary, see A: */
SetEvent(tsdPtr->condEvent);
}
LeaveCriticalSection(&winCondPtr->condLock);
} else {
/*
* No-one has used the condition variable, so there are no waiters.
*/
}
}
/*
*----------------------------------------------------------------------
*
* FinalizeConditionEvent --
*
* This procedure is invoked to clean up the per-thread event used to
* implement condition waiting. This is only safe to call at the end of
* time.
*
* Results:
* None.
*
* Side effects:
* The per-thread event is closed.
*
*----------------------------------------------------------------------
*/
static void
FinalizeConditionEvent(
void *data)
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) data;
tsdPtr->flags = WIN_THREAD_UNINIT;
CloseHandle(tsdPtr->condEvent);
}
/*
*----------------------------------------------------------------------
*
* TclpFinalizeCondition --
*
* This procedure is invoked to clean up a condition variable. This is
|
| ︙ | ︙ | |||
733 734 735 736 737 738 739 |
*----------------------------------------------------------------------
*/
void
TclpFinalizeCondition(
Tcl_Condition *condPtr)
{
| > | > > > > > > | > | | | 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
*----------------------------------------------------------------------
*/
void
TclpFinalizeCondition(
Tcl_Condition *condPtr)
{
WinCondition *winCondPtr = *(WinCondition **)condPtr;
/*
* Note - this is called long after the thread-local storage is reclaimed.
* The per-thread condition waiting event is reclaimed earlier in a
* per-thread exit handler, which is called before thread local storage is
* reclaimed.
*/
if (winCondPtr != NULL) {
DeleteCriticalSection(&winCondPtr->condLock);
Tcl_Free(winCondPtr);
*condPtr = NULL;
}
}
/*
* Additions by AOL for specialized thread memory allocator.
*/
#ifdef USE_THREAD_ALLOC
Tcl_Mutex *
TclpNewAllocMutex(void)
|
| ︙ | ︙ |
Deleted win/tclWinThreadJoin.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to win/tclWinTime.c.
| ︙ | ︙ | |||
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | static void StopCalibration(void *clientData); static DWORD WINAPI CalibrationThread(LPVOID arg); static void UpdateTimeEachSecond(void); static void ResetCounterSamples(unsigned long long fileTime, long long perfCounter, long long perfFreq); static long long AccumulateSample(long long perfCounter, unsigned long long fileTime); static long long NativeGetMicroseconds(void); /* *---------------------------------------------------------------------- * * TclpGetSeconds -- * * This procedure returns the number of seconds from the epoch. On most | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
static void StopCalibration(void *clientData);
static DWORD WINAPI CalibrationThread(LPVOID arg);
static void UpdateTimeEachSecond(void);
static void ResetCounterSamples(unsigned long long fileTime,
long long perfCounter, long long perfFreq);
static long long AccumulateSample(long long perfCounter,
unsigned long long fileTime);
static void NativeScaleTime(Tcl_Time* timebuf,
void *clientData);
static long long NativeGetMicroseconds(void);
static void NativeGetTime(Tcl_Time* timebuf,
void *clientData);
/*
* TIP #233 (Virtualized Time): Data for the time hooks, if any.
*/
Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime;
Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
void *tclTimeClientData = NULL;
/*
* Inlined version of Tcl_GetTime.
*/
static inline void
GetTime(
Tcl_Time *timePtr)
{
tclGetTimeProcPtr(timePtr, tclTimeClientData);
}
static inline int
IsTimeNative(void)
{
return tclGetTimeProcPtr == NativeGetTime;
}
/*
*----------------------------------------------------------------------
*
* TclpGetSeconds --
*
* This procedure returns the number of seconds from the epoch. On most
|
| ︙ | ︙ | |||
138 139 140 141 142 143 144 |
{
long long usecSincePosixEpoch;
/*
* Try to use high resolution timer
*/
| | < < < | | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
{
long long usecSincePosixEpoch;
/*
* Try to use high resolution timer
*/
if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
return usecSincePosixEpoch / 1000000;
} else {
Tcl_Time t;
GetTime(&t);
return (unsigned long long)t.sec;
}
}
/*
*----------------------------------------------------------------------
*
* TclpGetClicks --
|
| ︙ | ︙ | |||
179 180 181 182 183 184 185 |
{
long long usecSincePosixEpoch;
/*
* Try to use high resolution timer.
*/
| | | | > > > > > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
{
long long usecSincePosixEpoch;
/*
* Try to use high resolution timer.
*/
if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
return (Tcl_WideUInt) usecSincePosixEpoch;
} else {
/*
* Use the Tcl_GetTime abstraction to get the time in microseconds, as
* nearly as we can, and return it.
*/
Tcl_Time now; /* Current Tcl time */
GetTime(&now);
return ((unsigned long long)(now.sec)*1000000ULL) +
(unsigned long long)(now.usec);
}
}
/*
*----------------------------------------------------------------------
*
* TclpGetWideClicks --
|
| ︙ | ︙ | |||
241 242 243 244 245 246 247 |
if (wideClick.perfCounter) {
if (QueryPerformanceCounter(&curCounter)) {
return (long long)curCounter.QuadPart;
}
/* fallback using microseconds */
wideClick.perfCounter = 0;
wideClick.microsecsScale = 1;
| | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
if (wideClick.perfCounter) {
if (QueryPerformanceCounter(&curCounter)) {
return (long long)curCounter.QuadPart;
}
/* fallback using microseconds */
wideClick.perfCounter = 0;
wideClick.microsecsScale = 1;
return TclpGetMicroseconds();
} else {
return TclpGetMicroseconds();
}
}
/*
*----------------------------------------------------------------------
*
* TclpWideClickInMicrosec --
|
| ︙ | ︙ | |||
277 278 279 280 281 282 283 |
}
return wideClick.microsecsScale;
}
/*
*----------------------------------------------------------------------
*
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | > < < < < | < < | | < < < < | | | | | < < < | < < < < < < | < < < | < < < < < < < < | < < < > | < < < < | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
}
return wideClick.microsecsScale;
}
/*
*----------------------------------------------------------------------
*
* TclpGetMicroseconds --
*
* This procedure returns a WideInt value that represents the highest
* resolution clock in microseconds available on the system.
*
* Results:
* Number of microseconds (from the epoch).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
long long
TclpGetMicroseconds(void)
{
long long usecSincePosixEpoch;
/*
* Try to use high resolution timer.
*/
if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
return usecSincePosixEpoch;
} else {
/*
* Use the Tcl_GetTime abstraction to get the time in microseconds, as
* nearly as we can, and return it.
*/
Tcl_Time now;
GetTime(&now);
return now.sec * 1000000 + now.usec;
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetTime --
*
* Gets the current system time in seconds and microseconds since the
* beginning of the epoch: 00:00 UCT, January 1, 1970.
*
* Results:
* Returns the current time in timePtr.
*
* Side effects:
* On the first call, initializes a set of static variables to keep track
* of the base value of the performance counter, the corresponding wall
* clock (obtained through ftime) and the frequency of the performance
* counter. Also spins a thread whose function is to wake up periodically
* and monitor these values, adjusting them as necessary to correct for
* drift in the performance counter's oscillator.
*
*----------------------------------------------------------------------
*/
void
Tcl_GetTime(
Tcl_Time *timePtr) /* Location to store time information. */
{
long long usecSincePosixEpoch;
/*
* Try to use high resolution timer.
*/
if (IsTimeNative() && (usecSincePosixEpoch = NativeGetMicroseconds())) {
timePtr->sec = usecSincePosixEpoch / 1000000;
timePtr->usec = (long)(usecSincePosixEpoch % 1000000);
} else {
GetTime(timePtr);
}
}
/*
*----------------------------------------------------------------------
*
* NativeScaleTime --
*
* TIP #233: Scale from virtual time to the real-time. For native scaling
* the relationship is 1:1 and nothing has to be done.
*
* Results:
* Scales the time in timePtr.
*
* Side effects:
* See above.
*
*----------------------------------------------------------------------
*/
static void
NativeScaleTime(
TCL_UNUSED(Tcl_Time *),
TCL_UNUSED(void *))
{
/*
* Native scale is 1:1. Nothing is done.
*/
}
/*
*----------------------------------------------------------------------
*
* IsPerfCounterAvailable --
*
|
| ︙ | ︙ | |||
612 613 614 615 616 617 618 |
return 0;
}
/*
*----------------------------------------------------------------------
*
| | | | < < < < < | | | | > | 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 |
return 0;
}
/*
*----------------------------------------------------------------------
*
* NativeGetTime --
*
* TIP #233: Gets the current system time in seconds and microseconds
* since the beginning of the epoch: 00:00 UCT, January 1, 1970.
*
* Results:
* Returns the current time in timePtr.
*
* Side effects:
* See NativeGetMicroseconds for more information.
*
*----------------------------------------------------------------------
*/
static void
NativeGetTime(
Tcl_Time *timePtr,
TCL_UNUSED(void *))
{
long long usecSincePosixEpoch;
/*
* Try to use high resolution timer.
*/
|
| ︙ | ︙ | |||
1043 1044 1045 1046 1047 1048 1049 |
timeInfo.perfCounterSample[i] = perfCounter;
timeInfo.fileTimeSample[i] = fileTime;
perfCounter -= perfFreq;
fileTime -= 10000000;
}
timeInfo.sampleNo = 0;
}
| | | 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 |
timeInfo.perfCounterSample[i] = perfCounter;
timeInfo.fileTimeSample[i] = fileTime;
perfCounter -= perfFreq;
fileTime -= 10000000;
}
timeInfo.sampleNo = 0;
}
/*
*----------------------------------------------------------------------
*
* AccumulateSample --
*
* Updates the circular buffer of performance counter and system time
* samples with a new data point.
|
| ︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | * (1) The performance counter may have jumped. * (2) The system clock may have been reset. * * In either case, we'll need to reinitialize the circular buffer with samples * relative to the current system time and the NOMINAL performance frequency * (not the actual, because the actual has probably run slow in the first * case). | | | < | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 |
* (1) The performance counter may have jumped.
* (2) The system clock may have been reset.
*
* In either case, we'll need to reinitialize the circular buffer with samples
* relative to the current system time and the NOMINAL performance frequency
* (not the actual, because the actual has probably run slow in the first
* case).
*/
static long long
AccumulateSample(
long long perfCounter,
unsigned long long fileTime)
{
unsigned long long workFTSample;
/* File time sample being removed from or
|
| ︙ | ︙ | |||
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 |
if (++timeInfo.sampleNo >= SAMPLES) {
timeInfo.sampleNo = 0;
}
return estFreq;
}
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 |
if (++timeInfo.sampleNo >= SAMPLES) {
timeInfo.sampleNo = 0;
}
return estFreq;
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetTimeProc --
*
* TIP #233 (Virtualized Time): Registers two handlers for the
* virtualization of Tcl's access to time information.
*
* Results:
* None.
*
* Side effects:
* Remembers the handlers, alters core behaviour.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetTimeProc(
Tcl_GetTimeProc *getProc,
Tcl_ScaleTimeProc *scaleProc,
void *clientData)
{
tclGetTimeProcPtr = getProc;
tclScaleTimeProcPtr = scaleProc;
tclTimeClientData = clientData;
}
/*
*----------------------------------------------------------------------
*
* Tcl_QueryTimeProc --
*
* TIP #233 (Virtualized Time): Query which time handlers are registered.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Tcl_QueryTimeProc(
Tcl_GetTimeProc **getProc,
Tcl_ScaleTimeProc **scaleProc,
void **clientData)
{
if (getProc) {
*getProc = tclGetTimeProcPtr;
}
if (scaleProc) {
*scaleProc = tclScaleTimeProcPtr;
}
if (clientData) {
*clientData = tclTimeClientData;
}
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
|
Changes to win/tclsh.exe.manifest.in.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 |
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
| | > > > > > > | | | < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
uiAccess="false"
/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
</application>
</compatibility>
<asmv3:application>
<asmv3:windowsSettings
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
|
| ︙ | ︙ |
Changes to win/tclsh.ico.
cannot compute difference between binary files
Changes to win/tclsh.rc.
1 2 3 4 5 6 | // // Version Resource Script // #include <winver.h> #include <tcl.h> | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 | // // Version Resource Script // #include <winver.h> #include <tcl.h> // // build-up the name suffix that defines the type of build this is. // #if STATIC_BUILD #define SUFFIX_STATIC "s" #else |
| ︙ | ︙ | |||
27 28 29 30 31 32 33 | LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */ VS_VERSION_INFO VERSIONINFO FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL FILEFLAGSMASK 0x3fL | | | | | | | | | | | | > > > > > > > > > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */
VS_VERSION_INFO VERSIONINFO
FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL
PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL
FILEFLAGSMASK 0x3fL
#ifdef DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "FileDescription", "Tclsh Application\0"
VALUE "OriginalFilename", "tclsh" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) SUFFIX ".exe\0"
VALUE "FileVersion", TCL_PATCH_LEVEL
VALUE "LegalCopyright", "Copyright \251 1987-2022 Regents of the University of California and other parties\0"
VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
VALUE "ProductVersion", TCL_PATCH_LEVEL
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
//
// Icon
//
tclsh ICON DISCARDABLE "tclsh.ico"
//
// This is needed for Windows 8.1 onwards.
//
#ifndef RT_MANIFEST
#define RT_MANIFEST 24
#endif
#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#endif
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "tclsh.exe.manifest"
|
Changes to win/tcltest.rc.
1 2 3 4 5 6 | // // Version Resource Script // #include <winver.h> #include <tcl.h> | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 | // // Version Resource Script // #include <winver.h> #include <tcl.h> // // build-up the name suffix that defines the type of build this is. // #if STATIC_BUILD #define SUFFIX_STATIC "s" #else |
| ︙ | ︙ | |||
27 28 29 30 31 32 33 | LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */ VS_VERSION_INFO VERSIONINFO FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL FILEFLAGSMASK 0x3fL | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */ VS_VERSION_INFO VERSIONINFO FILEVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL PRODUCTVERSION TCL_MAJOR_VERSION,TCL_MINOR_VERSION,TCL_RELEASE_LEVEL,TCL_RELEASE_SERIAL FILEFLAGSMASK 0x3fL #ifdef DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L |
| ︙ | ︙ | |||
60 61 62 63 64 65 66 67 | // // Icon // tclsh ICON DISCARDABLE "tclsh.ico" CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "tclsh.exe.manifest" | > > > > > > > > > > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | // // Icon // tclsh ICON DISCARDABLE "tclsh.ico" // // This is needed for Windows 8.1 onwards. // #ifndef RT_MANIFEST #define RT_MANIFEST 24 #endif #ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID #define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 #endif CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "tclsh.exe.manifest" |
Changes to win/vctool.bat.
| ︙ | ︙ | |||
128 129 130 131 132 133 134 | ) :done endlocal exit /b 0 :error | < | < | < < < < | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
)
:done
endlocal
exit /b 0
:error
endlocal
exit /b 1
:: call :runmake dir opts
:runmake
if "%debug%" == "" (
nmake /s /f makefile.vc OUT_DIR=%currentDir%\vc-%ARCH%-%1 TMP_DIR=%currentDir%\vc-%ARCH%-%1\objs OPTS=pdbs,%2 INSTALLDIR=%INSTROOT%-%1 %TARGETS% && goto error
) else (
nmake /s /f makefile.vc OUT_DIR=%currentDir%\vc-%ARCH%-%1-debug TMP_DIR=%currentDir%\vc-%ARCH%-%1-debug\objs OPTS=pdbs,%2 cdebug="-Zi -Od" INSTALLDIR=%INSTROOT%-%1-debug %TARGETS% && goto error
)
goto eof
:help
echo.
echo Usage: %0 arg ...
echo.
echo where each arg may be either a build config or a target or "debug".
echo.
|
| ︙ | ︙ |
Added win/x86_64-w64-mingw32-nmakehlp.exe.
cannot compute difference between binary files