Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f76c6ff3da | ||
|
|
596fd6687e | ||
|
|
35ca781f6c | ||
|
|
28ac0c5353 |
@@ -3,17 +3,13 @@ compat/zlib/contrib/vstudio/readme.txt
|
||||
compat/zlib/contrib/vstudio/*/zlib.rc
|
||||
compat/zlib/win32/*.txt
|
||||
compat/zlib/win64/*.txt
|
||||
libtommath/*.dsp
|
||||
libtommath/*.sln
|
||||
libtommath/*.vcproj
|
||||
tools/tcl.hpj.in
|
||||
tools/tcl.wse.in
|
||||
win/buildall.vc.bat
|
||||
win/coffbase.txt
|
||||
win/makefile.bc
|
||||
win/makefile.vc
|
||||
win/rules.vc
|
||||
win/rules-ext.vc
|
||||
win/targets.vc
|
||||
win/tcl.dsp
|
||||
win/tcl.dsw
|
||||
win/tcl.hpj.in
|
||||
@@ -2,6 +2,7 @@ tools/tcl.hpj.in
|
||||
tools/tcl.wse.in
|
||||
win/buildall.vc.bat
|
||||
win/coffbase.txt
|
||||
win/makefile.bc
|
||||
win/makefile.vc
|
||||
win/rules.vc
|
||||
win/tcl.dsp
|
||||
|
||||
@@ -18,19 +18,14 @@
|
||||
*/tclsh*
|
||||
*/tcltest*
|
||||
*/versions.vc
|
||||
*/version.vc
|
||||
*/libtcl.vfs
|
||||
*/libtcl_*.zip
|
||||
html
|
||||
libtommath/bn.ilg
|
||||
libtommath/bn.ind
|
||||
libtommath/pretty.build
|
||||
libtommath/tommath.src
|
||||
libtommath/*.log
|
||||
libtommath/*.pdf
|
||||
libtommath/*.pl
|
||||
libtommath/*.sh
|
||||
libtommath/doc/*
|
||||
libtommath/tombc/*
|
||||
libtommath/pre_gen/*
|
||||
libtommath/pics/*
|
||||
@@ -45,9 +40,7 @@ unix/dltest.marker
|
||||
unix/tcl.pc
|
||||
unix/tclIndex
|
||||
unix/pkgs/*
|
||||
win/Debug*
|
||||
win/Release*
|
||||
win/Debug_VC*
|
||||
win/Release_VC*
|
||||
win/pkgs/*
|
||||
win/coffbase.txt
|
||||
win/tcl.hpj
|
||||
win/nmhlp-out.txt
|
||||
win/tcl.hpj
|
||||
@@ -1,3 +0,0 @@
|
||||
Important Note
|
||||
==========
|
||||
Please do not file issues with Tcl on Github. They are unlikely to be noticed in a timely fashion. Tcl issues are hosted in the [tcl fossil repository on core.tcl.tk](https://core.tcl.tk/tcl/tktnew); please post them there.
|
||||
@@ -1,3 +0,0 @@
|
||||
Important Note
|
||||
==========
|
||||
Please do not file pull requests with Tcl on Github. They are unlikely to be noticed in a timely fashion. Tcl issues (including patches) are hosted in the [tcl fossil repository on core.tcl.tk](https://core.tcl.tk/tcl/tktnew); please post them there.
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>tcl8</name>
|
||||
<name>tcl8.7</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
|
||||
-297
@@ -1,297 +0,0 @@
|
||||
sudo: false
|
||||
language: c
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
env:
|
||||
- CFGOPT=--disable-shared
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
env:
|
||||
- CFGOPT=--disable-shared
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc-4.9
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.9
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc-5
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc-6
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-6
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc-7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc-7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- CFGOPT=CFLAGS=-DTCL_UTF_MAX=6
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc-7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- CFGOPT=CFLAGS=-DTCL_UTF_MAX=3
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: gcc-7
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- CFGOPT=CFLAGS=-DTCL_NO_DEPRECATED=1
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
env:
|
||||
- BUILD_DIR=unix
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
env:
|
||||
- BUILD_DIR=macosx
|
||||
- NO_DIRECT_CONFIGURE=1
|
||||
- os: osx
|
||||
osx_image: xcode9
|
||||
env:
|
||||
- BUILD_DIR=macosx
|
||||
- NO_DIRECT_CONFIGURE=1
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
env:
|
||||
- BUILD_DIR=macosx
|
||||
- NO_DIRECT_CONFIGURE=1
|
||||
### C builds not currently supported on Windows instances
|
||||
# - os: windows
|
||||
# env:
|
||||
# - BUILD_DIR=win
|
||||
### ... so proxy with a Mingw cross-compile
|
||||
# Test with mingw-w64 (32 bit)
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: i686-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-i686
|
||||
- gcc-mingw-w64-i686
|
||||
- gcc-mingw-w64
|
||||
- gcc-multilib
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT=--host=i686-w64-mingw32
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: i686-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-i686
|
||||
- gcc-mingw-w64-i686
|
||||
- gcc-mingw-w64
|
||||
- gcc-multilib
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=i686-w64-mingw32 --disable-shared"
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: i686-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-i686
|
||||
- gcc-mingw-w64-i686
|
||||
- gcc-mingw-w64
|
||||
- gcc-multilib
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=i686-w64-mingw32 CFLAGS=-DTCL_UTF_MAX=6"
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: i686-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-i686
|
||||
- gcc-mingw-w64-i686
|
||||
- gcc-mingw-w64
|
||||
- gcc-multilib
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=i686-w64-mingw32 CFLAGS=-DTCL_UTF_MAX=3"
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: i686-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-i686
|
||||
- gcc-mingw-w64-i686
|
||||
- gcc-mingw-w64
|
||||
- gcc-multilib
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=i686-w64-mingw32 CFLAGS=-DTCL_NO_DEPRECATED=1"
|
||||
- NO_DIRECT_TEST=1
|
||||
# Test with mingw-w64 (64 bit)
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: x86_64-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-x86-64
|
||||
- gcc-mingw-w64-x86-64
|
||||
- gcc-mingw-w64
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=x86_64-w64-mingw32 --enable-64bit"
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: x86_64-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-x86-64
|
||||
- gcc-mingw-w64-x86-64
|
||||
- gcc-mingw-w64
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=x86_64-w64-mingw32 --enable-64bit --disable-shared"
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: x86_64-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-x86-64
|
||||
- gcc-mingw-w64-x86-64
|
||||
- gcc-mingw-w64
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=x86_64-w64-mingw32 --enable-64bit CFLAGS=-DTCL_UTF_MAX=6"
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: x86_64-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-x86-64
|
||||
- gcc-mingw-w64-x86-64
|
||||
- gcc-mingw-w64
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=x86_64-w64-mingw32 --enable-64bit CFLAGS=-DTCL_UTF_MAX=3"
|
||||
- NO_DIRECT_TEST=1
|
||||
- os: linux
|
||||
dist: xenial
|
||||
compiler: x86_64-w64-mingw32-gcc
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-mingw-w64-base
|
||||
- binutils-mingw-w64-x86-64
|
||||
- gcc-mingw-w64-x86-64
|
||||
- gcc-mingw-w64
|
||||
- wine
|
||||
env:
|
||||
- BUILD_DIR=win
|
||||
- CFGOPT="--host=x86_64-w64-mingw32 --enable-64bit CFLAGS=-DTCL_NO_DEPRECATED=1"
|
||||
- NO_DIRECT_TEST=1
|
||||
before_install:
|
||||
- export ERROR_ON_FAILURES=1
|
||||
- cd ${BUILD_DIR}
|
||||
install:
|
||||
- test -n "$NO_DIRECT_CONFIGURE" || ./configure ${CFGOPT}
|
||||
script:
|
||||
- make
|
||||
# The styles=develop avoids some weird problems on OSX
|
||||
- test -n "$NO_DIRECT_TEST" || make test styles=develop
|
||||
@@ -1,6 +1,6 @@
|
||||
A NOTE ON THE CHANGELOG:
|
||||
Starting in early 2011, Tcl source code has been under the management of
|
||||
fossil, hosted at https://core.tcl-lang.org/tcl/ . Fossil presents a "Timeline"
|
||||
fossil, hosted at http://core.tcl.tk/tcl/ . Fossil presents a "Timeline"
|
||||
view of changes made that is superior in every way to a hand edited log file.
|
||||
Because of this, many Tcl developers are now out of the habit of maintaining
|
||||
this log file. You may still find useful things in it, but the Timeline is
|
||||
|
||||
+1
-1
@@ -1426,7 +1426,7 @@
|
||||
initialization assumptions of the TIP 280 code in CompileWord().
|
||||
|
||||
* generic/tclCompExpr.c: Suppress the attempt to convert to
|
||||
numeric when pre-compiling a constant expression indicates an error.
|
||||
numeric when pre-compiling a constant expresion indicates an error.
|
||||
|
||||
2007-08-22 Miguel Sofer <msofer@users.sf.net>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
README: Tcl
|
||||
This is the Tcl 8.7a2 source distribution.
|
||||
This is the Tcl 8.7a0 source distribution.
|
||||
http://sourceforge.net/projects/tcl/files/Tcl/
|
||||
You can get any source release of Tcl from the URL above.
|
||||
|
||||
@@ -29,7 +29,7 @@ Tcl is maintained, enhanced, and distributed freely by the Tcl community.
|
||||
Source code development and tracking of bug reports and feature requests
|
||||
takes place at:
|
||||
|
||||
http://core.tcl-lang.org/
|
||||
http://core.tcl.tk/
|
||||
|
||||
Tcl/Tk release and mailing list services are hosted by SourceForge:
|
||||
|
||||
@@ -37,7 +37,7 @@ Tcl/Tk release and mailing list services are hosted by SourceForge:
|
||||
|
||||
with the Tcl Developer Xchange hosted at:
|
||||
|
||||
http://www.tcl-lang.org/
|
||||
http://www.tcl.tk/
|
||||
|
||||
Tcl is a freely available open source package. You can do virtually
|
||||
anything you like with it, such as modifying it, redistributing it,
|
||||
@@ -49,21 +49,21 @@ and selling it either in whole or in part. See the file
|
||||
|
||||
Extensive documentation is available at our website.
|
||||
The home page for this release, including new features, is
|
||||
http://www.tcl-lang.org/software/tcltk/8.7.html
|
||||
http://www.tcl.tk/software/tcltk/8.7.html
|
||||
|
||||
Detailed release notes can be found at the file distributions page
|
||||
by clicking on the relevant version.
|
||||
http://sourceforge.net/projects/tcl/files/Tcl/
|
||||
|
||||
Information about Tcl itself can be found at
|
||||
http://www.tcl-lang.org/about/
|
||||
http://www.tcl.tk/about/
|
||||
|
||||
There have been many Tcl books on the market. Many are mentioned in the Wiki:
|
||||
http://wiki.tcl-lang.org/_/ref?N=25206
|
||||
http://wiki.tcl.tk/_/ref?N=25206
|
||||
|
||||
To view the complete set of reference manual entries for Tcl 8.7 online,
|
||||
visit the URL:
|
||||
http://www.tcl-lang.org/man/tcl8.7/
|
||||
http://www.tcl.tk/man/tcl8.7/
|
||||
|
||||
2a. Unix Documentation
|
||||
----------------------
|
||||
@@ -101,7 +101,7 @@ There are brief notes in the unix/README, win/README, and macosx/README about
|
||||
compiling on these different platforms. There is additional information
|
||||
about building Tcl from sources at
|
||||
|
||||
http://www.tcl-lang.org/doc/howto/compile.html
|
||||
http://www.tcl.tk/doc/howto/compile.html
|
||||
|
||||
4. Development tools
|
||||
---------------------------
|
||||
@@ -127,7 +127,7 @@ see the "Support and bug fixes" section below.
|
||||
|
||||
A Wiki-based open community site covering all aspects of Tcl/Tk is at:
|
||||
|
||||
http://wiki.tcl-lang.org/
|
||||
http://wiki.tcl.tk/
|
||||
|
||||
It is dedicated to the Tcl programming language and its extensions. A
|
||||
wealth of useful information can be found there. It contains code
|
||||
@@ -153,7 +153,7 @@ We are very interested in receiving bug reports, patches, and suggestions
|
||||
for improvements. We prefer that you send this information to us as
|
||||
tickets entered into our tracker at:
|
||||
|
||||
http://core.tcl-lang.org/tcl/reportlist
|
||||
http://core.tcl.tk/tcl/reportlist
|
||||
|
||||
We will log and follow-up on each bug, although we cannot promise a
|
||||
specific turn-around time. Enhancements may take longer and may not happen
|
||||
@@ -169,13 +169,13 @@ questions for which no one else is likely to know the answer. In addition,
|
||||
see the following Web site for links to other organizations that offer
|
||||
Tcl/Tk training:
|
||||
|
||||
http://wiki.tcl-lang.org/training
|
||||
http://wiki.tcl.tk/training
|
||||
|
||||
9. Tracking Development
|
||||
-----------------------
|
||||
|
||||
Tcl is developed in public. To keep an eye on how Tcl is changing, see
|
||||
http://core.tcl-lang.org/
|
||||
http://core.tcl.tk/
|
||||
|
||||
10. Thank You
|
||||
-------------
|
||||
|
||||
@@ -8624,329 +8624,3 @@ improvements to regexp engine from Postgres (lane,porter,fellows,seltenreich)
|
||||
2016-02-22 (bug)[9b4702] [info exists env(missing)] kills trace (nijtmans)
|
||||
|
||||
--- Released 8.6.5, February 29, 2016 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
2016-03-01 (bug)[803042] mem leak due to reference cycle (porter)
|
||||
|
||||
2016-03-08 (bug)[bbc304] reflected watch race condition (porter)
|
||||
|
||||
2016-03-17 (bug)[fadc99] compile-5.3 (rodriguez,porter)
|
||||
|
||||
2016-03-17 (enhancement)[1a25fd] compile [variable ${ns}::v] (porter)
|
||||
|
||||
2016-03-20 (bug)[1af8de] crash in compiled [string replace] (harder,fellows)
|
||||
|
||||
2016-03-21 (bug)[d30718] segv in notifier finalize (hirofumi,nijtmans)
|
||||
|
||||
2016-03-23 (enhancement)[7d0db7] parallel make (yarda,nijtmans)
|
||||
|
||||
2016-03-23 [f12535] enable test bindings customization (vogel,nijtmans)
|
||||
|
||||
2016-04-04 (bug)[47ac84] compiled [lreplace] fixes (aspect,ferrieux,fellows)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-04-08 (bug)[866368] RE \w includes 'Punctuation Connector' (nijtmans)
|
||||
|
||||
2016-04-08 (bug)[2538f3] Win crash Tcl_OpenTcpServer() (griffin)
|
||||
|
||||
2016-04-10 [07d13d] Restore TclBlend support lost in 8.6.1 (buratti)
|
||||
|
||||
2016-05-13 (bug)[3154ea] Mem corruption in assembler exceptions (tkob,kenny)
|
||||
|
||||
2016-05-13 (bug) registry package support any Unicode env (nijtmans)
|
||||
=> registry 1.3.2
|
||||
|
||||
2016-05-21 (bug)[f7d4e] [namespace delete] performance (fellows)
|
||||
|
||||
2016-06-02 (TIP 447) execution time verbosity option (cerutti)
|
||||
=> tcltest 2.4.0
|
||||
|
||||
2016-06-16 (bug)[16828b] crash due to [vwait] trace undo fail (dah,porter)
|
||||
|
||||
2016-06-16 (enhancement)[4b61af] good [info frame] from more cases (beric)
|
||||
|
||||
2016-06-21 (bug)[c383eb] crash in [glob -path a] (oehlmann,porter)
|
||||
|
||||
2016-06-21 (update) Update Unicode data to 9.0 (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-06-22 (bug)[16896d] Tcl_DString tolerate append to self. (dah,porter)
|
||||
|
||||
2016-06-23 (bug)[d55322] crash in [dict update] (yorick,fellows)
|
||||
|
||||
2016-06-27 (bug)[dd260a] crash in [chan configure -dictionary] (madden,aspect)
|
||||
|
||||
2016-07-02 (bug)[f961d7] usage message with parameters with spaces (porter)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-07-02 (enhancement)[09fabc] Sort order of -relateddir (lanam)
|
||||
|
||||
2016-07-07 (bug)[5d7ca0] Win: [file executable] for .cmd and .ps1 (nadkarni)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-07-08 (bug)[a47641] [file normalize] & Windows junctions (nadkarni)
|
||||
|
||||
2016-07-09 [ae61a6] [file] handling of Win hardcoded names (CON) (nadkarni)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-07-09 [3613671] [file owned] (more) useful on Win (nadkarni)
|
||||
|
||||
2016-07-09 (bug)[1493a4] [namespace upvar] use of resolvers (beric,fellows)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-07-10 (bug)[da340d] integer division in clock math (nadkarni)
|
||||
|
||||
2016-07-20 tzdata updated to Olson's tzdata2016f (venkat)
|
||||
|
||||
--- Released 8.6.6, July 27, 2016 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
2016-09-07 (bug)[c09edf] Bad caching with custom resolver (neumann,nijtmans)
|
||||
|
||||
2016-09-07 (bug)[4dbdd9] Memleak in test var-8.3 (mr_calvin,porter)
|
||||
|
||||
2016-10-03 (bug)[2bf561] Allow empty command as alias target (yorick,nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-10-04 (bug)[4d5ae7] Crash in async connects host no address (gahr,fellows)
|
||||
|
||||
2016-10-08 (bug)[838e99] treat application/xml as text (gahr,fellows)
|
||||
=> http 2.8.10
|
||||
|
||||
2016-10-11 (bug)[3cc1d9] Thread finalization crash in zippy (neumann)
|
||||
|
||||
2016-10-12 (bug)[be003d] Fix [scan 0x1 %b], [scan 0x1 %o] (porter)
|
||||
|
||||
2016-10-14 (bug)[eb6b68] Fix stringComp-14.5 (porter)
|
||||
|
||||
2016-10-30 (bug)[b26e38] Fix zlib-7.8 (fellows)
|
||||
|
||||
2016-10-30 (bug)[1ae129] Fix memleak in [history] destruction (fellows)
|
||||
|
||||
2016-11-04 (feature) Provisional Tcl 9 support in msgcat and tcltest (nijtmans)
|
||||
=> msgcat 1.6.1
|
||||
=> tcltest 2.4.1
|
||||
|
||||
2016-11-04 (bug)[824752] Crash in Tcl_ListObjReplace() (gahr,porter)
|
||||
|
||||
2016-11-11 (bug)[79614f] invalidate VFS mounts on sytem encoding change (yorick)
|
||||
|
||||
2016-11-14 OSX: End panic() as legacy support macro; system conflicts (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-11-15 (bug) TclOO fix stops crash mixing Itcl and snit (fellows)
|
||||
|
||||
2016-11-17 (update) Reconcile libtommath updates; purge unused files (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-01-09 (bug)[b87ad7] Repair drifts in timer clock (sebres)
|
||||
|
||||
2017-01-17 (update) => zlib 1.2.11 (nijtmans)
|
||||
|
||||
2017-01-31 (bug)[39f630] Revise Tcl_LinkVar to tolerate some prefixes (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-02-01 (bug)[d0f7ba] Improper NAN optimization. expr-22.1[01] (aspect)
|
||||
|
||||
2017-02-26 (bug)[25842c] zlib stream finalization (aspect)
|
||||
|
||||
2017-03-07 (deprecate) Remove unmaintained makefile.bc file (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-03-14 (enhancement) [clock] and [encoding] are now ensembles (kenny)
|
||||
|
||||
2017-03-15 (enhancement) several [clock] subcommands bytecoded (kenny)
|
||||
|
||||
2017-03-23 tzdata updated to Olson's tzdata2017b (jima)
|
||||
|
||||
2017-03-29 (bug)[900cb0] Fix OO unexport introspection (napier)
|
||||
|
||||
2017-04-12 (bug)[42202b] Nesting imbalance in coro injection (nadkarni,sebres)
|
||||
|
||||
2017-04-18 (bug)[bc4322] http package support for safe interps (nash,nijtmans)
|
||||
|
||||
2017-04-28 (bug)[f34cf8] [file join a //b] => /b (neumann,porter)
|
||||
|
||||
2017-05-01 (bug)[8bd13f] Windows threads and pipes (sebres,nijtmans)
|
||||
|
||||
2017-05-01 (bug)[f9fe90] [file join //a b] EIAS violation (aspect,porter)
|
||||
|
||||
2017-05-04 (bug) Make test filesystem-1.52 pass on Windows (nijtmans)
|
||||
|
||||
2017-05-05 (bug)[601522] [binary] field spec overflow -> segfault (porter)
|
||||
|
||||
2017-05-08 (bug)[6ca52a] http memleak handling keep-alive (aspect,nijtmans)
|
||||
=> http 2.8.11
|
||||
|
||||
2017-05-29 (bug)[a3fb33] crash in [lsort] on long lists (sebres)
|
||||
|
||||
2017-06-05 (bug)[67aa9a] Tcl_UtfToUniChar() revised handling invalid UTF-8 (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-06-08 (bug)[2738427] Tcl_NumUtfChars() corner case utf-4.9 (nijtmans)
|
||||
|
||||
2017-06-22 (update) Update Unicode data to 10.0 (nijtmans)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2017-06-22 (TIP 473) Let [oo::copy] specify target namespace (fellows)
|
||||
|
||||
2017-06-26 (bug)[46f801] Repair autoloader fragility (porter)
|
||||
|
||||
2017-07-06 (bug)[adb198] Plug memleak in TclJoinPath (sebres,porter)
|
||||
|
||||
2017-07-17 (bug)[fb2208] Repeatable tclIndex generation (wiedemann,nijtmans)
|
||||
|
||||
--- Released 8.6.7, August 9, 2017 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
2017-08-10 [array names -regexp] supports backrefs (goth)
|
||||
|
||||
2017-08-10 Fix gcc build failures due to #pragma placement (cassoff,fellows)
|
||||
|
||||
2017-08-29 (bug)[b50fb2] exec redir append stdout and stderr to file (coulter)
|
||||
|
||||
2017-08-31 (bug)[2a9465] http state 100 continue handling broken (oehlmann)
|
||||
=> http 2.8.12
|
||||
|
||||
2017-09-02 (bug)[0e4d88] replace command, delete trace kills namespace (porter)
|
||||
|
||||
2017-10-19 (bug)[1a5655] [info * methods] includes mixins (fellows)
|
||||
|
||||
2017-10-23 tzdata updated to Olson's tzdata2017c (jima)
|
||||
|
||||
2017-10-24 (bug)[fc1409] segfault in method cloning, oo-15.15 (coulter,fellows)
|
||||
|
||||
2017-11-03 (bug)[6f2f83] More robust [load] for ReactOS (werner)
|
||||
|
||||
2017-11-08 (bug)[3298012] Stop crash when hash tables overflow 32 bits (porter)
|
||||
|
||||
2017-11-14 (bug)[5d6de6] Close failing case of [package prefer stable] (kupries)
|
||||
|
||||
2017-11-17 (bug)[fab924] Fix misleading [load] message on Windows (oehlmann)
|
||||
|
||||
2017-12-05 (bug)[4f6a1e] Crash when ensemble map and list are same (sebres)
|
||||
|
||||
2017-12-06 (bug)[ce3a21] file normalize failure when tail is empty (porter)
|
||||
|
||||
2017-12-08 (new)[TIP 477] nmake build system reform (nadkarni)
|
||||
|
||||
2017-12-19 (bug)[586e71] EvalObjv exception handling at level #0 (sebres,porter)
|
||||
|
||||
--- Released 8.6.8, December 22, 2017 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
2018-02-11 (enhance) stop blocking conversion of object to/from class (coulter)
|
||||
|
||||
2018-02-12 (enhance) NR-enable [package require] (coulter)
|
||||
|
||||
2018-02-14 (bug)[9fd5c6] crash in object deletion, test oo-11.5 (coulter)
|
||||
|
||||
2018-02-14 (bug)[3c32a3] crash deleting object with class mixed in (coulter)
|
||||
|
||||
2018-02-15 (platform) stop using -lieee, removed from glibc-2.27 (porter)
|
||||
***POTENTIAL INCOMPATIBILITY for math programs that embed Tcl***
|
||||
|
||||
2018-02-23 (bug)[8e6a9a] bad binary [string match], test string-11.55 (porter)
|
||||
|
||||
2018-03-05 (bug)[1873ea] repair multi-thread std channel init (sebres)
|
||||
|
||||
2018-03-09 (bug)[db36fa] broken bytecode for index values (porter)
|
||||
|
||||
2018-03-13 (bug) broken compiled [string replace], test string-14.19 (porter)
|
||||
|
||||
2018-03-14 (bug) [string trim*] engine crashed on invalid UTF (sebres)
|
||||
|
||||
2018-04-17 (bug) missing trace in compiled [array set], test var-20.11 (porter)
|
||||
|
||||
2018-04-22 (bug)[46a241] crash in unset array with search, var-13.[23] (goth)
|
||||
|
||||
2018-04-30 (bug)[27b682] race made [file delete] raise "no such file" (sebres)
|
||||
|
||||
2018-06-04 (bug)[925643] 32/64 cleanup of filesystem DIR operations (sebres)
|
||||
|
||||
2018-06-18 (bug) leaks in TclSetEnv and env cache (coulter)
|
||||
|
||||
2018-06-24 (bug)[3592747] [yieldto] dying namespace, tailcall-14.1 (coulter)
|
||||
|
||||
2018-07-09 (bug)[270f78] race in [file mkdir] (sebres)
|
||||
|
||||
2018-07-12 (bug)[3f7af0] [file delete] raised "permission denied" (sebres)
|
||||
|
||||
2018-07-26 (bug)[d051b7] overflow crash in [format] (sebres)
|
||||
|
||||
2018-08-29 revised quoting of [exec] args in generated command line (sebres)
|
||||
***POTENTIAL INCOMPATIBILITY***
|
||||
|
||||
2018-09-20 HTTP Keep-Alive with pipelined requests (nash)
|
||||
=> http 2.9.0
|
||||
|
||||
2018-09-27 (new)[TIP 505] [lreplace] accepts all out of range indices (porter)
|
||||
|
||||
2018-10-04 (bug) Prevent crash from NULL keyName (nijtmans)
|
||||
=> registry 1.3.3
|
||||
|
||||
2018-10-26 (enhance) advance dde version (nijtmans)
|
||||
=> dde 1.4.1
|
||||
|
||||
2018-10-27 tzdata updated to Olson's tzdata2018g (jima)
|
||||
|
||||
2018-10-29 Update tcltest package for Travis support (fellows)
|
||||
=> tcltest 2.5.0
|
||||
|
||||
2018-11-09 (bug)[35a8f1] overlong string length of some lists (owens)
|
||||
|
||||
2018-11-16 (bug)[00d04c] Repair [binary encode base64] (sebres)
|
||||
|
||||
- Released 8.6.9, November 16, 2018 - details at http://core.tcl-lang.org/tcl/ -
|
||||
|
||||
Changes to 8.7a1 include all changes to the 8.6 line through 8.6.7,
|
||||
plus the following, which focuses on the high-level feature changes
|
||||
in this changeset (new minor version) rather than bug fixes:
|
||||
|
||||
2016-03-17 (bug)[0b8c38] socket accept callbacks always in global ns (porter)
|
||||
*** POTENTIAL INCOMPATIBILITY ***
|
||||
|
||||
2016-07-01 Hack accommodations for legacy Itcl 3 disabled (porter)
|
||||
|
||||
2016-07-12 Make TCL_HASH_TYPE build-time configurable (nijtmans)
|
||||
|
||||
2016-07-19 (bug)[0363f0] Partial array search ID reform (porter)
|
||||
|
||||
2016-07-19 (feature removed) Tcl_ObjType "array search" unregistered (porter)
|
||||
*** POTENTIAL INCOMPATIBILITY for Tcl_GetObjType("array search") ***
|
||||
|
||||
2016-10-04 Server socket on port 0 chooses port supporting IPv4 * IPv6 (max)
|
||||
|
||||
2016-11-25 [array names -regexp] supports backrefs (goth)
|
||||
|
||||
2017-01-04 (TIP 456) New routine Tcl_OpenTcpServerEx() (limeboy)
|
||||
|
||||
2017-01-04 (TIP 459) New subcommand [package files] (nijtmans)
|
||||
|
||||
2017-01-16 threaded allocator initialization repair (vasiljevic,nijtmans)
|
||||
|
||||
2017-01-30 Add to Win shell builtins: assoc ftype move (ashok)
|
||||
|
||||
2017-03-31 TCL_MEM_DEBUG facilities better support 64-bit memory (nijtmans)
|
||||
|
||||
2017-04-13 \u escaped content in msg files converted to true utf-8 (nijtmans)
|
||||
|
||||
2017-05-18 (TIP 458) New epoll or kqueue notifiers are default (alborboz)
|
||||
|
||||
2017-05-31 Purge build support for SunOS-4.* (stu)
|
||||
|
||||
2017-06-22 (TIP 463) New option [regsub ... -command ...] (fellows)
|
||||
|
||||
2017-06-22 (TIP 470) Tcl_GetDefineContextObject();[oo::define [self]] (fellows)
|
||||
=> TclOO 1.2.0
|
||||
|
||||
2017-06-23 (TIP 472) Support 0d as prefix of decimal numbers (iyer,griffin)
|
||||
|
||||
2017-08-31 (bug)[2a9465] http state 100 continue handling broken (oehlmann)
|
||||
|
||||
2017-09-02 (bug)[0e4d88] replace command, delete trace kills namespace (porter)
|
||||
|
||||
--- Released 8.7a1, September 8, 2017 --- http://core.tcl.tk/tcl/ for details
|
||||
|
||||
2018-03-12 (TIP 490) add oo support for msgcat => msgcat 1.7.0 (oehlmann)
|
||||
|
||||
2018-03-12 (TIP 499) custom locale preference list (oehlmann)
|
||||
=> msgcat 1.7.0
|
||||
|
||||
- Released 8.7a3, Nov 30, 2018 --- http://core.tcl-lang.org/tcl/ for details -
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* fixstrtod.c --
|
||||
*
|
||||
* Source code for the "fixstrtod" procedure. This procedure is
|
||||
* used in place of strtod under Solaris 2.4, in order to fix
|
||||
* a bug where the "end" pointer gets set incorrectly.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
|
||||
#undef strtod
|
||||
|
||||
/*
|
||||
* Declare strtod explicitly rather than including stdlib.h, since in
|
||||
* somes systems (e.g. SunOS 4.1.4) stdlib.h doesn't declare strtod.
|
||||
*/
|
||||
|
||||
extern double strtod(char *, char **);
|
||||
|
||||
double
|
||||
fixstrtod(
|
||||
char *string,
|
||||
char **endPtr)
|
||||
{
|
||||
double d;
|
||||
d = strtod(string, endPtr);
|
||||
if ((endPtr != NULL) && (*endPtr != string) && ((*endPtr)[-1] == 0)) {
|
||||
*endPtr -= 1;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* float.h --
|
||||
*
|
||||
* This is a dummy header file to #include in Tcl when there
|
||||
* is no float.h in /usr/include. Right now this file is empty:
|
||||
* Tcl contains #ifdefs to deal with the lack of definitions;
|
||||
* all it needs is for the #include statement to work.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
@@ -29,6 +29,7 @@ extern char * malloc(unsigned int numBytes);
|
||||
extern void qsort(void *base, int n, int size, int (*compar)(
|
||||
const void *element1, const void *element2));
|
||||
extern char * realloc(char *ptr, unsigned int numBytes);
|
||||
extern double strtod(const char *string, char **endPtr);
|
||||
extern long strtol(const char *string, char **endPtr, int base);
|
||||
extern unsigned long strtoul(const char *string, char **endPtr, int base);
|
||||
|
||||
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* strtod.c --
|
||||
*
|
||||
* Source code for the "strtod" library procedure.
|
||||
*
|
||||
* Copyright (c) 1988-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 "tclInt.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
static const int maxExponent = 511; /* Largest possible base 10 exponent. Any
|
||||
* exponent larger than this will already
|
||||
* produce underflow or overflow, so there's
|
||||
* no need to worry about additional digits.
|
||||
*/
|
||||
static const double powersOf10[] = { /* Table giving binary powers of 10. Entry */
|
||||
10., /* is 10^2^i. Used to convert decimal */
|
||||
100., /* exponents into floating-point numbers. */
|
||||
1.0e4,
|
||||
1.0e8,
|
||||
1.0e16,
|
||||
1.0e32,
|
||||
1.0e64,
|
||||
1.0e128,
|
||||
1.0e256
|
||||
};
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* strtod --
|
||||
*
|
||||
* This procedure converts a floating-point number from an ASCII
|
||||
* decimal representation to internal double-precision format.
|
||||
*
|
||||
* Results:
|
||||
* The return value is the double-precision floating-point
|
||||
* representation of the characters in string. If endPtr isn't
|
||||
* NULL, then *endPtr is filled in with the address of the
|
||||
* next character after the last one that was part of the
|
||||
* floating-point number.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
double
|
||||
strtod(
|
||||
const char *string, /* A decimal ASCII floating-point number,
|
||||
* optionally preceded by white space. Must
|
||||
* have form "-I.FE-X", where I is the integer
|
||||
* part of the mantissa, F is the fractional
|
||||
* part of the mantissa, and X is the
|
||||
* exponent. Either of the signs may be "+",
|
||||
* "-", or omitted. Either I or F may be
|
||||
* omitted, or both. The decimal point isn't
|
||||
* necessary unless F is present. The "E" may
|
||||
* actually be an "e". E and X may both be
|
||||
* omitted (but not just one). */
|
||||
char **endPtr) /* If non-NULL, store terminating character's
|
||||
* address here. */
|
||||
{
|
||||
int sign, expSign = FALSE;
|
||||
double fraction, dblExp;
|
||||
const double *d;
|
||||
register const char *p;
|
||||
register int c;
|
||||
int exp = 0; /* Exponent read from "EX" field. */
|
||||
int fracExp = 0; /* Exponent that derives from the fractional
|
||||
* part. Under normal circumstatnces, it is
|
||||
* the negative of the number of digits in F.
|
||||
* However, if I is very long, the last digits
|
||||
* of I get dropped (otherwise a long I with a
|
||||
* large negative exponent could cause an
|
||||
* unnecessary overflow on I alone). In this
|
||||
* case, fracExp is incremented one for each
|
||||
* dropped digit. */
|
||||
int mantSize; /* Number of digits in mantissa. */
|
||||
int decPt; /* Number of mantissa digits BEFORE decimal
|
||||
* point. */
|
||||
const char *pExp; /* Temporarily holds location of exponent in
|
||||
* string. */
|
||||
|
||||
/*
|
||||
* Strip off leading blanks and check for a sign.
|
||||
*/
|
||||
|
||||
p = string;
|
||||
while (isspace(UCHAR(*p))) {
|
||||
p += 1;
|
||||
}
|
||||
if (*p == '-') {
|
||||
sign = TRUE;
|
||||
p += 1;
|
||||
} else {
|
||||
if (*p == '+') {
|
||||
p += 1;
|
||||
}
|
||||
sign = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count the number of digits in the mantissa (including the decimal
|
||||
* point), and also locate the decimal point.
|
||||
*/
|
||||
|
||||
decPt = -1;
|
||||
for (mantSize = 0; ; mantSize += 1)
|
||||
{
|
||||
c = *p;
|
||||
if (!isdigit(c)) {
|
||||
if ((c != '.') || (decPt >= 0)) {
|
||||
break;
|
||||
}
|
||||
decPt = mantSize;
|
||||
}
|
||||
p += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now suck up the digits in the mantissa. Use two integers to collect 9
|
||||
* digits each (this is faster than using floating-point). If the mantissa
|
||||
* has more than 18 digits, ignore the extras, since they can't affect the
|
||||
* value anyway.
|
||||
*/
|
||||
|
||||
pExp = p;
|
||||
p -= mantSize;
|
||||
if (decPt < 0) {
|
||||
decPt = mantSize;
|
||||
} else {
|
||||
mantSize -= 1; /* One of the digits was the point. */
|
||||
}
|
||||
if (mantSize > 18) {
|
||||
fracExp = decPt - 18;
|
||||
mantSize = 18;
|
||||
} else {
|
||||
fracExp = decPt - mantSize;
|
||||
}
|
||||
if (mantSize == 0) {
|
||||
fraction = 0.0;
|
||||
p = string;
|
||||
goto done;
|
||||
} else {
|
||||
int frac1, frac2;
|
||||
|
||||
frac1 = 0;
|
||||
for ( ; mantSize > 9; mantSize -= 1) {
|
||||
c = *p;
|
||||
p += 1;
|
||||
if (c == '.') {
|
||||
c = *p;
|
||||
p += 1;
|
||||
}
|
||||
frac1 = 10*frac1 + (c - '0');
|
||||
}
|
||||
frac2 = 0;
|
||||
for (; mantSize > 0; mantSize -= 1) {
|
||||
c = *p;
|
||||
p += 1;
|
||||
if (c == '.') {
|
||||
c = *p;
|
||||
p += 1;
|
||||
}
|
||||
frac2 = 10*frac2 + (c - '0');
|
||||
}
|
||||
fraction = (1.0e9 * frac1) + frac2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skim off the exponent.
|
||||
*/
|
||||
|
||||
p = pExp;
|
||||
if ((*p == 'E') || (*p == 'e')) {
|
||||
p += 1;
|
||||
if (*p == '-') {
|
||||
expSign = TRUE;
|
||||
p += 1;
|
||||
} else {
|
||||
if (*p == '+') {
|
||||
p += 1;
|
||||
}
|
||||
expSign = FALSE;
|
||||
}
|
||||
if (!isdigit(UCHAR(*p))) {
|
||||
p = pExp;
|
||||
goto done;
|
||||
}
|
||||
while (isdigit(UCHAR(*p))) {
|
||||
exp = exp * 10 + (*p - '0');
|
||||
p += 1;
|
||||
}
|
||||
}
|
||||
if (expSign) {
|
||||
exp = fracExp - exp;
|
||||
} else {
|
||||
exp = fracExp + exp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a floating-point number that represents the exponent. Do this
|
||||
* by processing the exponent one bit at a time to combine many powers of
|
||||
* 2 of 10. Then combine the exponent with the fraction.
|
||||
*/
|
||||
|
||||
if (exp < 0) {
|
||||
expSign = TRUE;
|
||||
exp = -exp;
|
||||
} else {
|
||||
expSign = FALSE;
|
||||
}
|
||||
if (exp > maxExponent) {
|
||||
exp = maxExponent;
|
||||
errno = ERANGE;
|
||||
}
|
||||
dblExp = 1.0;
|
||||
for (d = powersOf10; exp != 0; exp >>= 1, ++d) {
|
||||
if (exp & 01) {
|
||||
dblExp *= *d;
|
||||
}
|
||||
}
|
||||
if (expSign) {
|
||||
fraction /= dblExp;
|
||||
} else {
|
||||
fraction *= dblExp;
|
||||
}
|
||||
|
||||
done:
|
||||
if (endPtr != NULL) {
|
||||
*endPtr = (char *) p;
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
return -fraction;
|
||||
}
|
||||
return fraction;
|
||||
}
|
||||
+1
-1
@@ -53,7 +53,7 @@ strtol(
|
||||
*/
|
||||
|
||||
p = string;
|
||||
while (TclIsSpaceProc(*p)) {
|
||||
while (isspace(UCHAR(*p))) {
|
||||
p += 1;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ strtoul(
|
||||
*/
|
||||
|
||||
p = string;
|
||||
while (TclIsSpaceProc(*p)) {
|
||||
while (isspace(UCHAR(*p))) {
|
||||
p += 1;
|
||||
}
|
||||
if (*p == '-') {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* unistd.h --
|
||||
*
|
||||
* Macros, constants and prototypes for Posix conformance.
|
||||
*
|
||||
* Copyright 1989 Regents of the University of California Permission to use,
|
||||
* copy, modify, and distribute this software and its documentation for any
|
||||
* purpose and without fee is hereby granted, provided that the above
|
||||
* copyright notice appear in all copies. The University of California makes
|
||||
* no representations about the suitability of this software for any purpose.
|
||||
* It is provided "as is" without express or implied warranty.
|
||||
*/
|
||||
|
||||
#ifndef _UNISTD
|
||||
#define _UNISTD
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Strict POSIX stuff goes here. Extensions go down below, in the ifndef
|
||||
* _POSIX_SOURCE section.
|
||||
*/
|
||||
|
||||
extern void _exit(int status);
|
||||
extern int access(const char *path, int mode);
|
||||
extern int chdir(const char *path);
|
||||
extern int chown(const char *path, uid_t owner, gid_t group);
|
||||
extern int close(int fd);
|
||||
extern int dup(int oldfd);
|
||||
extern int dup2(int oldfd, int newfd);
|
||||
extern int execl(const char *path, ...);
|
||||
extern int execle(const char *path, ...);
|
||||
extern int execlp(const char *file, ...);
|
||||
extern int execv(const char *path, char **argv);
|
||||
extern int execve(const char *path, char **argv, char **envp);
|
||||
extern int execvpw(const char *file, char **argv);
|
||||
extern pid_t fork(void);
|
||||
extern char * getcwd(char *buf, size_t size);
|
||||
extern gid_t getegid(void);
|
||||
extern uid_t geteuid(void);
|
||||
extern gid_t getgid(void);
|
||||
extern int getgroups(int bufSize, int *buffer);
|
||||
extern pid_t getpid(void);
|
||||
extern uid_t getuid(void);
|
||||
extern int isatty(int fd);
|
||||
extern long lseek(int fd, long offset, int whence);
|
||||
extern int pipe(int *fildes);
|
||||
extern int read(int fd, char *buf, size_t size);
|
||||
extern int setgid(gid_t group);
|
||||
extern int setuid(uid_t user);
|
||||
extern unsigned sleep(unsigned seconds);
|
||||
extern char * ttyname(int fd);
|
||||
extern int unlink(const char *path);
|
||||
extern int write(int fd, const char *buf, size_t size);
|
||||
|
||||
#ifndef _POSIX_SOURCE
|
||||
extern char * crypt(const char *, const char *);
|
||||
extern int fchown(int fd, uid_t owner, gid_t group);
|
||||
extern int flock(int fd, int operation);
|
||||
extern int ftruncate(int fd, unsigned long length);
|
||||
extern int ioctl(int fd, int request, ...);
|
||||
extern int readlink(const char *path, char *buf, int bufsize);
|
||||
extern int setegid(gid_t group);
|
||||
extern int seteuidw(uid_t user);
|
||||
extern int setreuid(int ruid, int euid);
|
||||
extern int symlink(const char *, const char *);
|
||||
extern int ttyslot(void);
|
||||
extern int truncate(const char *path, unsigned long length);
|
||||
extern int vfork(void);
|
||||
#endif /* _POSIX_SOURCE */
|
||||
|
||||
#endif /* _UNISTD */
|
||||
@@ -29,12 +29,6 @@
|
||||
|
||||
#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
|
||||
|
||||
#ifdef Z_U4
|
||||
typedef Z_U4 z_crc_t;
|
||||
#else
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* Return the next byte in the pseudo-random sequence
|
||||
*/
|
||||
|
||||
@@ -97,7 +97,7 @@ void change_file_date(filename,dosdate,tmu_date)
|
||||
SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
|
||||
CloseHandle(hFile);
|
||||
#else
|
||||
#if defined(unix) || defined(__APPLE__)
|
||||
#ifdef unix || __APPLE__
|
||||
struct utimbuf ut;
|
||||
struct tm newdate;
|
||||
newdate.tm_sec = tmu_date.tm_sec;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
*/
|
||||
|
||||
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#define __USE_FILE_OFFSET64
|
||||
@@ -27,7 +28,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(IOAPI_NO_64)
|
||||
#ifdef __APPLE__
|
||||
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
|
||||
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello(stream)
|
||||
@@ -38,7 +39,8 @@
|
||||
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
|
||||
#endif
|
||||
|
||||
#include "tinydir.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -92,7 +94,7 @@ uLong filetime(f, tmzip, dt)
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#if defined(unix) || defined(__APPLE__)
|
||||
#ifdef unix || __APPLE__
|
||||
uLong filetime(f, tmzip, dt)
|
||||
char *f; /* name of file to get info on */
|
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */
|
||||
@@ -170,7 +172,6 @@ void do_banner()
|
||||
void do_help()
|
||||
{
|
||||
printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \
|
||||
" -r Scan directories recursively\n" \
|
||||
" -o Overwrite existing file.zip\n" \
|
||||
" -a Append to existing file.zip\n" \
|
||||
" -0 Store only\n" \
|
||||
@@ -242,153 +243,12 @@ int isLargeFile(const char* filename)
|
||||
return largeFile;
|
||||
}
|
||||
|
||||
void addFileToZip(zipFile zf, const char *filenameinzip, const char *password, int opt_exclude_path,int opt_compress_level) {
|
||||
FILE * fin;
|
||||
int size_read;
|
||||
const char *savefilenameinzip;
|
||||
zip_fileinfo zi;
|
||||
unsigned long crcFile=0;
|
||||
int zip64 = 0;
|
||||
int err=0;
|
||||
int size_buf=WRITEBUFFERSIZE;
|
||||
unsigned char buf[WRITEBUFFERSIZE];
|
||||
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
|
||||
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
|
||||
zi.dosDate = 0;
|
||||
zi.internal_fa = 0;
|
||||
zi.external_fa = 0;
|
||||
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
|
||||
|
||||
/*
|
||||
err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL / * comment * /,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level);
|
||||
*/
|
||||
if ((password != NULL) && (err==ZIP_OK))
|
||||
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
|
||||
|
||||
zip64 = isLargeFile(filenameinzip);
|
||||
|
||||
/* The path name saved, should not include a leading slash. */
|
||||
/*if it did, windows/xp and dynazip couldn't read the zip file. */
|
||||
savefilenameinzip = filenameinzip;
|
||||
while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
|
||||
{
|
||||
savefilenameinzip++;
|
||||
}
|
||||
|
||||
/*should the zip file contain any path at all?*/
|
||||
if( opt_exclude_path )
|
||||
{
|
||||
const char *tmpptr;
|
||||
const char *lastslash = 0;
|
||||
for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++)
|
||||
{
|
||||
if( *tmpptr == '\\' || *tmpptr == '/')
|
||||
{
|
||||
lastslash = tmpptr;
|
||||
}
|
||||
}
|
||||
if( lastslash != NULL )
|
||||
{
|
||||
savefilenameinzip = lastslash+1; // base filename follows last slash.
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL /* comment*/,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level,0,
|
||||
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
|
||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
||||
password,crcFile, zip64);
|
||||
|
||||
if (err != ZIP_OK)
|
||||
printf("error in opening %s in zipfile\n",filenameinzip);
|
||||
else
|
||||
{
|
||||
fin = FOPEN_FUNC(filenameinzip,"rb");
|
||||
if (fin==NULL)
|
||||
{
|
||||
err=ZIP_ERRNO;
|
||||
printf("error in opening %s for reading\n",filenameinzip);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ZIP_OK)
|
||||
do
|
||||
{
|
||||
err = ZIP_OK;
|
||||
size_read = (int)fread(buf,1,size_buf,fin);
|
||||
if (size_read < size_buf)
|
||||
if (feof(fin)==0)
|
||||
{
|
||||
printf("error in reading %s\n",filenameinzip);
|
||||
err = ZIP_ERRNO;
|
||||
}
|
||||
|
||||
if (size_read>0)
|
||||
{
|
||||
err = zipWriteInFileInZip (zf,buf,size_read);
|
||||
if (err<0)
|
||||
{
|
||||
printf("error in writing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
}
|
||||
|
||||
}
|
||||
} while ((err == ZIP_OK) && (size_read>0));
|
||||
|
||||
if (fin)
|
||||
fclose(fin);
|
||||
|
||||
if (err<0)
|
||||
err=ZIP_ERRNO;
|
||||
else
|
||||
{
|
||||
err = zipCloseFileInZip(zf);
|
||||
if (err!=ZIP_OK)
|
||||
printf("error in closing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void addPathToZip(zipFile zf, const char *filenameinzip, const char *password, int opt_exclude_path,int opt_compress_level) {
|
||||
tinydir_dir dir;
|
||||
int i;
|
||||
char newname[512];
|
||||
|
||||
tinydir_open_sorted(&dir, filenameinzip);
|
||||
|
||||
for (i = 0; i < dir.n_files; i++)
|
||||
{
|
||||
tinydir_file file;
|
||||
tinydir_readfile_n(&dir, &file, i);
|
||||
if(strcmp(file.name,".")==0) continue;
|
||||
if(strcmp(file.name,"..")==0) continue;
|
||||
sprintf(newname,"%s/%s",dir.path,file.name);
|
||||
if (file.is_dir)
|
||||
{
|
||||
addPathToZip(zf,newname,password,opt_exclude_path,opt_compress_level);
|
||||
} else {
|
||||
addFileToZip(zf,newname,password,opt_exclude_path,opt_compress_level);
|
||||
}
|
||||
}
|
||||
|
||||
tinydir_close(&dir);
|
||||
}
|
||||
|
||||
|
||||
int main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i;
|
||||
int opt_recursive=0;
|
||||
int opt_overwrite=1;
|
||||
int opt_overwrite=0;
|
||||
int opt_compress_level=Z_DEFAULT_COMPRESSION;
|
||||
int opt_exclude_path=0;
|
||||
int zipfilenamearg = 0;
|
||||
@@ -425,8 +285,7 @@ int main(argc,argv)
|
||||
opt_compress_level = c-'0';
|
||||
if ((c=='j') || (c=='J'))
|
||||
opt_exclude_path = 1;
|
||||
if ((c=='r') || (c=='R'))
|
||||
opt_recursive = 1;
|
||||
|
||||
if (((c=='p') || (c=='P')) && (i+1<argc))
|
||||
{
|
||||
password=argv[i+1];
|
||||
@@ -533,14 +392,117 @@ int main(argc,argv)
|
||||
((argv[i][1]=='o') || (argv[i][1]=='O') ||
|
||||
(argv[i][1]=='a') || (argv[i][1]=='A') ||
|
||||
(argv[i][1]=='p') || (argv[i][1]=='P') ||
|
||||
(argv[i][1]=='r') || (argv[i][1]=='R') ||
|
||||
((argv[i][1]>='0') || (argv[i][1]<='9'))) &&
|
||||
(strlen(argv[i]) == 2)))
|
||||
{
|
||||
if(opt_recursive) {
|
||||
addPathToZip(zf,argv[i],password,opt_exclude_path,opt_compress_level);
|
||||
} else {
|
||||
addFileToZip(zf,argv[i],password,opt_exclude_path,opt_compress_level);
|
||||
FILE * fin;
|
||||
int size_read;
|
||||
const char* filenameinzip = argv[i];
|
||||
const char *savefilenameinzip;
|
||||
zip_fileinfo zi;
|
||||
unsigned long crcFile=0;
|
||||
int zip64 = 0;
|
||||
|
||||
zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
|
||||
zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
|
||||
zi.dosDate = 0;
|
||||
zi.internal_fa = 0;
|
||||
zi.external_fa = 0;
|
||||
filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
|
||||
|
||||
/*
|
||||
err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL / * comment * /,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level);
|
||||
*/
|
||||
if ((password != NULL) && (err==ZIP_OK))
|
||||
err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
|
||||
|
||||
zip64 = isLargeFile(filenameinzip);
|
||||
|
||||
/* The path name saved, should not include a leading slash. */
|
||||
/*if it did, windows/xp and dynazip couldn't read the zip file. */
|
||||
savefilenameinzip = filenameinzip;
|
||||
while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
|
||||
{
|
||||
savefilenameinzip++;
|
||||
}
|
||||
|
||||
/*should the zip file contain any path at all?*/
|
||||
if( opt_exclude_path )
|
||||
{
|
||||
const char *tmpptr;
|
||||
const char *lastslash = 0;
|
||||
for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++)
|
||||
{
|
||||
if( *tmpptr == '\\' || *tmpptr == '/')
|
||||
{
|
||||
lastslash = tmpptr;
|
||||
}
|
||||
}
|
||||
if( lastslash != NULL )
|
||||
{
|
||||
savefilenameinzip = lastslash+1; // base filename follows last slash.
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
|
||||
NULL,0,NULL,0,NULL /* comment*/,
|
||||
(opt_compress_level != 0) ? Z_DEFLATED : 0,
|
||||
opt_compress_level,0,
|
||||
/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
|
||||
-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
|
||||
password,crcFile, zip64);
|
||||
|
||||
if (err != ZIP_OK)
|
||||
printf("error in opening %s in zipfile\n",filenameinzip);
|
||||
else
|
||||
{
|
||||
fin = FOPEN_FUNC(filenameinzip,"rb");
|
||||
if (fin==NULL)
|
||||
{
|
||||
err=ZIP_ERRNO;
|
||||
printf("error in opening %s for reading\n",filenameinzip);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ZIP_OK)
|
||||
do
|
||||
{
|
||||
err = ZIP_OK;
|
||||
size_read = (int)fread(buf,1,size_buf,fin);
|
||||
if (size_read < size_buf)
|
||||
if (feof(fin)==0)
|
||||
{
|
||||
printf("error in reading %s\n",filenameinzip);
|
||||
err = ZIP_ERRNO;
|
||||
}
|
||||
|
||||
if (size_read>0)
|
||||
{
|
||||
err = zipWriteInFileInZip (zf,buf,size_read);
|
||||
if (err<0)
|
||||
{
|
||||
printf("error in writing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
}
|
||||
|
||||
}
|
||||
} while ((err == ZIP_OK) && (size_read>0));
|
||||
|
||||
if (fin)
|
||||
fclose(fin);
|
||||
|
||||
if (err<0)
|
||||
err=ZIP_ERRNO;
|
||||
else
|
||||
{
|
||||
err = zipCloseFileInZip(zf);
|
||||
if (err!=ZIP_OK)
|
||||
printf("error in closing %s in the zipfile\n",
|
||||
filenameinzip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,816 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013-2017, tinydir authors:
|
||||
- Cong Xu
|
||||
- Lautis Sun
|
||||
- Baudouin Feildel
|
||||
- Andargor <andargor@yahoo.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef TINYDIR_H
|
||||
#define TINYDIR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if ((defined _UNICODE) && !(defined UNICODE))
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#if ((defined UNICODE) && !(defined _UNICODE))
|
||||
#define _UNICODE
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# include <tchar.h>
|
||||
# pragma warning(push)
|
||||
# pragma warning (disable : 4996)
|
||||
#else
|
||||
# include <dirent.h>
|
||||
# include <libgen.h>
|
||||
# include <sys/stat.h>
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
#ifdef __MINGW32__
|
||||
# include <tchar.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* types */
|
||||
|
||||
/* Windows UNICODE wide character support */
|
||||
#if defined _MSC_VER || defined __MINGW32__
|
||||
# define _tinydir_char_t TCHAR
|
||||
# define TINYDIR_STRING(s) _TEXT(s)
|
||||
# define _tinydir_strlen _tcslen
|
||||
# define _tinydir_strcpy _tcscpy
|
||||
# define _tinydir_strcat _tcscat
|
||||
# define _tinydir_strcmp _tcscmp
|
||||
# define _tinydir_strrchr _tcsrchr
|
||||
# define _tinydir_strncmp _tcsncmp
|
||||
#else
|
||||
# define _tinydir_char_t char
|
||||
# define TINYDIR_STRING(s) s
|
||||
# define _tinydir_strlen strlen
|
||||
# define _tinydir_strcpy strcpy
|
||||
# define _tinydir_strcat strcat
|
||||
# define _tinydir_strcmp strcmp
|
||||
# define _tinydir_strrchr strrchr
|
||||
# define _tinydir_strncmp strncmp
|
||||
#endif
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
# include <windows.h>
|
||||
# define _TINYDIR_PATH_MAX MAX_PATH
|
||||
#elif defined __linux__
|
||||
# include <limits.h>
|
||||
# define _TINYDIR_PATH_MAX PATH_MAX
|
||||
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
# include <sys/param.h>
|
||||
# if defined(BSD)
|
||||
# include <limits.h>
|
||||
# define _TINYDIR_PATH_MAX PATH_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef _TINYDIR_PATH_MAX
|
||||
#define _TINYDIR_PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* extra chars for the "\\*" mask */
|
||||
# define _TINYDIR_PATH_EXTRA 2
|
||||
#else
|
||||
# define _TINYDIR_PATH_EXTRA 0
|
||||
#endif
|
||||
|
||||
#define _TINYDIR_FILENAME_MAX 256
|
||||
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#define _TINYDIR_DRIVE_MAX 3
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define _TINYDIR_FUNC static __inline
|
||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||
# define _TINYDIR_FUNC static __inline__
|
||||
#else
|
||||
# define _TINYDIR_FUNC static inline
|
||||
#endif
|
||||
|
||||
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
||||
#ifdef TINYDIR_USE_READDIR_R
|
||||
|
||||
/* readdir_r is a POSIX-only function, and may not be available under various
|
||||
* environments/settings, e.g. MinGW. Use readdir fallback */
|
||||
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
|
||||
_POSIX_SOURCE
|
||||
# define _TINYDIR_HAS_READDIR_R
|
||||
#endif
|
||||
#if _POSIX_C_SOURCE >= 200112L
|
||||
# define _TINYDIR_HAS_FPATHCONF
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if _BSD_SOURCE || _SVID_SOURCE || \
|
||||
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||
# define _TINYDIR_HAS_DIRFD
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
|
||||
defined _PC_NAME_MAX
|
||||
# define _TINYDIR_USE_FPATHCONF
|
||||
#endif
|
||||
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
|
||||
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* Use readdir by default */
|
||||
#else
|
||||
# define _TINYDIR_USE_READDIR
|
||||
#endif
|
||||
|
||||
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
||||
#ifndef _MSC_VER
|
||||
#if (defined __MINGW32__) && (defined _UNICODE)
|
||||
#define _TINYDIR_DIR _WDIR
|
||||
#define _tinydir_dirent _wdirent
|
||||
#define _tinydir_opendir _wopendir
|
||||
#define _tinydir_readdir _wreaddir
|
||||
#define _tinydir_closedir _wclosedir
|
||||
#else
|
||||
#define _TINYDIR_DIR DIR
|
||||
#define _tinydir_dirent dirent
|
||||
#define _tinydir_opendir opendir
|
||||
#define _tinydir_readdir readdir
|
||||
#define _tinydir_closedir closedir
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
||||
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
||||
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
||||
#else
|
||||
#error "Either define both alloc and free or none of them!"
|
||||
#endif
|
||||
|
||||
#if !defined(_TINYDIR_MALLOC)
|
||||
#define _TINYDIR_MALLOC(_size) malloc(_size)
|
||||
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
||||
#endif /* !defined(_TINYDIR_MALLOC) */
|
||||
|
||||
typedef struct tinydir_file
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *extension;
|
||||
int is_dir;
|
||||
int is_reg;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
struct _stat _s;
|
||||
#else
|
||||
struct stat _s;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_file;
|
||||
|
||||
typedef struct tinydir_dir
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
int has_next;
|
||||
size_t n_files;
|
||||
|
||||
tinydir_file *_files;
|
||||
#ifdef _MSC_VER
|
||||
HANDLE _h;
|
||||
WIN32_FIND_DATA _f;
|
||||
#else
|
||||
_TINYDIR_DIR *_d;
|
||||
struct _tinydir_dirent *_e;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
struct _tinydir_dirent *_ep;
|
||||
#endif
|
||||
#endif
|
||||
} tinydir_dir;
|
||||
|
||||
|
||||
/* declarations */
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file);
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b);
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* definitions*/
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
int error;
|
||||
int size; /* using int size */
|
||||
#endif
|
||||
#else
|
||||
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
||||
#endif
|
||||
_tinydir_char_t *pathp;
|
||||
|
||||
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* initialise dir */
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
dir->_d = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
tinydir_close(dir);
|
||||
|
||||
_tinydir_strcpy(dir->path, path);
|
||||
/* Remove trailing slashes */
|
||||
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
||||
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
|
||||
{
|
||||
*pathp = TINYDIR_STRING('\0');
|
||||
pathp++;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
_tinydir_strcpy(path_buf, dir->path);
|
||||
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
||||
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
||||
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
||||
#else
|
||||
dir->_h = FindFirstFile(path_buf, &dir->_f);
|
||||
#endif
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
errno = ENOENT;
|
||||
#else
|
||||
dir->_d = _tinydir_opendir(path);
|
||||
if (dir->_d == NULL)
|
||||
{
|
||||
#endif
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* read first file */
|
||||
dir->has_next = 1;
|
||||
#ifndef _MSC_VER
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
/* allocate dirent buffer for readdir_r */
|
||||
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
||||
if (size == -1) return -1;
|
||||
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
||||
if (dir->_ep == NULL) return -1;
|
||||
|
||||
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
||||
if (error != 0) return -1;
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
{
|
||||
dir->has_next = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||
{
|
||||
/* Count the number of files first, to pre-allocate the files array */
|
||||
size_t n_files = 0;
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
n_files++;
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
tinydir_close(dir);
|
||||
|
||||
if (tinydir_open(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir->n_files = 0;
|
||||
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
||||
if (dir->_files == NULL)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
while (dir->has_next)
|
||||
{
|
||||
tinydir_file *p_file;
|
||||
dir->n_files++;
|
||||
|
||||
p_file = &dir->_files[dir->n_files - 1];
|
||||
if (tinydir_readfile(dir, p_file) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (tinydir_next(dir) == -1)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* Just in case the number of files has changed between the first and
|
||||
second reads, terminate without writing into unallocated memory */
|
||||
if (dir->n_files == n_files)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
tinydir_close(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void tinydir_close(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dir->path, 0, sizeof(dir->path));
|
||||
dir->has_next = 0;
|
||||
dir->n_files = 0;
|
||||
_TINYDIR_FREE(dir->_files);
|
||||
dir->_files = NULL;
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
FindClose(dir->_h);
|
||||
}
|
||||
dir->_h = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
if (dir->_d)
|
||||
{
|
||||
_tinydir_closedir(dir->_d);
|
||||
}
|
||||
dir->_d = NULL;
|
||||
dir->_e = NULL;
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
_TINYDIR_FREE(dir->_ep);
|
||||
dir->_ep = NULL;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_next(tinydir_dir *dir)
|
||||
{
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!dir->has_next)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
if (FindNextFile(dir->_h, &dir->_f) == 0)
|
||||
#else
|
||||
#ifdef _TINYDIR_USE_READDIR
|
||||
dir->_e = _tinydir_readdir(dir->_d);
|
||||
#else
|
||||
if (dir->_ep == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
dir->has_next = 0;
|
||||
#ifdef _MSC_VER
|
||||
if (GetLastError() != ERROR_SUCCESS &&
|
||||
GetLastError() != ERROR_NO_MORE_FILES)
|
||||
{
|
||||
tinydir_close(dir);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||
#else
|
||||
if (dir->_e == NULL)
|
||||
#endif
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(dir->path) +
|
||||
_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) + 1 + _TINYDIR_PATH_EXTRA >=
|
||||
_TINYDIR_PATH_MAX)
|
||||
{
|
||||
/* the path for the file will be too long */
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
) >= _TINYDIR_FILENAME_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(file->path, dir->path);
|
||||
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
|
||||
_tinydir_strcpy(file->name,
|
||||
#ifdef _MSC_VER
|
||||
dir->_f.cFileName
|
||||
#else
|
||||
dir->_e->d_name
|
||||
#endif
|
||||
);
|
||||
_tinydir_strcat(file->path, file->name);
|
||||
#ifndef _MSC_VER
|
||||
#ifdef __MINGW32__
|
||||
if (_tstat(
|
||||
#else
|
||||
if (stat(
|
||||
#endif
|
||||
file->path, &file->_s) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
file->is_dir =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
S_ISDIR(file->_s.st_mode);
|
||||
#endif
|
||||
file->is_reg =
|
||||
#ifdef _MSC_VER
|
||||
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
|
||||
(
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
||||
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
||||
#endif
|
||||
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
||||
#endif
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
|
||||
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
||||
#else
|
||||
S_ISREG(file->_s.st_mode);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
||||
{
|
||||
if (dir == NULL || file == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
|
||||
_tinydir_get_ext(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
||||
{
|
||||
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||
if (dir == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (i >= dir->n_files || !dir->_files[i].is_dir)
|
||||
{
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_tinydir_strcpy(path, dir->_files[i].path);
|
||||
tinydir_close(dir);
|
||||
if (tinydir_open_sorted(dir, path) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Open a single file given its path */
|
||||
_TINYDIR_FUNC
|
||||
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
||||
{
|
||||
tinydir_dir dir;
|
||||
int result = 0;
|
||||
int found = 0;
|
||||
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
||||
_tinydir_char_t *dir_name;
|
||||
_tinydir_char_t *base_name;
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
|
||||
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
||||
#endif
|
||||
|
||||
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||
{
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the parent path */
|
||||
#if (defined _MSC_VER || defined __MINGW32__)
|
||||
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
||||
_tsplitpath_s(
|
||||
path,
|
||||
drive_buf, _TINYDIR_DRIVE_MAX,
|
||||
dir_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
file_name_buf, _TINYDIR_FILENAME_MAX,
|
||||
ext_buf, _TINYDIR_FILENAME_MAX);
|
||||
#else
|
||||
_tsplitpath(
|
||||
path,
|
||||
drive_buf,
|
||||
dir_name_buf,
|
||||
file_name_buf,
|
||||
ext_buf);
|
||||
#endif
|
||||
|
||||
/* _splitpath_s not work fine with only filename and widechar support */
|
||||
#ifdef _UNICODE
|
||||
if (drive_buf[0] == L'\xFEFE')
|
||||
drive_buf[0] = '\0';
|
||||
if (dir_name_buf[0] == L'\xFEFE')
|
||||
dir_name_buf[0] = '\0';
|
||||
#endif
|
||||
|
||||
if (errno)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
||||
empty */
|
||||
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
|
||||
{
|
||||
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
||||
}
|
||||
/* Concatenate the drive letter and dir name to form full dir name */
|
||||
_tinydir_strcat(drive_buf, dir_name_buf);
|
||||
dir_name = drive_buf;
|
||||
/* Concatenate the file name and extension to form base name */
|
||||
_tinydir_strcat(file_name_buf, ext_buf);
|
||||
base_name = file_name_buf;
|
||||
#else
|
||||
_tinydir_strcpy(dir_name_buf, path);
|
||||
dir_name = dirname(dir_name_buf);
|
||||
_tinydir_strcpy(file_name_buf, path);
|
||||
base_name =basename(file_name_buf);
|
||||
#endif
|
||||
|
||||
/* Open the parent directory */
|
||||
if (tinydir_open(&dir, dir_name) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read through the parent directory and look for the file */
|
||||
while (dir.has_next)
|
||||
{
|
||||
if (tinydir_readfile(&dir, file) == -1)
|
||||
{
|
||||
result = -1;
|
||||
goto bail;
|
||||
}
|
||||
if (_tinydir_strcmp(file->name, base_name) == 0)
|
||||
{
|
||||
/* File found */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
tinydir_next(&dir);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
result = -1;
|
||||
errno = ENOENT;
|
||||
}
|
||||
|
||||
bail:
|
||||
tinydir_close(&dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
void _tinydir_get_ext(tinydir_file *file)
|
||||
{
|
||||
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
||||
if (period == NULL)
|
||||
{
|
||||
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
file->extension = period + 1;
|
||||
}
|
||||
}
|
||||
|
||||
_TINYDIR_FUNC
|
||||
int _tinydir_file_cmp(const void *a, const void *b)
|
||||
{
|
||||
const tinydir_file *fa = (const tinydir_file *)a;
|
||||
const tinydir_file *fb = (const tinydir_file *)b;
|
||||
if (fa->is_dir != fb->is_dir)
|
||||
{
|
||||
return -(fa->is_dir - fb->is_dir);
|
||||
}
|
||||
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
||||
}
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifndef _TINYDIR_USE_READDIR
|
||||
/*
|
||||
The following authored by Ben Hutchings <ben@decadent.org.uk>
|
||||
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
||||
*/
|
||||
/* Calculate the required buffer size (in bytes) for directory *
|
||||
* entries read from the given directory handle. Return -1 if this *
|
||||
* this cannot be done. *
|
||||
* *
|
||||
* This code does not trust values of NAME_MAX that are less than *
|
||||
* 255, since some systems (including at least HP-UX) incorrectly *
|
||||
* define it to be a smaller value. */
|
||||
_TINYDIR_FUNC
|
||||
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
||||
{
|
||||
long name_max;
|
||||
size_t name_end;
|
||||
/* parameter may be unused */
|
||||
(void)dirp;
|
||||
|
||||
#if defined _TINYDIR_USE_FPATHCONF
|
||||
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||
if (name_max == -1)
|
||||
#if defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
return (size_t)(-1);
|
||||
#endif
|
||||
#elif defined(NAME_MAX)
|
||||
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||
#else
|
||||
#error "buffer size for readdir_r cannot be determined"
|
||||
#endif
|
||||
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
||||
return (name_end > sizeof(struct _tinydir_dirent) ?
|
||||
name_end : sizeof(struct _tinydir_dirent));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
# if defined (_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,209 @@
|
||||
1. Compression algorithm (deflate)
|
||||
|
||||
The deflation algorithm used by gzip (also zip and zlib) is a variation of
|
||||
LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
|
||||
the input data. The second occurrence of a string is replaced by a
|
||||
pointer to the previous string, in the form of a pair (distance,
|
||||
length). Distances are limited to 32K bytes, and lengths are limited
|
||||
to 258 bytes. When a string does not occur anywhere in the previous
|
||||
32K bytes, it is emitted as a sequence of literal bytes. (In this
|
||||
description, `string' must be taken as an arbitrary sequence of bytes,
|
||||
and is not restricted to printable characters.)
|
||||
|
||||
Literals or match lengths are compressed with one Huffman tree, and
|
||||
match distances are compressed with another tree. The trees are stored
|
||||
in a compact form at the start of each block. The blocks can have any
|
||||
size (except that the compressed data for one block must fit in
|
||||
available memory). A block is terminated when deflate() determines that
|
||||
it would be useful to start another block with fresh trees. (This is
|
||||
somewhat similar to the behavior of LZW-based _compress_.)
|
||||
|
||||
Duplicated strings are found using a hash table. All input strings of
|
||||
length 3 are inserted in the hash table. A hash index is computed for
|
||||
the next 3 bytes. If the hash chain for this index is not empty, all
|
||||
strings in the chain are compared with the current input string, and
|
||||
the longest match is selected.
|
||||
|
||||
The hash chains are searched starting with the most recent strings, to
|
||||
favor small distances and thus take advantage of the Huffman encoding.
|
||||
The hash chains are singly linked. There are no deletions from the
|
||||
hash chains, the algorithm simply discards matches that are too old.
|
||||
|
||||
To avoid a worst-case situation, very long hash chains are arbitrarily
|
||||
truncated at a certain length, determined by a runtime option (level
|
||||
parameter of deflateInit). So deflate() does not always find the longest
|
||||
possible match but generally finds a match which is long enough.
|
||||
|
||||
deflate() also defers the selection of matches with a lazy evaluation
|
||||
mechanism. After a match of length N has been found, deflate() searches for
|
||||
a longer match at the next input byte. If a longer match is found, the
|
||||
previous match is truncated to a length of one (thus producing a single
|
||||
literal byte) and the process of lazy evaluation begins again. Otherwise,
|
||||
the original match is kept, and the next match search is attempted only N
|
||||
steps later.
|
||||
|
||||
The lazy match evaluation is also subject to a runtime parameter. If
|
||||
the current match is long enough, deflate() reduces the search for a longer
|
||||
match, thus speeding up the whole process. If compression ratio is more
|
||||
important than speed, deflate() attempts a complete second search even if
|
||||
the first match is already long enough.
|
||||
|
||||
The lazy match evaluation is not performed for the fastest compression
|
||||
modes (level parameter 1 to 3). For these fast modes, new strings
|
||||
are inserted in the hash table only when no match was found, or
|
||||
when the match is not too long. This degrades the compression ratio
|
||||
but saves time since there are both fewer insertions and fewer searches.
|
||||
|
||||
|
||||
2. Decompression algorithm (inflate)
|
||||
|
||||
2.1 Introduction
|
||||
|
||||
The key question is how to represent a Huffman code (or any prefix code) so
|
||||
that you can decode fast. The most important characteristic is that shorter
|
||||
codes are much more common than longer codes, so pay attention to decoding the
|
||||
short codes fast, and let the long codes take longer to decode.
|
||||
|
||||
inflate() sets up a first level table that covers some number of bits of
|
||||
input less than the length of longest code. It gets that many bits from the
|
||||
stream, and looks it up in the table. The table will tell if the next
|
||||
code is that many bits or less and how many, and if it is, it will tell
|
||||
the value, else it will point to the next level table for which inflate()
|
||||
grabs more bits and tries to decode a longer code.
|
||||
|
||||
How many bits to make the first lookup is a tradeoff between the time it
|
||||
takes to decode and the time it takes to build the table. If building the
|
||||
table took no time (and if you had infinite memory), then there would only
|
||||
be a first level table to cover all the way to the longest code. However,
|
||||
building the table ends up taking a lot longer for more bits since short
|
||||
codes are replicated many times in such a table. What inflate() does is
|
||||
simply to make the number of bits in the first table a variable, and then
|
||||
to set that variable for the maximum speed.
|
||||
|
||||
For inflate, which has 286 possible codes for the literal/length tree, the size
|
||||
of the first table is nine bits. Also the distance trees have 30 possible
|
||||
values, and the size of the first table is six bits. Note that for each of
|
||||
those cases, the table ended up one bit longer than the ``average'' code
|
||||
length, i.e. the code length of an approximately flat code which would be a
|
||||
little more than eight bits for 286 symbols and a little less than five bits
|
||||
for 30 symbols.
|
||||
|
||||
|
||||
2.2 More details on the inflate table lookup
|
||||
|
||||
Ok, you want to know what this cleverly obfuscated inflate tree actually
|
||||
looks like. You are correct that it's not a Huffman tree. It is simply a
|
||||
lookup table for the first, let's say, nine bits of a Huffman symbol. The
|
||||
symbol could be as short as one bit or as long as 15 bits. If a particular
|
||||
symbol is shorter than nine bits, then that symbol's translation is duplicated
|
||||
in all those entries that start with that symbol's bits. For example, if the
|
||||
symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a
|
||||
symbol is nine bits long, it appears in the table once.
|
||||
|
||||
If the symbol is longer than nine bits, then that entry in the table points
|
||||
to another similar table for the remaining bits. Again, there are duplicated
|
||||
entries as needed. The idea is that most of the time the symbol will be short
|
||||
and there will only be one table look up. (That's whole idea behind data
|
||||
compression in the first place.) For the less frequent long symbols, there
|
||||
will be two lookups. If you had a compression method with really long
|
||||
symbols, you could have as many levels of lookups as is efficient. For
|
||||
inflate, two is enough.
|
||||
|
||||
So a table entry either points to another table (in which case nine bits in
|
||||
the above example are gobbled), or it contains the translation for the symbol
|
||||
and the number of bits to gobble. Then you start again with the next
|
||||
ungobbled bit.
|
||||
|
||||
You may wonder: why not just have one lookup table for how ever many bits the
|
||||
longest symbol is? The reason is that if you do that, you end up spending
|
||||
more time filling in duplicate symbol entries than you do actually decoding.
|
||||
At least for deflate's output that generates new trees every several 10's of
|
||||
kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code
|
||||
would take too long if you're only decoding several thousand symbols. At the
|
||||
other extreme, you could make a new table for every bit in the code. In fact,
|
||||
that's essentially a Huffman tree. But then you spend too much time
|
||||
traversing the tree while decoding, even for short symbols.
|
||||
|
||||
So the number of bits for the first lookup table is a trade of the time to
|
||||
fill out the table vs. the time spent looking at the second level and above of
|
||||
the table.
|
||||
|
||||
Here is an example, scaled down:
|
||||
|
||||
The code being decoded, with 10 symbols, from 1 to 6 bits long:
|
||||
|
||||
A: 0
|
||||
B: 10
|
||||
C: 1100
|
||||
D: 11010
|
||||
E: 11011
|
||||
F: 11100
|
||||
G: 11101
|
||||
H: 11110
|
||||
I: 111110
|
||||
J: 111111
|
||||
|
||||
Let's make the first table three bits long (eight entries):
|
||||
|
||||
000: A,1
|
||||
001: A,1
|
||||
010: A,1
|
||||
011: A,1
|
||||
100: B,2
|
||||
101: B,2
|
||||
110: -> table X (gobble 3 bits)
|
||||
111: -> table Y (gobble 3 bits)
|
||||
|
||||
Each entry is what the bits decode as and how many bits that is, i.e. how
|
||||
many bits to gobble. Or the entry points to another table, with the number of
|
||||
bits to gobble implicit in the size of the table.
|
||||
|
||||
Table X is two bits long since the longest code starting with 110 is five bits
|
||||
long:
|
||||
|
||||
00: C,1
|
||||
01: C,1
|
||||
10: D,2
|
||||
11: E,2
|
||||
|
||||
Table Y is three bits long since the longest code starting with 111 is six
|
||||
bits long:
|
||||
|
||||
000: F,2
|
||||
001: F,2
|
||||
010: G,2
|
||||
011: G,2
|
||||
100: H,2
|
||||
101: H,2
|
||||
110: I,3
|
||||
111: J,3
|
||||
|
||||
So what we have here are three tables with a total of 20 entries that had to
|
||||
be constructed. That's compared to 64 entries for a single table. Or
|
||||
compared to 16 entries for a Huffman tree (six two entry tables and one four
|
||||
entry table). Assuming that the code ideally represents the probability of
|
||||
the symbols, it takes on the average 1.25 lookups per symbol. That's compared
|
||||
to one lookup for the single table, or 1.66 lookups per symbol for the
|
||||
Huffman tree.
|
||||
|
||||
There, I think that gives you a picture of what's going on. For inflate, the
|
||||
meaning of a particular symbol is often more than just a letter. It can be a
|
||||
byte (a "literal"), or it can be either a length or a distance which
|
||||
indicates a base value and a number of bits to fetch after the code that is
|
||||
added to the base value. Or it might be the special end-of-block code. The
|
||||
data structures created in inftrees.c try to encode all that information
|
||||
compactly in the tables.
|
||||
|
||||
|
||||
Jean-loup Gailly Mark Adler
|
||||
jloup@gzip.org madler@alumni.caltech.edu
|
||||
|
||||
|
||||
References:
|
||||
|
||||
[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
|
||||
Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
|
||||
pp. 337-343.
|
||||
|
||||
``DEFLATE Compressed Data Format Specification'' available in
|
||||
http://tools.ietf.org/html/rfc1951
|
||||
@@ -0,0 +1,619 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group P. Deutsch
|
||||
Request for Comments: 1950 Aladdin Enterprises
|
||||
Category: Informational J-L. Gailly
|
||||
Info-ZIP
|
||||
May 1996
|
||||
|
||||
|
||||
ZLIB Compressed Data Format Specification version 3.3
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This memo provides information for the Internet community. This memo
|
||||
does not specify an Internet standard of any kind. Distribution of
|
||||
this memo is unlimited.
|
||||
|
||||
IESG Note:
|
||||
|
||||
The IESG takes no position on the validity of any Intellectual
|
||||
Property Rights statements contained in this document.
|
||||
|
||||
Notices
|
||||
|
||||
Copyright (c) 1996 L. Peter Deutsch and Jean-Loup Gailly
|
||||
|
||||
Permission is granted to copy and distribute this document for any
|
||||
purpose and without charge, including translations into other
|
||||
languages and incorporation into compilations, provided that the
|
||||
copyright notice and this notice are preserved, and that any
|
||||
substantive changes or deletions from the original are clearly
|
||||
marked.
|
||||
|
||||
A pointer to the latest version of this and related documentation in
|
||||
HTML format can be found at the URL
|
||||
<ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html>.
|
||||
|
||||
Abstract
|
||||
|
||||
This specification defines a lossless compressed data format. The
|
||||
data can be produced or consumed, even for an arbitrarily long
|
||||
sequentially presented input data stream, using only an a priori
|
||||
bounded amount of intermediate storage. The format presently uses
|
||||
the DEFLATE compression method but can be easily extended to use
|
||||
other compression methods. It can be implemented readily in a manner
|
||||
not covered by patents. This specification also defines the ADLER-32
|
||||
checksum (an extension and improvement of the Fletcher checksum),
|
||||
used for detection of data corruption, and provides an algorithm for
|
||||
computing it.
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 1]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction ................................................... 2
|
||||
1.1. Purpose ................................................... 2
|
||||
1.2. Intended audience ......................................... 3
|
||||
1.3. Scope ..................................................... 3
|
||||
1.4. Compliance ................................................ 3
|
||||
1.5. Definitions of terms and conventions used ................ 3
|
||||
1.6. Changes from previous versions ............................ 3
|
||||
2. Detailed specification ......................................... 3
|
||||
2.1. Overall conventions ....................................... 3
|
||||
2.2. Data format ............................................... 4
|
||||
2.3. Compliance ................................................ 7
|
||||
3. References ..................................................... 7
|
||||
4. Source code .................................................... 8
|
||||
5. Security Considerations ........................................ 8
|
||||
6. Acknowledgements ............................................... 8
|
||||
7. Authors' Addresses ............................................. 8
|
||||
8. Appendix: Rationale ............................................ 9
|
||||
9. Appendix: Sample code ..........................................10
|
||||
|
||||
1. Introduction
|
||||
|
||||
1.1. Purpose
|
||||
|
||||
The purpose of this specification is to define a lossless
|
||||
compressed data format that:
|
||||
|
||||
* Is independent of CPU type, operating system, file system,
|
||||
and character set, and hence can be used for interchange;
|
||||
|
||||
* Can be produced or consumed, even for an arbitrarily long
|
||||
sequentially presented input data stream, using only an a
|
||||
priori bounded amount of intermediate storage, and hence can
|
||||
be used in data communications or similar structures such as
|
||||
Unix filters;
|
||||
|
||||
* Can use a number of different compression methods;
|
||||
|
||||
* Can be implemented readily in a manner not covered by
|
||||
patents, and hence can be practiced freely.
|
||||
|
||||
The data format defined by this specification does not attempt to
|
||||
allow random access to compressed data.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 2]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
1.2. Intended audience
|
||||
|
||||
This specification is intended for use by implementors of software
|
||||
to compress data into zlib format and/or decompress data from zlib
|
||||
format.
|
||||
|
||||
The text of the specification assumes a basic background in
|
||||
programming at the level of bits and other primitive data
|
||||
representations.
|
||||
|
||||
1.3. Scope
|
||||
|
||||
The specification specifies a compressed data format that can be
|
||||
used for in-memory compression of a sequence of arbitrary bytes.
|
||||
|
||||
1.4. Compliance
|
||||
|
||||
Unless otherwise indicated below, a compliant decompressor must be
|
||||
able to accept and decompress any data set that conforms to all
|
||||
the specifications presented here; a compliant compressor must
|
||||
produce data sets that conform to all the specifications presented
|
||||
here.
|
||||
|
||||
1.5. Definitions of terms and conventions used
|
||||
|
||||
byte: 8 bits stored or transmitted as a unit (same as an octet).
|
||||
(For this specification, a byte is exactly 8 bits, even on
|
||||
machines which store a character on a number of bits different
|
||||
from 8.) See below, for the numbering of bits within a byte.
|
||||
|
||||
1.6. Changes from previous versions
|
||||
|
||||
Version 3.1 was the first public release of this specification.
|
||||
In version 3.2, some terminology was changed and the Adler-32
|
||||
sample code was rewritten for clarity. In version 3.3, the
|
||||
support for a preset dictionary was introduced, and the
|
||||
specification was converted to RFC style.
|
||||
|
||||
2. Detailed specification
|
||||
|
||||
2.1. Overall conventions
|
||||
|
||||
In the diagrams below, a box like this:
|
||||
|
||||
+---+
|
||||
| | <-- the vertical bars might be missing
|
||||
+---+
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 3]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
represents one byte; a box like this:
|
||||
|
||||
+==============+
|
||||
| |
|
||||
+==============+
|
||||
|
||||
represents a variable number of bytes.
|
||||
|
||||
Bytes stored within a computer do not have a "bit order", since
|
||||
they are always treated as a unit. However, a byte considered as
|
||||
an integer between 0 and 255 does have a most- and least-
|
||||
significant bit, and since we write numbers with the most-
|
||||
significant digit on the left, we also write bytes with the most-
|
||||
significant bit on the left. In the diagrams below, we number the
|
||||
bits of a byte so that bit 0 is the least-significant bit, i.e.,
|
||||
the bits are numbered:
|
||||
|
||||
+--------+
|
||||
|76543210|
|
||||
+--------+
|
||||
|
||||
Within a computer, a number may occupy multiple bytes. All
|
||||
multi-byte numbers in the format described here are stored with
|
||||
the MOST-significant byte first (at the lower memory address).
|
||||
For example, the decimal number 520 is stored as:
|
||||
|
||||
0 1
|
||||
+--------+--------+
|
||||
|00000010|00001000|
|
||||
+--------+--------+
|
||||
^ ^
|
||||
| |
|
||||
| + less significant byte = 8
|
||||
+ more significant byte = 2 x 256
|
||||
|
||||
2.2. Data format
|
||||
|
||||
A zlib stream has the following structure:
|
||||
|
||||
0 1
|
||||
+---+---+
|
||||
|CMF|FLG| (more-->)
|
||||
+---+---+
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 4]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
(if FLG.FDICT set)
|
||||
|
||||
0 1 2 3
|
||||
+---+---+---+---+
|
||||
| DICTID | (more-->)
|
||||
+---+---+---+---+
|
||||
|
||||
+=====================+---+---+---+---+
|
||||
|...compressed data...| ADLER32 |
|
||||
+=====================+---+---+---+---+
|
||||
|
||||
Any data which may appear after ADLER32 are not part of the zlib
|
||||
stream.
|
||||
|
||||
CMF (Compression Method and flags)
|
||||
This byte is divided into a 4-bit compression method and a 4-
|
||||
bit information field depending on the compression method.
|
||||
|
||||
bits 0 to 3 CM Compression method
|
||||
bits 4 to 7 CINFO Compression info
|
||||
|
||||
CM (Compression method)
|
||||
This identifies the compression method used in the file. CM = 8
|
||||
denotes the "deflate" compression method with a window size up
|
||||
to 32K. This is the method used by gzip and PNG (see
|
||||
references [1] and [2] in Chapter 3, below, for the reference
|
||||
documents). CM = 15 is reserved. It might be used in a future
|
||||
version of this specification to indicate the presence of an
|
||||
extra field before the compressed data.
|
||||
|
||||
CINFO (Compression info)
|
||||
For CM = 8, CINFO is the base-2 logarithm of the LZ77 window
|
||||
size, minus eight (CINFO=7 indicates a 32K window size). Values
|
||||
of CINFO above 7 are not allowed in this version of the
|
||||
specification. CINFO is not defined in this specification for
|
||||
CM not equal to 8.
|
||||
|
||||
FLG (FLaGs)
|
||||
This flag byte is divided as follows:
|
||||
|
||||
bits 0 to 4 FCHECK (check bits for CMF and FLG)
|
||||
bit 5 FDICT (preset dictionary)
|
||||
bits 6 to 7 FLEVEL (compression level)
|
||||
|
||||
The FCHECK value must be such that CMF and FLG, when viewed as
|
||||
a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG),
|
||||
is a multiple of 31.
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 5]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
FDICT (Preset dictionary)
|
||||
If FDICT is set, a DICT dictionary identifier is present
|
||||
immediately after the FLG byte. The dictionary is a sequence of
|
||||
bytes which are initially fed to the compressor without
|
||||
producing any compressed output. DICT is the Adler-32 checksum
|
||||
of this sequence of bytes (see the definition of ADLER32
|
||||
below). The decompressor can use this identifier to determine
|
||||
which dictionary has been used by the compressor.
|
||||
|
||||
FLEVEL (Compression level)
|
||||
These flags are available for use by specific compression
|
||||
methods. The "deflate" method (CM = 8) sets these flags as
|
||||
follows:
|
||||
|
||||
0 - compressor used fastest algorithm
|
||||
1 - compressor used fast algorithm
|
||||
2 - compressor used default algorithm
|
||||
3 - compressor used maximum compression, slowest algorithm
|
||||
|
||||
The information in FLEVEL is not needed for decompression; it
|
||||
is there to indicate if recompression might be worthwhile.
|
||||
|
||||
compressed data
|
||||
For compression method 8, the compressed data is stored in the
|
||||
deflate compressed data format as described in the document
|
||||
"DEFLATE Compressed Data Format Specification" by L. Peter
|
||||
Deutsch. (See reference [3] in Chapter 3, below)
|
||||
|
||||
Other compressed data formats are not specified in this version
|
||||
of the zlib specification.
|
||||
|
||||
ADLER32 (Adler-32 checksum)
|
||||
This contains a checksum value of the uncompressed data
|
||||
(excluding any dictionary data) computed according to Adler-32
|
||||
algorithm. This algorithm is a 32-bit extension and improvement
|
||||
of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
|
||||
standard. See references [4] and [5] in Chapter 3, below)
|
||||
|
||||
Adler-32 is composed of two sums accumulated per byte: s1 is
|
||||
the sum of all bytes, s2 is the sum of all s1 values. Both sums
|
||||
are done modulo 65521. s1 is initialized to 1, s2 to zero. The
|
||||
Adler-32 checksum is stored as s2*65536 + s1 in most-
|
||||
significant-byte first (network) order.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 6]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
2.3. Compliance
|
||||
|
||||
A compliant compressor must produce streams with correct CMF, FLG
|
||||
and ADLER32, but need not support preset dictionaries. When the
|
||||
zlib data format is used as part of another standard data format,
|
||||
the compressor may use only preset dictionaries that are specified
|
||||
by this other data format. If this other format does not use the
|
||||
preset dictionary feature, the compressor must not set the FDICT
|
||||
flag.
|
||||
|
||||
A compliant decompressor must check CMF, FLG, and ADLER32, and
|
||||
provide an error indication if any of these have incorrect values.
|
||||
A compliant decompressor must give an error indication if CM is
|
||||
not one of the values defined in this specification (only the
|
||||
value 8 is permitted in this version), since another value could
|
||||
indicate the presence of new features that would cause subsequent
|
||||
data to be interpreted incorrectly. A compliant decompressor must
|
||||
give an error indication if FDICT is set and DICTID is not the
|
||||
identifier of a known preset dictionary. A decompressor may
|
||||
ignore FLEVEL and still be compliant. When the zlib data format
|
||||
is being used as a part of another standard format, a compliant
|
||||
decompressor must support all the preset dictionaries specified by
|
||||
the other format. When the other format does not use the preset
|
||||
dictionary feature, a compliant decompressor must reject any
|
||||
stream in which the FDICT flag is set.
|
||||
|
||||
3. References
|
||||
|
||||
[1] Deutsch, L.P.,"GZIP Compressed Data Format Specification",
|
||||
available in ftp://ftp.uu.net/pub/archiving/zip/doc/
|
||||
|
||||
[2] Thomas Boutell, "PNG (Portable Network Graphics) specification",
|
||||
available in ftp://ftp.uu.net/graphics/png/documents/
|
||||
|
||||
[3] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification",
|
||||
available in ftp://ftp.uu.net/pub/archiving/zip/doc/
|
||||
|
||||
[4] Fletcher, J. G., "An Arithmetic Checksum for Serial
|
||||
Transmissions," IEEE Transactions on Communications, Vol. COM-30,
|
||||
No. 1, January 1982, pp. 247-252.
|
||||
|
||||
[5] ITU-T Recommendation X.224, Annex D, "Checksum Algorithms,"
|
||||
November, 1993, pp. 144, 145. (Available from
|
||||
gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 7]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
4. Source code
|
||||
|
||||
Source code for a C language implementation of a "zlib" compliant
|
||||
library is available at ftp://ftp.uu.net/pub/archiving/zip/zlib/.
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
A decoder that fails to check the ADLER32 checksum value may be
|
||||
subject to undetected data corruption.
|
||||
|
||||
6. Acknowledgements
|
||||
|
||||
Trademarks cited in this document are the property of their
|
||||
respective owners.
|
||||
|
||||
Jean-Loup Gailly and Mark Adler designed the zlib format and wrote
|
||||
the related software described in this specification. Glenn
|
||||
Randers-Pehrson converted this document to RFC and HTML format.
|
||||
|
||||
7. Authors' Addresses
|
||||
|
||||
L. Peter Deutsch
|
||||
Aladdin Enterprises
|
||||
203 Santa Margarita Ave.
|
||||
Menlo Park, CA 94025
|
||||
|
||||
Phone: (415) 322-0103 (AM only)
|
||||
FAX: (415) 322-1734
|
||||
EMail: <ghost@aladdin.com>
|
||||
|
||||
|
||||
Jean-Loup Gailly
|
||||
|
||||
EMail: <gzip@prep.ai.mit.edu>
|
||||
|
||||
Questions about the technical content of this specification can be
|
||||
sent by email to
|
||||
|
||||
Jean-Loup Gailly <gzip@prep.ai.mit.edu> and
|
||||
Mark Adler <madler@alumni.caltech.edu>
|
||||
|
||||
Editorial comments on this specification can be sent by email to
|
||||
|
||||
L. Peter Deutsch <ghost@aladdin.com> and
|
||||
Glenn Randers-Pehrson <randeg@alumni.rpi.edu>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 8]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
8. Appendix: Rationale
|
||||
|
||||
8.1. Preset dictionaries
|
||||
|
||||
A preset dictionary is specially useful to compress short input
|
||||
sequences. The compressor can take advantage of the dictionary
|
||||
context to encode the input in a more compact manner. The
|
||||
decompressor can be initialized with the appropriate context by
|
||||
virtually decompressing a compressed version of the dictionary
|
||||
without producing any output. However for certain compression
|
||||
algorithms such as the deflate algorithm this operation can be
|
||||
achieved without actually performing any decompression.
|
||||
|
||||
The compressor and the decompressor must use exactly the same
|
||||
dictionary. The dictionary may be fixed or may be chosen among a
|
||||
certain number of predefined dictionaries, according to the kind
|
||||
of input data. The decompressor can determine which dictionary has
|
||||
been chosen by the compressor by checking the dictionary
|
||||
identifier. This document does not specify the contents of
|
||||
predefined dictionaries, since the optimal dictionaries are
|
||||
application specific. Standard data formats using this feature of
|
||||
the zlib specification must precisely define the allowed
|
||||
dictionaries.
|
||||
|
||||
8.2. The Adler-32 algorithm
|
||||
|
||||
The Adler-32 algorithm is much faster than the CRC32 algorithm yet
|
||||
still provides an extremely low probability of undetected errors.
|
||||
|
||||
The modulo on unsigned long accumulators can be delayed for 5552
|
||||
bytes, so the modulo operation time is negligible. If the bytes
|
||||
are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
|
||||
and order sensitive, unlike the first sum, which is just a
|
||||
checksum. That 65521 is prime is important to avoid a possible
|
||||
large class of two-byte errors that leave the check unchanged.
|
||||
(The Fletcher checksum uses 255, which is not prime and which also
|
||||
makes the Fletcher check insensitive to single byte changes 0 <->
|
||||
255.)
|
||||
|
||||
The sum s1 is initialized to 1 instead of zero to make the length
|
||||
of the sequence part of s2, so that the length does not have to be
|
||||
checked separately. (Any sequence of zeroes has a Fletcher
|
||||
checksum of zero.)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 9]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
9. Appendix: Sample code
|
||||
|
||||
The following C code computes the Adler-32 checksum of a data buffer.
|
||||
It is written for clarity, not for speed. The sample code is in the
|
||||
ANSI C programming language. Non C users may find it easier to read
|
||||
with these hints:
|
||||
|
||||
& Bitwise AND operator.
|
||||
>> Bitwise right shift operator. When applied to an
|
||||
unsigned quantity, as here, right shift inserts zero bit(s)
|
||||
at the left.
|
||||
<< Bitwise left shift operator. Left shift inserts zero
|
||||
bit(s) at the right.
|
||||
++ "n++" increments the variable n.
|
||||
% modulo operator: a % b is the remainder of a divided by b.
|
||||
|
||||
#define BASE 65521 /* largest prime smaller than 65536 */
|
||||
|
||||
/*
|
||||
Update a running Adler-32 checksum with the bytes buf[0..len-1]
|
||||
and return the updated checksum. The Adler-32 checksum should be
|
||||
initialized to 1.
|
||||
|
||||
Usage example:
|
||||
|
||||
unsigned long adler = 1L;
|
||||
|
||||
while (read_buffer(buffer, length) != EOF) {
|
||||
adler = update_adler32(adler, buffer, length);
|
||||
}
|
||||
if (adler != original_adler) error();
|
||||
*/
|
||||
unsigned long update_adler32(unsigned long adler,
|
||||
unsigned char *buf, int len)
|
||||
{
|
||||
unsigned long s1 = adler & 0xffff;
|
||||
unsigned long s2 = (adler >> 16) & 0xffff;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < len; n++) {
|
||||
s1 = (s1 + buf[n]) % BASE;
|
||||
s2 = (s2 + s1) % BASE;
|
||||
}
|
||||
return (s2 << 16) + s1;
|
||||
}
|
||||
|
||||
/* Return the adler32 of the bytes buf[0..len-1] */
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 10]
|
||||
|
||||
RFC 1950 ZLIB Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
unsigned long adler32(unsigned char *buf, int len)
|
||||
{
|
||||
return update_adler32(1L, buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch & Gailly Informational [Page 11]
|
||||
|
||||
@@ -0,0 +1,955 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group P. Deutsch
|
||||
Request for Comments: 1951 Aladdin Enterprises
|
||||
Category: Informational May 1996
|
||||
|
||||
|
||||
DEFLATE Compressed Data Format Specification version 1.3
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This memo provides information for the Internet community. This memo
|
||||
does not specify an Internet standard of any kind. Distribution of
|
||||
this memo is unlimited.
|
||||
|
||||
IESG Note:
|
||||
|
||||
The IESG takes no position on the validity of any Intellectual
|
||||
Property Rights statements contained in this document.
|
||||
|
||||
Notices
|
||||
|
||||
Copyright (c) 1996 L. Peter Deutsch
|
||||
|
||||
Permission is granted to copy and distribute this document for any
|
||||
purpose and without charge, including translations into other
|
||||
languages and incorporation into compilations, provided that the
|
||||
copyright notice and this notice are preserved, and that any
|
||||
substantive changes or deletions from the original are clearly
|
||||
marked.
|
||||
|
||||
A pointer to the latest version of this and related documentation in
|
||||
HTML format can be found at the URL
|
||||
<ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html>.
|
||||
|
||||
Abstract
|
||||
|
||||
This specification defines a lossless compressed data format that
|
||||
compresses data using a combination of the LZ77 algorithm and Huffman
|
||||
coding, with efficiency comparable to the best currently available
|
||||
general-purpose compression methods. The data can be produced or
|
||||
consumed, even for an arbitrarily long sequentially presented input
|
||||
data stream, using only an a priori bounded amount of intermediate
|
||||
storage. The format can be implemented readily in a manner not
|
||||
covered by patents.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 1]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction ................................................... 2
|
||||
1.1. Purpose ................................................... 2
|
||||
1.2. Intended audience ......................................... 3
|
||||
1.3. Scope ..................................................... 3
|
||||
1.4. Compliance ................................................ 3
|
||||
1.5. Definitions of terms and conventions used ................ 3
|
||||
1.6. Changes from previous versions ............................ 4
|
||||
2. Compressed representation overview ............................. 4
|
||||
3. Detailed specification ......................................... 5
|
||||
3.1. Overall conventions ....................................... 5
|
||||
3.1.1. Packing into bytes .................................. 5
|
||||
3.2. Compressed block format ................................... 6
|
||||
3.2.1. Synopsis of prefix and Huffman coding ............... 6
|
||||
3.2.2. Use of Huffman coding in the "deflate" format ....... 7
|
||||
3.2.3. Details of block format ............................. 9
|
||||
3.2.4. Non-compressed blocks (BTYPE=00) ................... 11
|
||||
3.2.5. Compressed blocks (length and distance codes) ...... 11
|
||||
3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12
|
||||
3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13
|
||||
3.3. Compliance ............................................... 14
|
||||
4. Compression algorithm details ................................. 14
|
||||
5. References .................................................... 16
|
||||
6. Security Considerations ....................................... 16
|
||||
7. Source code ................................................... 16
|
||||
8. Acknowledgements .............................................. 16
|
||||
9. Author's Address .............................................. 17
|
||||
|
||||
1. Introduction
|
||||
|
||||
1.1. Purpose
|
||||
|
||||
The purpose of this specification is to define a lossless
|
||||
compressed data format that:
|
||||
* Is independent of CPU type, operating system, file system,
|
||||
and character set, and hence can be used for interchange;
|
||||
* Can be produced or consumed, even for an arbitrarily long
|
||||
sequentially presented input data stream, using only an a
|
||||
priori bounded amount of intermediate storage, and hence
|
||||
can be used in data communications or similar structures
|
||||
such as Unix filters;
|
||||
* Compresses data with efficiency comparable to the best
|
||||
currently available general-purpose compression methods,
|
||||
and in particular considerably better than the "compress"
|
||||
program;
|
||||
* Can be implemented readily in a manner not covered by
|
||||
patents, and hence can be practiced freely;
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 2]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
* Is compatible with the file format produced by the current
|
||||
widely used gzip utility, in that conforming decompressors
|
||||
will be able to read data produced by the existing gzip
|
||||
compressor.
|
||||
|
||||
The data format defined by this specification does not attempt to:
|
||||
|
||||
* Allow random access to compressed data;
|
||||
* Compress specialized data (e.g., raster graphics) as well
|
||||
as the best currently available specialized algorithms.
|
||||
|
||||
A simple counting argument shows that no lossless compression
|
||||
algorithm can compress every possible input data set. For the
|
||||
format defined here, the worst case expansion is 5 bytes per 32K-
|
||||
byte block, i.e., a size increase of 0.015% for large data sets.
|
||||
English text usually compresses by a factor of 2.5 to 3;
|
||||
executable files usually compress somewhat less; graphical data
|
||||
such as raster images may compress much more.
|
||||
|
||||
1.2. Intended audience
|
||||
|
||||
This specification is intended for use by implementors of software
|
||||
to compress data into "deflate" format and/or decompress data from
|
||||
"deflate" format.
|
||||
|
||||
The text of the specification assumes a basic background in
|
||||
programming at the level of bits and other primitive data
|
||||
representations. Familiarity with the technique of Huffman coding
|
||||
is helpful but not required.
|
||||
|
||||
1.3. Scope
|
||||
|
||||
The specification specifies a method for representing a sequence
|
||||
of bytes as a (usually shorter) sequence of bits, and a method for
|
||||
packing the latter bit sequence into bytes.
|
||||
|
||||
1.4. Compliance
|
||||
|
||||
Unless otherwise indicated below, a compliant decompressor must be
|
||||
able to accept and decompress any data set that conforms to all
|
||||
the specifications presented here; a compliant compressor must
|
||||
produce data sets that conform to all the specifications presented
|
||||
here.
|
||||
|
||||
1.5. Definitions of terms and conventions used
|
||||
|
||||
Byte: 8 bits stored or transmitted as a unit (same as an octet).
|
||||
For this specification, a byte is exactly 8 bits, even on machines
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 3]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
which store a character on a number of bits different from eight.
|
||||
See below, for the numbering of bits within a byte.
|
||||
|
||||
String: a sequence of arbitrary bytes.
|
||||
|
||||
1.6. Changes from previous versions
|
||||
|
||||
There have been no technical changes to the deflate format since
|
||||
version 1.1 of this specification. In version 1.2, some
|
||||
terminology was changed. Version 1.3 is a conversion of the
|
||||
specification to RFC style.
|
||||
|
||||
2. Compressed representation overview
|
||||
|
||||
A compressed data set consists of a series of blocks, corresponding
|
||||
to successive blocks of input data. The block sizes are arbitrary,
|
||||
except that non-compressible blocks are limited to 65,535 bytes.
|
||||
|
||||
Each block is compressed using a combination of the LZ77 algorithm
|
||||
and Huffman coding. The Huffman trees for each block are independent
|
||||
of those for previous or subsequent blocks; the LZ77 algorithm may
|
||||
use a reference to a duplicated string occurring in a previous block,
|
||||
up to 32K input bytes before.
|
||||
|
||||
Each block consists of two parts: a pair of Huffman code trees that
|
||||
describe the representation of the compressed data part, and a
|
||||
compressed data part. (The Huffman trees themselves are compressed
|
||||
using Huffman encoding.) The compressed data consists of a series of
|
||||
elements of two types: literal bytes (of strings that have not been
|
||||
detected as duplicated within the previous 32K input bytes), and
|
||||
pointers to duplicated strings, where a pointer is represented as a
|
||||
pair <length, backward distance>. The representation used in the
|
||||
"deflate" format limits distances to 32K bytes and lengths to 258
|
||||
bytes, but does not limit the size of a block, except for
|
||||
uncompressible blocks, which are limited as noted above.
|
||||
|
||||
Each type of value (literals, distances, and lengths) in the
|
||||
compressed data is represented using a Huffman code, using one code
|
||||
tree for literals and lengths and a separate code tree for distances.
|
||||
The code trees for each block appear in a compact form just before
|
||||
the compressed data for that block.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 4]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
3. Detailed specification
|
||||
|
||||
3.1. Overall conventions In the diagrams below, a box like this:
|
||||
|
||||
+---+
|
||||
| | <-- the vertical bars might be missing
|
||||
+---+
|
||||
|
||||
represents one byte; a box like this:
|
||||
|
||||
+==============+
|
||||
| |
|
||||
+==============+
|
||||
|
||||
represents a variable number of bytes.
|
||||
|
||||
Bytes stored within a computer do not have a "bit order", since
|
||||
they are always treated as a unit. However, a byte considered as
|
||||
an integer between 0 and 255 does have a most- and least-
|
||||
significant bit, and since we write numbers with the most-
|
||||
significant digit on the left, we also write bytes with the most-
|
||||
significant bit on the left. In the diagrams below, we number the
|
||||
bits of a byte so that bit 0 is the least-significant bit, i.e.,
|
||||
the bits are numbered:
|
||||
|
||||
+--------+
|
||||
|76543210|
|
||||
+--------+
|
||||
|
||||
Within a computer, a number may occupy multiple bytes. All
|
||||
multi-byte numbers in the format described here are stored with
|
||||
the least-significant byte first (at the lower memory address).
|
||||
For example, the decimal number 520 is stored as:
|
||||
|
||||
0 1
|
||||
+--------+--------+
|
||||
|00001000|00000010|
|
||||
+--------+--------+
|
||||
^ ^
|
||||
| |
|
||||
| + more significant byte = 2 x 256
|
||||
+ less significant byte = 8
|
||||
|
||||
3.1.1. Packing into bytes
|
||||
|
||||
This document does not address the issue of the order in which
|
||||
bits of a byte are transmitted on a bit-sequential medium,
|
||||
since the final data format described here is byte- rather than
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 5]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
bit-oriented. However, we describe the compressed block format
|
||||
in below, as a sequence of data elements of various bit
|
||||
lengths, not a sequence of bytes. We must therefore specify
|
||||
how to pack these data elements into bytes to form the final
|
||||
compressed byte sequence:
|
||||
|
||||
* Data elements are packed into bytes in order of
|
||||
increasing bit number within the byte, i.e., starting
|
||||
with the least-significant bit of the byte.
|
||||
* Data elements other than Huffman codes are packed
|
||||
starting with the least-significant bit of the data
|
||||
element.
|
||||
* Huffman codes are packed starting with the most-
|
||||
significant bit of the code.
|
||||
|
||||
In other words, if one were to print out the compressed data as
|
||||
a sequence of bytes, starting with the first byte at the
|
||||
*right* margin and proceeding to the *left*, with the most-
|
||||
significant bit of each byte on the left as usual, one would be
|
||||
able to parse the result from right to left, with fixed-width
|
||||
elements in the correct MSB-to-LSB order and Huffman codes in
|
||||
bit-reversed order (i.e., with the first bit of the code in the
|
||||
relative LSB position).
|
||||
|
||||
3.2. Compressed block format
|
||||
|
||||
3.2.1. Synopsis of prefix and Huffman coding
|
||||
|
||||
Prefix coding represents symbols from an a priori known
|
||||
alphabet by bit sequences (codes), one code for each symbol, in
|
||||
a manner such that different symbols may be represented by bit
|
||||
sequences of different lengths, but a parser can always parse
|
||||
an encoded string unambiguously symbol-by-symbol.
|
||||
|
||||
We define a prefix code in terms of a binary tree in which the
|
||||
two edges descending from each non-leaf node are labeled 0 and
|
||||
1 and in which the leaf nodes correspond one-for-one with (are
|
||||
labeled with) the symbols of the alphabet; then the code for a
|
||||
symbol is the sequence of 0's and 1's on the edges leading from
|
||||
the root to the leaf labeled with that symbol. For example:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 6]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
/\ Symbol Code
|
||||
0 1 ------ ----
|
||||
/ \ A 00
|
||||
/\ B B 1
|
||||
0 1 C 011
|
||||
/ \ D 010
|
||||
A /\
|
||||
0 1
|
||||
/ \
|
||||
D C
|
||||
|
||||
A parser can decode the next symbol from an encoded input
|
||||
stream by walking down the tree from the root, at each step
|
||||
choosing the edge corresponding to the next input bit.
|
||||
|
||||
Given an alphabet with known symbol frequencies, the Huffman
|
||||
algorithm allows the construction of an optimal prefix code
|
||||
(one which represents strings with those symbol frequencies
|
||||
using the fewest bits of any possible prefix codes for that
|
||||
alphabet). Such a code is called a Huffman code. (See
|
||||
reference [1] in Chapter 5, references for additional
|
||||
information on Huffman codes.)
|
||||
|
||||
Note that in the "deflate" format, the Huffman codes for the
|
||||
various alphabets must not exceed certain maximum code lengths.
|
||||
This constraint complicates the algorithm for computing code
|
||||
lengths from symbol frequencies. Again, see Chapter 5,
|
||||
references for details.
|
||||
|
||||
3.2.2. Use of Huffman coding in the "deflate" format
|
||||
|
||||
The Huffman codes used for each alphabet in the "deflate"
|
||||
format have two additional rules:
|
||||
|
||||
* All codes of a given bit length have lexicographically
|
||||
consecutive values, in the same order as the symbols
|
||||
they represent;
|
||||
|
||||
* Shorter codes lexicographically precede longer codes.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 7]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
We could recode the example above to follow this rule as
|
||||
follows, assuming that the order of the alphabet is ABCD:
|
||||
|
||||
Symbol Code
|
||||
------ ----
|
||||
A 10
|
||||
B 0
|
||||
C 110
|
||||
D 111
|
||||
|
||||
I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are
|
||||
lexicographically consecutive.
|
||||
|
||||
Given this rule, we can define the Huffman code for an alphabet
|
||||
just by giving the bit lengths of the codes for each symbol of
|
||||
the alphabet in order; this is sufficient to determine the
|
||||
actual codes. In our example, the code is completely defined
|
||||
by the sequence of bit lengths (2, 1, 3, 3). The following
|
||||
algorithm generates the codes as integers, intended to be read
|
||||
from most- to least-significant bit. The code lengths are
|
||||
initially in tree[I].Len; the codes are produced in
|
||||
tree[I].Code.
|
||||
|
||||
1) Count the number of codes for each code length. Let
|
||||
bl_count[N] be the number of codes of length N, N >= 1.
|
||||
|
||||
2) Find the numerical value of the smallest code for each
|
||||
code length:
|
||||
|
||||
code = 0;
|
||||
bl_count[0] = 0;
|
||||
for (bits = 1; bits <= MAX_BITS; bits++) {
|
||||
code = (code + bl_count[bits-1]) << 1;
|
||||
next_code[bits] = code;
|
||||
}
|
||||
|
||||
3) Assign numerical values to all codes, using consecutive
|
||||
values for all codes of the same length with the base
|
||||
values determined at step 2. Codes that are never used
|
||||
(which have a bit length of zero) must not be assigned a
|
||||
value.
|
||||
|
||||
for (n = 0; n <= max_code; n++) {
|
||||
len = tree[n].Len;
|
||||
if (len != 0) {
|
||||
tree[n].Code = next_code[len];
|
||||
next_code[len]++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 8]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
}
|
||||
|
||||
Example:
|
||||
|
||||
Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3,
|
||||
3, 2, 4, 4). After step 1, we have:
|
||||
|
||||
N bl_count[N]
|
||||
- -----------
|
||||
2 1
|
||||
3 5
|
||||
4 2
|
||||
|
||||
Step 2 computes the following next_code values:
|
||||
|
||||
N next_code[N]
|
||||
- ------------
|
||||
1 0
|
||||
2 0
|
||||
3 2
|
||||
4 14
|
||||
|
||||
Step 3 produces the following code values:
|
||||
|
||||
Symbol Length Code
|
||||
------ ------ ----
|
||||
A 3 010
|
||||
B 3 011
|
||||
C 3 100
|
||||
D 3 101
|
||||
E 3 110
|
||||
F 2 00
|
||||
G 4 1110
|
||||
H 4 1111
|
||||
|
||||
3.2.3. Details of block format
|
||||
|
||||
Each block of compressed data begins with 3 header bits
|
||||
containing the following data:
|
||||
|
||||
first bit BFINAL
|
||||
next 2 bits BTYPE
|
||||
|
||||
Note that the header bits do not necessarily begin on a byte
|
||||
boundary, since a block does not necessarily occupy an integral
|
||||
number of bytes.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 9]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
BFINAL is set if and only if this is the last block of the data
|
||||
set.
|
||||
|
||||
BTYPE specifies how the data are compressed, as follows:
|
||||
|
||||
00 - no compression
|
||||
01 - compressed with fixed Huffman codes
|
||||
10 - compressed with dynamic Huffman codes
|
||||
11 - reserved (error)
|
||||
|
||||
The only difference between the two compressed cases is how the
|
||||
Huffman codes for the literal/length and distance alphabets are
|
||||
defined.
|
||||
|
||||
In all cases, the decoding algorithm for the actual data is as
|
||||
follows:
|
||||
|
||||
do
|
||||
read block header from input stream.
|
||||
if stored with no compression
|
||||
skip any remaining bits in current partially
|
||||
processed byte
|
||||
read LEN and NLEN (see next section)
|
||||
copy LEN bytes of data to output
|
||||
otherwise
|
||||
if compressed with dynamic Huffman codes
|
||||
read representation of code trees (see
|
||||
subsection below)
|
||||
loop (until end of block code recognized)
|
||||
decode literal/length value from input stream
|
||||
if value < 256
|
||||
copy value (literal byte) to output stream
|
||||
otherwise
|
||||
if value = end of block (256)
|
||||
break from loop
|
||||
otherwise (value = 257..285)
|
||||
decode distance from input stream
|
||||
|
||||
move backwards distance bytes in the output
|
||||
stream, and copy length bytes from this
|
||||
position to the output stream.
|
||||
end loop
|
||||
while not last block
|
||||
|
||||
Note that a duplicated string reference may refer to a string
|
||||
in a previous block; i.e., the backward distance may cross one
|
||||
or more block boundaries. However a distance cannot refer past
|
||||
the beginning of the output stream. (An application using a
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 10]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
preset dictionary might discard part of the output stream; a
|
||||
distance can refer to that part of the output stream anyway)
|
||||
Note also that the referenced string may overlap the current
|
||||
position; for example, if the last 2 bytes decoded have values
|
||||
X and Y, a string reference with <length = 5, distance = 2>
|
||||
adds X,Y,X,Y,X to the output stream.
|
||||
|
||||
We now specify each compression method in turn.
|
||||
|
||||
3.2.4. Non-compressed blocks (BTYPE=00)
|
||||
|
||||
Any bits of input up to the next byte boundary are ignored.
|
||||
The rest of the block consists of the following information:
|
||||
|
||||
0 1 2 3 4...
|
||||
+---+---+---+---+================================+
|
||||
| LEN | NLEN |... LEN bytes of literal data...|
|
||||
+---+---+---+---+================================+
|
||||
|
||||
LEN is the number of data bytes in the block. NLEN is the
|
||||
one's complement of LEN.
|
||||
|
||||
3.2.5. Compressed blocks (length and distance codes)
|
||||
|
||||
As noted above, encoded data blocks in the "deflate" format
|
||||
consist of sequences of symbols drawn from three conceptually
|
||||
distinct alphabets: either literal bytes, from the alphabet of
|
||||
byte values (0..255), or <length, backward distance> pairs,
|
||||
where the length is drawn from (3..258) and the distance is
|
||||
drawn from (1..32,768). In fact, the literal and length
|
||||
alphabets are merged into a single alphabet (0..285), where
|
||||
values 0..255 represent literal bytes, the value 256 indicates
|
||||
end-of-block, and values 257..285 represent length codes
|
||||
(possibly in conjunction with extra bits following the symbol
|
||||
code) as follows:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 11]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
Extra Extra Extra
|
||||
Code Bits Length(s) Code Bits Lengths Code Bits Length(s)
|
||||
---- ---- ------ ---- ---- ------- ---- ---- -------
|
||||
257 0 3 267 1 15,16 277 4 67-82
|
||||
258 0 4 268 1 17,18 278 4 83-98
|
||||
259 0 5 269 2 19-22 279 4 99-114
|
||||
260 0 6 270 2 23-26 280 4 115-130
|
||||
261 0 7 271 2 27-30 281 5 131-162
|
||||
262 0 8 272 2 31-34 282 5 163-194
|
||||
263 0 9 273 3 35-42 283 5 195-226
|
||||
264 0 10 274 3 43-50 284 5 227-257
|
||||
265 1 11,12 275 3 51-58 285 0 258
|
||||
266 1 13,14 276 3 59-66
|
||||
|
||||
The extra bits should be interpreted as a machine integer
|
||||
stored with the most-significant bit first, e.g., bits 1110
|
||||
represent the value 14.
|
||||
|
||||
Extra Extra Extra
|
||||
Code Bits Dist Code Bits Dist Code Bits Distance
|
||||
---- ---- ---- ---- ---- ------ ---- ---- --------
|
||||
0 0 1 10 4 33-48 20 9 1025-1536
|
||||
1 0 2 11 4 49-64 21 9 1537-2048
|
||||
2 0 3 12 5 65-96 22 10 2049-3072
|
||||
3 0 4 13 5 97-128 23 10 3073-4096
|
||||
4 1 5,6 14 6 129-192 24 11 4097-6144
|
||||
5 1 7,8 15 6 193-256 25 11 6145-8192
|
||||
6 2 9-12 16 7 257-384 26 12 8193-12288
|
||||
7 2 13-16 17 7 385-512 27 12 12289-16384
|
||||
8 3 17-24 18 8 513-768 28 13 16385-24576
|
||||
9 3 25-32 19 8 769-1024 29 13 24577-32768
|
||||
|
||||
3.2.6. Compression with fixed Huffman codes (BTYPE=01)
|
||||
|
||||
The Huffman codes for the two alphabets are fixed, and are not
|
||||
represented explicitly in the data. The Huffman code lengths
|
||||
for the literal/length alphabet are:
|
||||
|
||||
Lit Value Bits Codes
|
||||
--------- ---- -----
|
||||
0 - 143 8 00110000 through
|
||||
10111111
|
||||
144 - 255 9 110010000 through
|
||||
111111111
|
||||
256 - 279 7 0000000 through
|
||||
0010111
|
||||
280 - 287 8 11000000 through
|
||||
11000111
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 12]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
The code lengths are sufficient to generate the actual codes,
|
||||
as described above; we show the codes in the table for added
|
||||
clarity. Literal/length values 286-287 will never actually
|
||||
occur in the compressed data, but participate in the code
|
||||
construction.
|
||||
|
||||
Distance codes 0-31 are represented by (fixed-length) 5-bit
|
||||
codes, with possible additional bits as shown in the table
|
||||
shown in Paragraph 3.2.5, above. Note that distance codes 30-
|
||||
31 will never actually occur in the compressed data.
|
||||
|
||||
3.2.7. Compression with dynamic Huffman codes (BTYPE=10)
|
||||
|
||||
The Huffman codes for the two alphabets appear in the block
|
||||
immediately after the header bits and before the actual
|
||||
compressed data, first the literal/length code and then the
|
||||
distance code. Each code is defined by a sequence of code
|
||||
lengths, as discussed in Paragraph 3.2.2, above. For even
|
||||
greater compactness, the code length sequences themselves are
|
||||
compressed using a Huffman code. The alphabet for code lengths
|
||||
is as follows:
|
||||
|
||||
0 - 15: Represent code lengths of 0 - 15
|
||||
16: Copy the previous code length 3 - 6 times.
|
||||
The next 2 bits indicate repeat length
|
||||
(0 = 3, ... , 3 = 6)
|
||||
Example: Codes 8, 16 (+2 bits 11),
|
||||
16 (+2 bits 10) will expand to
|
||||
12 code lengths of 8 (1 + 6 + 5)
|
||||
17: Repeat a code length of 0 for 3 - 10 times.
|
||||
(3 bits of length)
|
||||
18: Repeat a code length of 0 for 11 - 138 times
|
||||
(7 bits of length)
|
||||
|
||||
A code length of 0 indicates that the corresponding symbol in
|
||||
the literal/length or distance alphabet will not occur in the
|
||||
block, and should not participate in the Huffman code
|
||||
construction algorithm given earlier. If only one distance
|
||||
code is used, it is encoded using one bit, not zero bits; in
|
||||
this case there is a single code length of one, with one unused
|
||||
code. One distance code of zero bits means that there are no
|
||||
distance codes used at all (the data is all literals).
|
||||
|
||||
We can now define the format of the block:
|
||||
|
||||
5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286)
|
||||
5 Bits: HDIST, # of Distance codes - 1 (1 - 32)
|
||||
4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19)
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 13]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
(HCLEN + 4) x 3 bits: code lengths for the code length
|
||||
alphabet given just above, in the order: 16, 17, 18,
|
||||
0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
|
||||
|
||||
These code lengths are interpreted as 3-bit integers
|
||||
(0-7); as above, a code length of 0 means the
|
||||
corresponding symbol (literal/length or distance code
|
||||
length) is not used.
|
||||
|
||||
HLIT + 257 code lengths for the literal/length alphabet,
|
||||
encoded using the code length Huffman code
|
||||
|
||||
HDIST + 1 code lengths for the distance alphabet,
|
||||
encoded using the code length Huffman code
|
||||
|
||||
The actual compressed data of the block,
|
||||
encoded using the literal/length and distance Huffman
|
||||
codes
|
||||
|
||||
The literal/length symbol 256 (end of data),
|
||||
encoded using the literal/length Huffman code
|
||||
|
||||
The code length repeat codes can cross from HLIT + 257 to the
|
||||
HDIST + 1 code lengths. In other words, all code lengths form
|
||||
a single sequence of HLIT + HDIST + 258 values.
|
||||
|
||||
3.3. Compliance
|
||||
|
||||
A compressor may limit further the ranges of values specified in
|
||||
the previous section and still be compliant; for example, it may
|
||||
limit the range of backward pointers to some value smaller than
|
||||
32K. Similarly, a compressor may limit the size of blocks so that
|
||||
a compressible block fits in memory.
|
||||
|
||||
A compliant decompressor must accept the full range of possible
|
||||
values defined in the previous section, and must accept blocks of
|
||||
arbitrary size.
|
||||
|
||||
4. Compression algorithm details
|
||||
|
||||
While it is the intent of this document to define the "deflate"
|
||||
compressed data format without reference to any particular
|
||||
compression algorithm, the format is related to the compressed
|
||||
formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below);
|
||||
since many variations of LZ77 are patented, it is strongly
|
||||
recommended that the implementor of a compressor follow the general
|
||||
algorithm presented here, which is known not to be patented per se.
|
||||
The material in this section is not part of the definition of the
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 14]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
specification per se, and a compressor need not follow it in order to
|
||||
be compliant.
|
||||
|
||||
The compressor terminates a block when it determines that starting a
|
||||
new block with fresh trees would be useful, or when the block size
|
||||
fills up the compressor's block buffer.
|
||||
|
||||
The compressor uses a chained hash table to find duplicated strings,
|
||||
using a hash function that operates on 3-byte sequences. At any
|
||||
given point during compression, let XYZ be the next 3 input bytes to
|
||||
be examined (not necessarily all different, of course). First, the
|
||||
compressor examines the hash chain for XYZ. If the chain is empty,
|
||||
the compressor simply writes out X as a literal byte and advances one
|
||||
byte in the input. If the hash chain is not empty, indicating that
|
||||
the sequence XYZ (or, if we are unlucky, some other 3 bytes with the
|
||||
same hash function value) has occurred recently, the compressor
|
||||
compares all strings on the XYZ hash chain with the actual input data
|
||||
sequence starting at the current point, and selects the longest
|
||||
match.
|
||||
|
||||
The compressor searches the hash chains starting with the most recent
|
||||
strings, to favor small distances and thus take advantage of the
|
||||
Huffman encoding. The hash chains are singly linked. There are no
|
||||
deletions from the hash chains; the algorithm simply discards matches
|
||||
that are too old. To avoid a worst-case situation, very long hash
|
||||
chains are arbitrarily truncated at a certain length, determined by a
|
||||
run-time parameter.
|
||||
|
||||
To improve overall compression, the compressor optionally defers the
|
||||
selection of matches ("lazy matching"): after a match of length N has
|
||||
been found, the compressor searches for a longer match starting at
|
||||
the next input byte. If it finds a longer match, it truncates the
|
||||
previous match to a length of one (thus producing a single literal
|
||||
byte) and then emits the longer match. Otherwise, it emits the
|
||||
original match, and, as described above, advances N bytes before
|
||||
continuing.
|
||||
|
||||
Run-time parameters also control this "lazy match" procedure. If
|
||||
compression ratio is most important, the compressor attempts a
|
||||
complete second search regardless of the length of the first match.
|
||||
In the normal case, if the current match is "long enough", the
|
||||
compressor reduces the search for a longer match, thus speeding up
|
||||
the process. If speed is most important, the compressor inserts new
|
||||
strings in the hash table only when no match was found, or when the
|
||||
match is not "too long". This degrades the compression ratio but
|
||||
saves time since there are both fewer insertions and fewer searches.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 15]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
5. References
|
||||
|
||||
[1] Huffman, D. A., "A Method for the Construction of Minimum
|
||||
Redundancy Codes", Proceedings of the Institute of Radio
|
||||
Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101.
|
||||
|
||||
[2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
|
||||
Compression", IEEE Transactions on Information Theory, Vol. 23,
|
||||
No. 3, pp. 337-343.
|
||||
|
||||
[3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources,
|
||||
available in ftp://ftp.uu.net/pub/archiving/zip/doc/
|
||||
|
||||
[4] Gailly, J.-L., and Adler, M., GZIP documentation and sources,
|
||||
available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/
|
||||
|
||||
[5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix
|
||||
encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169.
|
||||
|
||||
[6] Hirschberg and Lelewer, "Efficient decoding of prefix codes,"
|
||||
Comm. ACM, 33,4, April 1990, pp. 449-459.
|
||||
|
||||
6. Security Considerations
|
||||
|
||||
Any data compression method involves the reduction of redundancy in
|
||||
the data. Consequently, any corruption of the data is likely to have
|
||||
severe effects and be difficult to correct. Uncompressed text, on
|
||||
the other hand, will probably still be readable despite the presence
|
||||
of some corrupted bytes.
|
||||
|
||||
It is recommended that systems using this data format provide some
|
||||
means of validating the integrity of the compressed data. See
|
||||
reference [3], for example.
|
||||
|
||||
7. Source code
|
||||
|
||||
Source code for a C language implementation of a "deflate" compliant
|
||||
compressor and decompressor is available within the zlib package at
|
||||
ftp://ftp.uu.net/pub/archiving/zip/zlib/.
|
||||
|
||||
8. Acknowledgements
|
||||
|
||||
Trademarks cited in this document are the property of their
|
||||
respective owners.
|
||||
|
||||
Phil Katz designed the deflate format. Jean-Loup Gailly and Mark
|
||||
Adler wrote the related software described in this specification.
|
||||
Glenn Randers-Pehrson converted this document to RFC and HTML format.
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 16]
|
||||
|
||||
RFC 1951 DEFLATE Compressed Data Format Specification May 1996
|
||||
|
||||
|
||||
9. Author's Address
|
||||
|
||||
L. Peter Deutsch
|
||||
Aladdin Enterprises
|
||||
203 Santa Margarita Ave.
|
||||
Menlo Park, CA 94025
|
||||
|
||||
Phone: (415) 322-0103 (AM only)
|
||||
FAX: (415) 322-1734
|
||||
EMail: <ghost@aladdin.com>
|
||||
|
||||
Questions about the technical content of this specification can be
|
||||
sent by email to:
|
||||
|
||||
Jean-Loup Gailly <gzip@prep.ai.mit.edu> and
|
||||
Mark Adler <madler@alumni.caltech.edu>
|
||||
|
||||
Editorial comments on this specification can be sent by email to:
|
||||
|
||||
L. Peter Deutsch <ghost@aladdin.com> and
|
||||
Glenn Randers-Pehrson <randeg@alumni.rpi.edu>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 17]
|
||||
|
||||
@@ -0,0 +1,675 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group P. Deutsch
|
||||
Request for Comments: 1952 Aladdin Enterprises
|
||||
Category: Informational May 1996
|
||||
|
||||
|
||||
GZIP file format specification version 4.3
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This memo provides information for the Internet community. This memo
|
||||
does not specify an Internet standard of any kind. Distribution of
|
||||
this memo is unlimited.
|
||||
|
||||
IESG Note:
|
||||
|
||||
The IESG takes no position on the validity of any Intellectual
|
||||
Property Rights statements contained in this document.
|
||||
|
||||
Notices
|
||||
|
||||
Copyright (c) 1996 L. Peter Deutsch
|
||||
|
||||
Permission is granted to copy and distribute this document for any
|
||||
purpose and without charge, including translations into other
|
||||
languages and incorporation into compilations, provided that the
|
||||
copyright notice and this notice are preserved, and that any
|
||||
substantive changes or deletions from the original are clearly
|
||||
marked.
|
||||
|
||||
A pointer to the latest version of this and related documentation in
|
||||
HTML format can be found at the URL
|
||||
<ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html>.
|
||||
|
||||
Abstract
|
||||
|
||||
This specification defines a lossless compressed data format that is
|
||||
compatible with the widely used GZIP utility. The format includes a
|
||||
cyclic redundancy check value for detecting data corruption. The
|
||||
format presently uses the DEFLATE method of compression but can be
|
||||
easily extended to use other compression methods. The format can be
|
||||
implemented readily in a manner not covered by patents.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 1]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction ................................................... 2
|
||||
1.1. Purpose ................................................... 2
|
||||
1.2. Intended audience ......................................... 3
|
||||
1.3. Scope ..................................................... 3
|
||||
1.4. Compliance ................................................ 3
|
||||
1.5. Definitions of terms and conventions used ................. 3
|
||||
1.6. Changes from previous versions ............................ 3
|
||||
2. Detailed specification ......................................... 4
|
||||
2.1. Overall conventions ....................................... 4
|
||||
2.2. File format ............................................... 5
|
||||
2.3. Member format ............................................. 5
|
||||
2.3.1. Member header and trailer ........................... 6
|
||||
2.3.1.1. Extra field ................................... 8
|
||||
2.3.1.2. Compliance .................................... 9
|
||||
3. References .................................................. 9
|
||||
4. Security Considerations .................................... 10
|
||||
5. Acknowledgements ........................................... 10
|
||||
6. Author's Address ........................................... 10
|
||||
7. Appendix: Jean-Loup Gailly's gzip utility .................. 11
|
||||
8. Appendix: Sample CRC Code .................................. 11
|
||||
|
||||
1. Introduction
|
||||
|
||||
1.1. Purpose
|
||||
|
||||
The purpose of this specification is to define a lossless
|
||||
compressed data format that:
|
||||
|
||||
* Is independent of CPU type, operating system, file system,
|
||||
and character set, and hence can be used for interchange;
|
||||
* Can compress or decompress a data stream (as opposed to a
|
||||
randomly accessible file) to produce another data stream,
|
||||
using only an a priori bounded amount of intermediate
|
||||
storage, and hence can be used in data communications or
|
||||
similar structures such as Unix filters;
|
||||
* Compresses data with efficiency comparable to the best
|
||||
currently available general-purpose compression methods,
|
||||
and in particular considerably better than the "compress"
|
||||
program;
|
||||
* Can be implemented readily in a manner not covered by
|
||||
patents, and hence can be practiced freely;
|
||||
* Is compatible with the file format produced by the current
|
||||
widely used gzip utility, in that conforming decompressors
|
||||
will be able to read data produced by the existing gzip
|
||||
compressor.
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 2]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
The data format defined by this specification does not attempt to:
|
||||
|
||||
* Provide random access to compressed data;
|
||||
* Compress specialized data (e.g., raster graphics) as well as
|
||||
the best currently available specialized algorithms.
|
||||
|
||||
1.2. Intended audience
|
||||
|
||||
This specification is intended for use by implementors of software
|
||||
to compress data into gzip format and/or decompress data from gzip
|
||||
format.
|
||||
|
||||
The text of the specification assumes a basic background in
|
||||
programming at the level of bits and other primitive data
|
||||
representations.
|
||||
|
||||
1.3. Scope
|
||||
|
||||
The specification specifies a compression method and a file format
|
||||
(the latter assuming only that a file can store a sequence of
|
||||
arbitrary bytes). It does not specify any particular interface to
|
||||
a file system or anything about character sets or encodings
|
||||
(except for file names and comments, which are optional).
|
||||
|
||||
1.4. Compliance
|
||||
|
||||
Unless otherwise indicated below, a compliant decompressor must be
|
||||
able to accept and decompress any file that conforms to all the
|
||||
specifications presented here; a compliant compressor must produce
|
||||
files that conform to all the specifications presented here. The
|
||||
material in the appendices is not part of the specification per se
|
||||
and is not relevant to compliance.
|
||||
|
||||
1.5. Definitions of terms and conventions used
|
||||
|
||||
byte: 8 bits stored or transmitted as a unit (same as an octet).
|
||||
(For this specification, a byte is exactly 8 bits, even on
|
||||
machines which store a character on a number of bits different
|
||||
from 8.) See below for the numbering of bits within a byte.
|
||||
|
||||
1.6. Changes from previous versions
|
||||
|
||||
There have been no technical changes to the gzip format since
|
||||
version 4.1 of this specification. In version 4.2, some
|
||||
terminology was changed, and the sample CRC code was rewritten for
|
||||
clarity and to eliminate the requirement for the caller to do pre-
|
||||
and post-conditioning. Version 4.3 is a conversion of the
|
||||
specification to RFC style.
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 3]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
2. Detailed specification
|
||||
|
||||
2.1. Overall conventions
|
||||
|
||||
In the diagrams below, a box like this:
|
||||
|
||||
+---+
|
||||
| | <-- the vertical bars might be missing
|
||||
+---+
|
||||
|
||||
represents one byte; a box like this:
|
||||
|
||||
+==============+
|
||||
| |
|
||||
+==============+
|
||||
|
||||
represents a variable number of bytes.
|
||||
|
||||
Bytes stored within a computer do not have a "bit order", since
|
||||
they are always treated as a unit. However, a byte considered as
|
||||
an integer between 0 and 255 does have a most- and least-
|
||||
significant bit, and since we write numbers with the most-
|
||||
significant digit on the left, we also write bytes with the most-
|
||||
significant bit on the left. In the diagrams below, we number the
|
||||
bits of a byte so that bit 0 is the least-significant bit, i.e.,
|
||||
the bits are numbered:
|
||||
|
||||
+--------+
|
||||
|76543210|
|
||||
+--------+
|
||||
|
||||
This document does not address the issue of the order in which
|
||||
bits of a byte are transmitted on a bit-sequential medium, since
|
||||
the data format described here is byte- rather than bit-oriented.
|
||||
|
||||
Within a computer, a number may occupy multiple bytes. All
|
||||
multi-byte numbers in the format described here are stored with
|
||||
the least-significant byte first (at the lower memory address).
|
||||
For example, the decimal number 520 is stored as:
|
||||
|
||||
0 1
|
||||
+--------+--------+
|
||||
|00001000|00000010|
|
||||
+--------+--------+
|
||||
^ ^
|
||||
| |
|
||||
| + more significant byte = 2 x 256
|
||||
+ less significant byte = 8
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 4]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
2.2. File format
|
||||
|
||||
A gzip file consists of a series of "members" (compressed data
|
||||
sets). The format of each member is specified in the following
|
||||
section. The members simply appear one after another in the file,
|
||||
with no additional information before, between, or after them.
|
||||
|
||||
2.3. Member format
|
||||
|
||||
Each member has the following structure:
|
||||
|
||||
+---+---+---+---+---+---+---+---+---+---+
|
||||
|ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->)
|
||||
+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
(if FLG.FEXTRA set)
|
||||
|
||||
+---+---+=================================+
|
||||
| XLEN |...XLEN bytes of "extra field"...| (more-->)
|
||||
+---+---+=================================+
|
||||
|
||||
(if FLG.FNAME set)
|
||||
|
||||
+=========================================+
|
||||
|...original file name, zero-terminated...| (more-->)
|
||||
+=========================================+
|
||||
|
||||
(if FLG.FCOMMENT set)
|
||||
|
||||
+===================================+
|
||||
|...file comment, zero-terminated...| (more-->)
|
||||
+===================================+
|
||||
|
||||
(if FLG.FHCRC set)
|
||||
|
||||
+---+---+
|
||||
| CRC16 |
|
||||
+---+---+
|
||||
|
||||
+=======================+
|
||||
|...compressed blocks...| (more-->)
|
||||
+=======================+
|
||||
|
||||
0 1 2 3 4 5 6 7
|
||||
+---+---+---+---+---+---+---+---+
|
||||
| CRC32 | ISIZE |
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 5]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
2.3.1. Member header and trailer
|
||||
|
||||
ID1 (IDentification 1)
|
||||
ID2 (IDentification 2)
|
||||
These have the fixed values ID1 = 31 (0x1f, \037), ID2 = 139
|
||||
(0x8b, \213), to identify the file as being in gzip format.
|
||||
|
||||
CM (Compression Method)
|
||||
This identifies the compression method used in the file. CM
|
||||
= 0-7 are reserved. CM = 8 denotes the "deflate"
|
||||
compression method, which is the one customarily used by
|
||||
gzip and which is documented elsewhere.
|
||||
|
||||
FLG (FLaGs)
|
||||
This flag byte is divided into individual bits as follows:
|
||||
|
||||
bit 0 FTEXT
|
||||
bit 1 FHCRC
|
||||
bit 2 FEXTRA
|
||||
bit 3 FNAME
|
||||
bit 4 FCOMMENT
|
||||
bit 5 reserved
|
||||
bit 6 reserved
|
||||
bit 7 reserved
|
||||
|
||||
If FTEXT is set, the file is probably ASCII text. This is
|
||||
an optional indication, which the compressor may set by
|
||||
checking a small amount of the input data to see whether any
|
||||
non-ASCII characters are present. In case of doubt, FTEXT
|
||||
is cleared, indicating binary data. For systems which have
|
||||
different file formats for ascii text and binary data, the
|
||||
decompressor can use FTEXT to choose the appropriate format.
|
||||
We deliberately do not specify the algorithm used to set
|
||||
this bit, since a compressor always has the option of
|
||||
leaving it cleared and a decompressor always has the option
|
||||
of ignoring it and letting some other program handle issues
|
||||
of data conversion.
|
||||
|
||||
If FHCRC is set, a CRC16 for the gzip header is present,
|
||||
immediately before the compressed data. The CRC16 consists
|
||||
of the two least significant bytes of the CRC32 for all
|
||||
bytes of the gzip header up to and not including the CRC16.
|
||||
[The FHCRC bit was never set by versions of gzip up to
|
||||
1.2.4, even though it was documented with a different
|
||||
meaning in gzip 1.2.4.]
|
||||
|
||||
If FEXTRA is set, optional extra fields are present, as
|
||||
described in a following section.
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 6]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
If FNAME is set, an original file name is present,
|
||||
terminated by a zero byte. The name must consist of ISO
|
||||
8859-1 (LATIN-1) characters; on operating systems using
|
||||
EBCDIC or any other character set for file names, the name
|
||||
must be translated to the ISO LATIN-1 character set. This
|
||||
is the original name of the file being compressed, with any
|
||||
directory components removed, and, if the file being
|
||||
compressed is on a file system with case insensitive names,
|
||||
forced to lower case. There is no original file name if the
|
||||
data was compressed from a source other than a named file;
|
||||
for example, if the source was stdin on a Unix system, there
|
||||
is no file name.
|
||||
|
||||
If FCOMMENT is set, a zero-terminated file comment is
|
||||
present. This comment is not interpreted; it is only
|
||||
intended for human consumption. The comment must consist of
|
||||
ISO 8859-1 (LATIN-1) characters. Line breaks should be
|
||||
denoted by a single line feed character (10 decimal).
|
||||
|
||||
Reserved FLG bits must be zero.
|
||||
|
||||
MTIME (Modification TIME)
|
||||
This gives the most recent modification time of the original
|
||||
file being compressed. The time is in Unix format, i.e.,
|
||||
seconds since 00:00:00 GMT, Jan. 1, 1970. (Note that this
|
||||
may cause problems for MS-DOS and other systems that use
|
||||
local rather than Universal time.) If the compressed data
|
||||
did not come from a file, MTIME is set to the time at which
|
||||
compression started. MTIME = 0 means no time stamp is
|
||||
available.
|
||||
|
||||
XFL (eXtra FLags)
|
||||
These flags are available for use by specific compression
|
||||
methods. The "deflate" method (CM = 8) sets these flags as
|
||||
follows:
|
||||
|
||||
XFL = 2 - compressor used maximum compression,
|
||||
slowest algorithm
|
||||
XFL = 4 - compressor used fastest algorithm
|
||||
|
||||
OS (Operating System)
|
||||
This identifies the type of file system on which compression
|
||||
took place. This may be useful in determining end-of-line
|
||||
convention for text files. The currently defined values are
|
||||
as follows:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 7]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
0 - FAT filesystem (MS-DOS, OS/2, NT/Win32)
|
||||
1 - Amiga
|
||||
2 - VMS (or OpenVMS)
|
||||
3 - Unix
|
||||
4 - VM/CMS
|
||||
5 - Atari TOS
|
||||
6 - HPFS filesystem (OS/2, NT)
|
||||
7 - Macintosh
|
||||
8 - Z-System
|
||||
9 - CP/M
|
||||
10 - TOPS-20
|
||||
11 - NTFS filesystem (NT)
|
||||
12 - QDOS
|
||||
13 - Acorn RISCOS
|
||||
255 - unknown
|
||||
|
||||
XLEN (eXtra LENgth)
|
||||
If FLG.FEXTRA is set, this gives the length of the optional
|
||||
extra field. See below for details.
|
||||
|
||||
CRC32 (CRC-32)
|
||||
This contains a Cyclic Redundancy Check value of the
|
||||
uncompressed data computed according to CRC-32 algorithm
|
||||
used in the ISO 3309 standard and in section 8.1.1.6.2 of
|
||||
ITU-T recommendation V.42. (See http://www.iso.ch for
|
||||
ordering ISO documents. See gopher://info.itu.ch for an
|
||||
online version of ITU-T V.42.)
|
||||
|
||||
ISIZE (Input SIZE)
|
||||
This contains the size of the original (uncompressed) input
|
||||
data modulo 2^32.
|
||||
|
||||
2.3.1.1. Extra field
|
||||
|
||||
If the FLG.FEXTRA bit is set, an "extra field" is present in
|
||||
the header, with total length XLEN bytes. It consists of a
|
||||
series of subfields, each of the form:
|
||||
|
||||
+---+---+---+---+==================================+
|
||||
|SI1|SI2| LEN |... LEN bytes of subfield data ...|
|
||||
+---+---+---+---+==================================+
|
||||
|
||||
SI1 and SI2 provide a subfield ID, typically two ASCII letters
|
||||
with some mnemonic value. Jean-Loup Gailly
|
||||
<gzip@prep.ai.mit.edu> is maintaining a registry of subfield
|
||||
IDs; please send him any subfield ID you wish to use. Subfield
|
||||
IDs with SI2 = 0 are reserved for future use. The following
|
||||
IDs are currently defined:
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 8]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
SI1 SI2 Data
|
||||
---------- ---------- ----
|
||||
0x41 ('A') 0x70 ('P') Apollo file type information
|
||||
|
||||
LEN gives the length of the subfield data, excluding the 4
|
||||
initial bytes.
|
||||
|
||||
2.3.1.2. Compliance
|
||||
|
||||
A compliant compressor must produce files with correct ID1,
|
||||
ID2, CM, CRC32, and ISIZE, but may set all the other fields in
|
||||
the fixed-length part of the header to default values (255 for
|
||||
OS, 0 for all others). The compressor must set all reserved
|
||||
bits to zero.
|
||||
|
||||
A compliant decompressor must check ID1, ID2, and CM, and
|
||||
provide an error indication if any of these have incorrect
|
||||
values. It must examine FEXTRA/XLEN, FNAME, FCOMMENT and FHCRC
|
||||
at least so it can skip over the optional fields if they are
|
||||
present. It need not examine any other part of the header or
|
||||
trailer; in particular, a decompressor may ignore FTEXT and OS
|
||||
and always produce binary output, and still be compliant. A
|
||||
compliant decompressor must give an error indication if any
|
||||
reserved bit is non-zero, since such a bit could indicate the
|
||||
presence of a new field that would cause subsequent data to be
|
||||
interpreted incorrectly.
|
||||
|
||||
3. References
|
||||
|
||||
[1] "Information Processing - 8-bit single-byte coded graphic
|
||||
character sets - Part 1: Latin alphabet No.1" (ISO 8859-1:1987).
|
||||
The ISO 8859-1 (Latin-1) character set is a superset of 7-bit
|
||||
ASCII. Files defining this character set are available as
|
||||
iso_8859-1.* in ftp://ftp.uu.net/graphics/png/documents/
|
||||
|
||||
[2] ISO 3309
|
||||
|
||||
[3] ITU-T recommendation V.42
|
||||
|
||||
[4] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification",
|
||||
available in ftp://ftp.uu.net/pub/archiving/zip/doc/
|
||||
|
||||
[5] Gailly, J.-L., GZIP documentation, available as gzip-*.tar in
|
||||
ftp://prep.ai.mit.edu/pub/gnu/
|
||||
|
||||
[6] Sarwate, D.V., "Computation of Cyclic Redundancy Checks via Table
|
||||
Look-Up", Communications of the ACM, 31(8), pp.1008-1013.
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 9]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
[7] Schwaderer, W.D., "CRC Calculation", April 85 PC Tech Journal,
|
||||
pp.118-133.
|
||||
|
||||
[8] ftp://ftp.adelaide.edu.au/pub/rocksoft/papers/crc_v3.txt,
|
||||
describing the CRC concept.
|
||||
|
||||
4. Security Considerations
|
||||
|
||||
Any data compression method involves the reduction of redundancy in
|
||||
the data. Consequently, any corruption of the data is likely to have
|
||||
severe effects and be difficult to correct. Uncompressed text, on
|
||||
the other hand, will probably still be readable despite the presence
|
||||
of some corrupted bytes.
|
||||
|
||||
It is recommended that systems using this data format provide some
|
||||
means of validating the integrity of the compressed data, such as by
|
||||
setting and checking the CRC-32 check value.
|
||||
|
||||
5. Acknowledgements
|
||||
|
||||
Trademarks cited in this document are the property of their
|
||||
respective owners.
|
||||
|
||||
Jean-Loup Gailly designed the gzip format and wrote, with Mark Adler,
|
||||
the related software described in this specification. Glenn
|
||||
Randers-Pehrson converted this document to RFC and HTML format.
|
||||
|
||||
6. Author's Address
|
||||
|
||||
L. Peter Deutsch
|
||||
Aladdin Enterprises
|
||||
203 Santa Margarita Ave.
|
||||
Menlo Park, CA 94025
|
||||
|
||||
Phone: (415) 322-0103 (AM only)
|
||||
FAX: (415) 322-1734
|
||||
EMail: <ghost@aladdin.com>
|
||||
|
||||
Questions about the technical content of this specification can be
|
||||
sent by email to:
|
||||
|
||||
Jean-Loup Gailly <gzip@prep.ai.mit.edu> and
|
||||
Mark Adler <madler@alumni.caltech.edu>
|
||||
|
||||
Editorial comments on this specification can be sent by email to:
|
||||
|
||||
L. Peter Deutsch <ghost@aladdin.com> and
|
||||
Glenn Randers-Pehrson <randeg@alumni.rpi.edu>
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 10]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
7. Appendix: Jean-Loup Gailly's gzip utility
|
||||
|
||||
The most widely used implementation of gzip compression, and the
|
||||
original documentation on which this specification is based, were
|
||||
created by Jean-Loup Gailly <gzip@prep.ai.mit.edu>. Since this
|
||||
implementation is a de facto standard, we mention some more of its
|
||||
features here. Again, the material in this section is not part of
|
||||
the specification per se, and implementations need not follow it to
|
||||
be compliant.
|
||||
|
||||
When compressing or decompressing a file, gzip preserves the
|
||||
protection, ownership, and modification time attributes on the local
|
||||
file system, since there is no provision for representing protection
|
||||
attributes in the gzip file format itself. Since the file format
|
||||
includes a modification time, the gzip decompressor provides a
|
||||
command line switch that assigns the modification time from the file,
|
||||
rather than the local modification time of the compressed input, to
|
||||
the decompressed output.
|
||||
|
||||
8. Appendix: Sample CRC Code
|
||||
|
||||
The following sample code represents a practical implementation of
|
||||
the CRC (Cyclic Redundancy Check). (See also ISO 3309 and ITU-T V.42
|
||||
for a formal specification.)
|
||||
|
||||
The sample code is in the ANSI C programming language. Non C users
|
||||
may find it easier to read with these hints:
|
||||
|
||||
& Bitwise AND operator.
|
||||
^ Bitwise exclusive-OR operator.
|
||||
>> Bitwise right shift operator. When applied to an
|
||||
unsigned quantity, as here, right shift inserts zero
|
||||
bit(s) at the left.
|
||||
! Logical NOT operator.
|
||||
++ "n++" increments the variable n.
|
||||
0xNNN 0x introduces a hexadecimal (base 16) constant.
|
||||
Suffix L indicates a long value (at least 32 bits).
|
||||
|
||||
/* Table of CRCs of all 8-bit messages. */
|
||||
unsigned long crc_table[256];
|
||||
|
||||
/* Flag: has the table been computed? Initially false. */
|
||||
int crc_table_computed = 0;
|
||||
|
||||
/* Make the table for a fast CRC. */
|
||||
void make_crc_table(void)
|
||||
{
|
||||
unsigned long c;
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 11]
|
||||
|
||||
RFC 1952 GZIP File Format Specification May 1996
|
||||
|
||||
|
||||
int n, k;
|
||||
for (n = 0; n < 256; n++) {
|
||||
c = (unsigned long) n;
|
||||
for (k = 0; k < 8; k++) {
|
||||
if (c & 1) {
|
||||
c = 0xedb88320L ^ (c >> 1);
|
||||
} else {
|
||||
c = c >> 1;
|
||||
}
|
||||
}
|
||||
crc_table[n] = c;
|
||||
}
|
||||
crc_table_computed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Update a running crc with the bytes buf[0..len-1] and return
|
||||
the updated crc. The crc should be initialized to zero. Pre- and
|
||||
post-conditioning (one's complement) is performed within this
|
||||
function so it shouldn't be done by the caller. Usage example:
|
||||
|
||||
unsigned long crc = 0L;
|
||||
|
||||
while (read_buffer(buffer, length) != EOF) {
|
||||
crc = update_crc(crc, buffer, length);
|
||||
}
|
||||
if (crc != original_crc) error();
|
||||
*/
|
||||
unsigned long update_crc(unsigned long crc,
|
||||
unsigned char *buf, int len)
|
||||
{
|
||||
unsigned long c = crc ^ 0xffffffffL;
|
||||
int n;
|
||||
|
||||
if (!crc_table_computed)
|
||||
make_crc_table();
|
||||
for (n = 0; n < len; n++) {
|
||||
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
return c ^ 0xffffffffL;
|
||||
}
|
||||
|
||||
/* Return the CRC of the bytes buf[0..len-1]. */
|
||||
unsigned long crc(unsigned char *buf, int len)
|
||||
{
|
||||
return update_crc(0L, buf, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Deutsch Informational [Page 12]
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
A Fast Method for Identifying Plain Text Files
|
||||
==============================================
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Given a file coming from an unknown source, it is sometimes desirable
|
||||
to find out whether the format of that file is plain text. Although
|
||||
this may appear like a simple task, a fully accurate detection of the
|
||||
file type requires heavy-duty semantic analysis on the file contents.
|
||||
It is, however, possible to obtain satisfactory results by employing
|
||||
various heuristics.
|
||||
|
||||
Previous versions of PKZip and other zip-compatible compression tools
|
||||
were using a crude detection scheme: if more than 80% (4/5) of the bytes
|
||||
found in a certain buffer are within the range [7..127], the file is
|
||||
labeled as plain text, otherwise it is labeled as binary. A prominent
|
||||
limitation of this scheme is the restriction to Latin-based alphabets.
|
||||
Other alphabets, like Greek, Cyrillic or Asian, make extensive use of
|
||||
the bytes within the range [128..255], and texts using these alphabets
|
||||
are most often misidentified by this scheme; in other words, the rate
|
||||
of false negatives is sometimes too high, which means that the recall
|
||||
is low. Another weakness of this scheme is a reduced precision, due to
|
||||
the false positives that may occur when binary files containing large
|
||||
amounts of textual characters are misidentified as plain text.
|
||||
|
||||
In this article we propose a new, simple detection scheme that features
|
||||
a much increased precision and a near-100% recall. This scheme is
|
||||
designed to work on ASCII, Unicode and other ASCII-derived alphabets,
|
||||
and it handles single-byte encodings (ISO-8859, MacRoman, KOI8, etc.)
|
||||
and variable-sized encodings (ISO-2022, UTF-8, etc.). Wider encodings
|
||||
(UCS-2/UTF-16 and UCS-4/UTF-32) are not handled, however.
|
||||
|
||||
|
||||
The Algorithm
|
||||
-------------
|
||||
|
||||
The algorithm works by dividing the set of bytecodes [0..255] into three
|
||||
categories:
|
||||
- The white list of textual bytecodes:
|
||||
9 (TAB), 10 (LF), 13 (CR), 32 (SPACE) to 255.
|
||||
- The gray list of tolerated bytecodes:
|
||||
7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC).
|
||||
- The black list of undesired, non-textual bytecodes:
|
||||
0 (NUL) to 6, 14 to 31.
|
||||
|
||||
If a file contains at least one byte that belongs to the white list and
|
||||
no byte that belongs to the black list, then the file is categorized as
|
||||
plain text; otherwise, it is categorized as binary. (The boundary case,
|
||||
when the file is empty, automatically falls into the latter category.)
|
||||
|
||||
|
||||
Rationale
|
||||
---------
|
||||
|
||||
The idea behind this algorithm relies on two observations.
|
||||
|
||||
The first observation is that, although the full range of 7-bit codes
|
||||
[0..127] is properly specified by the ASCII standard, most control
|
||||
characters in the range [0..31] are not used in practice. The only
|
||||
widely-used, almost universally-portable control codes are 9 (TAB),
|
||||
10 (LF) and 13 (CR). There are a few more control codes that are
|
||||
recognized on a reduced range of platforms and text viewers/editors:
|
||||
7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB) and 27 (ESC); but these
|
||||
codes are rarely (if ever) used alone, without being accompanied by
|
||||
some printable text. Even the newer, portable text formats such as
|
||||
XML avoid using control characters outside the list mentioned here.
|
||||
|
||||
The second observation is that most of the binary files tend to contain
|
||||
control characters, especially 0 (NUL). Even though the older text
|
||||
detection schemes observe the presence of non-ASCII codes from the range
|
||||
[128..255], the precision rarely has to suffer if this upper range is
|
||||
labeled as textual, because the files that are genuinely binary tend to
|
||||
contain both control characters and codes from the upper range. On the
|
||||
other hand, the upper range needs to be labeled as textual, because it
|
||||
is used by virtually all ASCII extensions. In particular, this range is
|
||||
used for encoding non-Latin scripts.
|
||||
|
||||
Since there is no counting involved, other than simply observing the
|
||||
presence or the absence of some byte values, the algorithm produces
|
||||
consistent results, regardless what alphabet encoding is being used.
|
||||
(If counting were involved, it could be possible to obtain different
|
||||
results on a text encoded, say, using ISO-8859-16 versus UTF-8.)
|
||||
|
||||
There is an extra category of plain text files that are "polluted" with
|
||||
one or more black-listed codes, either by mistake or by peculiar design
|
||||
considerations. In such cases, a scheme that tolerates a small fraction
|
||||
of black-listed codes would provide an increased recall (i.e. more true
|
||||
positives). This, however, incurs a reduced precision overall, since
|
||||
false positives are more likely to appear in binary files that contain
|
||||
large chunks of textual data. Furthermore, "polluted" plain text should
|
||||
be regarded as binary by general-purpose text detection schemes, because
|
||||
general-purpose text processing algorithms might not be applicable.
|
||||
Under this premise, it is safe to say that our detection method provides
|
||||
a near-100% recall.
|
||||
|
||||
Experiments have been run on many files coming from various platforms
|
||||
and applications. We tried plain text files, system logs, source code,
|
||||
formatted office documents, compiled object code, etc. The results
|
||||
confirm the optimistic assumptions about the capabilities of this
|
||||
algorithm.
|
||||
|
||||
|
||||
--
|
||||
Cosmin Truta
|
||||
Last updated: 2006-May-28
|
||||
Regular → Executable
+1
-28
@@ -8,7 +8,7 @@
|
||||
.so man.macros
|
||||
.BS
|
||||
.SH NAME
|
||||
Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj, Tcl_RegisterCommandTypeName, Tcl_GetCommandTypeName \- implement new commands in C
|
||||
Tcl_CreateObjCommand, Tcl_DeleteCommand, Tcl_DeleteCommandFromToken, Tcl_GetCommandInfo, Tcl_GetCommandInfoFromToken, Tcl_SetCommandInfo, Tcl_SetCommandInfoFromToken, Tcl_GetCommandName, Tcl_GetCommandFullName, Tcl_GetCommandFromObj \- implement new commands in C
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tcl.h>\fR
|
||||
@@ -42,14 +42,6 @@ void
|
||||
.sp
|
||||
Tcl_Command
|
||||
\fBTcl_GetCommandFromObj\fR(\fIinterp, objPtr\fR)
|
||||
.sp
|
||||
.VS "info cmdtype feature"
|
||||
void
|
||||
\fBTcl_RegisterCommandTypeName\fR(\fIproc, typeName\fR)
|
||||
.sp
|
||||
const char *
|
||||
\fBTcl_GetCommandTypeName\fR(\fItoken\fR)
|
||||
.VE "info cmdtype feature"
|
||||
.SH ARGUMENTS
|
||||
.AS Tcl_CmdDeleteProc *deleteProc in/out
|
||||
.AP Tcl_Interp *interp in
|
||||
@@ -73,9 +65,6 @@ Pointer to structure containing various information about a
|
||||
Tcl command.
|
||||
.AP Tcl_Obj *objPtr in
|
||||
Value containing the name of a Tcl command.
|
||||
.AP "const char" *typeName in
|
||||
Indicates the name of the type of command implementation associated
|
||||
with a particular \fIproc\fR, or NULL to break the association.
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
@@ -307,22 +296,6 @@ is appended to the value specified by \fIobjPtr\fR.
|
||||
specified by the name in a \fBTcl_Obj\fR.
|
||||
The command name is resolved relative to the current namespace.
|
||||
Returns NULL if the command is not found.
|
||||
.PP
|
||||
.VS "info cmdtype feature"
|
||||
\fBTcl_RegisterCommandTypeName\fR is used to associate a name (the
|
||||
\fItypeName\fR argument) with a particular implementation function so that it
|
||||
can then be looked up with \fBTcl_GetCommandTypeName\fR, which in turn is
|
||||
called with a command token that information is wanted for and which returns
|
||||
the name of the type that was registered for the implementation function used
|
||||
for that command. (The lookup functionality is surfaced virtually directly in Tcl via
|
||||
\fBinfo cmdtype\fR.) If there is no function registered for a particular
|
||||
function, the result will be the string literal
|
||||
.QW \fBnative\fR .
|
||||
The registration of a name can be undone by registering a mapping to NULL
|
||||
instead. The result from \fBTcl_GetCommandTypeName\fR will be exactly that
|
||||
string which was registered, and not a copy; use of a compile-time constant
|
||||
string is \fIstrongly recommended\fR.
|
||||
.VE "info cmdtype feature"
|
||||
.SH "SEE ALSO"
|
||||
Tcl_CreateCommand(3), Tcl_ResetResult(3), Tcl_SetObjResult(3)
|
||||
.SH KEYWORDS
|
||||
|
||||
@@ -260,6 +260,10 @@ Windows-only convenience
|
||||
functions for converting between UTF-8 and Windows strings
|
||||
based on the TCHAR type which is by convention
|
||||
a Unicode character on Windows NT.
|
||||
These functions are essentially wrappers around
|
||||
\fBTcl_UtfToExternalDString\fR and
|
||||
\fBTcl_ExternalToUtfDString\fR that convert to and from the
|
||||
Unicode encoding.
|
||||
.PP
|
||||
\fBTcl_GetEncodingName\fR is roughly the inverse of \fBTcl_GetEncoding\fR.
|
||||
Given an \fIencoding\fR, the return value is the \fIname\fR argument that
|
||||
|
||||
+5
-5
@@ -176,10 +176,10 @@ it is faster to execute the script directly.
|
||||
.TP 23
|
||||
\fBTCL_EVAL_GLOBAL\fR
|
||||
.
|
||||
If this flag is set, the script is evaluated in the global namespace instead of
|
||||
the current namespace and its variable context consists of global variables
|
||||
only (it ignores any Tcl procedures that are active).
|
||||
.\" TODO: document TCL_EVAL_INVOKE and TCL_EVAL_NOERR.
|
||||
If this flag is set, the script is processed at global level. This
|
||||
means that it is evaluated in the global namespace and its variable
|
||||
context consists of global variables only (it ignores any Tcl
|
||||
procedures that are active).
|
||||
|
||||
.SH "MISCELLANEOUS DETAILS"
|
||||
.PP
|
||||
@@ -205,7 +205,7 @@ and sets \fIinterp\fR's result to an error message indicating that
|
||||
the \fBreturn\fR, \fBbreak\fR, or \fBcontinue\fR command was
|
||||
invoked in an inappropriate place.
|
||||
This means that top-level applications should never see a return code
|
||||
from \fBTcl_EvalObjEx\fR other than \fBTCL_OK\fR or \fBTCL_ERROR\fR.
|
||||
from \fBTcl_EvalObjEx\fR other then \fBTCL_OK\fR or \fBTCL_ERROR\fR.
|
||||
|
||||
.SH KEYWORDS
|
||||
execute, file, global, result, script, value
|
||||
|
||||
@@ -134,9 +134,6 @@ finalization of Tcl's subsystems via \fBTcl_Finalize\fR at an
|
||||
appropriate time. The argument passed to \fIproc\fR when it is
|
||||
invoked will be the exit status code (as passed to \fBTcl_Exit\fR)
|
||||
cast to a ClientData value.
|
||||
.PP
|
||||
\fBTcl_SetExitProc\fR can not be used in stub-enabled extensions. Its symbol
|
||||
entry in the stub table is deprecated and it will be removed in Tcl 9.0.
|
||||
.SH "SEE ALSO"
|
||||
exit(n)
|
||||
.SH KEYWORDS
|
||||
|
||||
+1
-3
@@ -58,8 +58,6 @@ internal full path name of the executable file as computed by
|
||||
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. Its symbol
|
||||
entry in the stub table is deprecated and it will be removed in Tcl 9.0.
|
||||
|
||||
.SH KEYWORDS
|
||||
binary, executable file
|
||||
|
||||
+2
-5
@@ -57,9 +57,6 @@ after the optional white space and sign are
|
||||
.QW \fB0x\fR
|
||||
then \fIsrc\fR is expected to be in hexadecimal form; otherwise,
|
||||
if the first such characters are
|
||||
.QW \fB0d\fR
|
||||
then \fIsrc\fR is expected to be in decimal form; otherwise,
|
||||
if the first such characters are
|
||||
.QW \fB0o\fR
|
||||
then \fIsrc\fR is expected to be in octal form; otherwise,
|
||||
if the first such characters are
|
||||
@@ -68,8 +65,8 @@ then \fIsrc\fR is expected to be in binary form; otherwise,
|
||||
if the first such character is
|
||||
.QW \fB0\fR
|
||||
then \fIsrc\fR
|
||||
is expected to be in octal form; otherwise, \fIsrc\fR
|
||||
is expected to be in decimal form.
|
||||
is expected to be in octal 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
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ are provided by the C language standard. The \fBTcl_WideInt\fR type is a
|
||||
typedef defined to be whatever signed integral type covers at least the
|
||||
64-bit integer range (-9223372036854775808 to 9223372036854775807). Depending
|
||||
on the platform and the C compiler, the actual type might be
|
||||
\fBlong long int\fR, \fB__int64\fR, or something else.
|
||||
\fBlong int\fR, \fBlong long int\fR, \fBint64\fR, or something else.
|
||||
The \fBmp_int\fR type is a multiple-precision integer type defined
|
||||
by the LibTomMath multiple-precision integer library.
|
||||
.PP
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ the command. The \fIfreeProc\fR field will be initialized to zero,
|
||||
and \fIinterp->result\fR will point to an empty string. Commands that
|
||||
do not return any value can simply leave the fields alone.
|
||||
Furthermore, the empty string pointed to by \fIresult\fR is actually
|
||||
part of an array of approximately 200 characters.
|
||||
part of an array of \fBTCL_RESULT_SIZE\fR characters (approximately 200).
|
||||
If a command wishes to return a short string, it can simply copy
|
||||
it to the area pointed to by \fIinterp->result\fR. Or, it can use
|
||||
the sprintf procedure to generate a short result string at the location
|
||||
|
||||
+13
-31
@@ -9,18 +9,18 @@
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsPrivate, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextInvokeNext, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
|
||||
Tcl_ClassSetConstructor, Tcl_ClassSetDestructor, Tcl_MethodDeclarerClass, Tcl_MethodDeclarerObject, Tcl_MethodIsPublic, Tcl_MethodIsType, Tcl_MethodName, Tcl_NewInstanceMethod, Tcl_NewMethod, Tcl_ObjectContextInvokeNext, Tcl_ObjectContextIsFiltering, Tcl_ObjectContextMethod, Tcl_ObjectContextObject, Tcl_ObjectContextSkippedArgs \- manipulate methods and method-call contexts
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tclOO.h>\fR
|
||||
.sp
|
||||
Tcl_Method
|
||||
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, flags, methodTypePtr,
|
||||
clientData\fR)
|
||||
\fBTcl_NewMethod\fR(\fIinterp, class, nameObj, isPublic,
|
||||
methodTypePtr, clientData\fR)
|
||||
.sp
|
||||
Tcl_Method
|
||||
\fBTcl_NewInstanceMethod\fR(\fIinterp, object, nameObj, flags, methodTypePtr,
|
||||
clientData\fR)
|
||||
\fBTcl_NewInstanceMethod\fR(\fIinterp, object, nameObj, isPublic,
|
||||
methodTypePtr, clientData\fR)
|
||||
.sp
|
||||
\fBTcl_ClassSetConstructor\fR(\fIinterp, class, method\fR)
|
||||
.sp
|
||||
@@ -35,13 +35,8 @@ Tcl_Object
|
||||
Tcl_Obj *
|
||||
\fBTcl_MethodName\fR(\fImethod\fR)
|
||||
.sp
|
||||
.VS TIP500
|
||||
int
|
||||
\fBTcl_MethodIsPublic\fR(\fImethod\fR)
|
||||
.VE TIP500
|
||||
.sp
|
||||
int
|
||||
\fBTcl_MethodIsPrivate\fR(\fImethod\fR)
|
||||
.sp
|
||||
int
|
||||
\fBTcl_MethodIsType\fR(\fImethod, methodTypePtr, clientDataPtr\fR)
|
||||
@@ -71,15 +66,10 @@ The class to create the method in.
|
||||
.AP Tcl_Obj *nameObj in
|
||||
The name of the method to create. Should not be NULL unless creating
|
||||
constructors or destructors.
|
||||
.AP int flags in
|
||||
A flag saying (currently) what the visibility of the method is. The supported
|
||||
public values of this flag are \fBTCL_OO_METHOD_PUBLIC\fR (which is fixed at 1
|
||||
for backward compatibility) for an exported method,
|
||||
\fBTCL_OO_METHOD_UNEXPORTED\fR (which is fixed at 0 for backward
|
||||
compatibility) for a non-exported method,
|
||||
.VS TIP500
|
||||
and \fBTCL_OO_METHOD_PRIVATE\fR for a private method.
|
||||
.VE TIP500
|
||||
.AP int isPublic in
|
||||
A flag saying what the visibility of the method is. The only supported public
|
||||
values of this flag are 0 for a non-exported method, and 1 for an exported
|
||||
method.
|
||||
.AP Tcl_MethodType *methodTypePtr in
|
||||
A description of the type of the method to create, or the type of method to
|
||||
compare against.
|
||||
@@ -115,12 +105,8 @@ Given a method, the entity that declared it can be found using
|
||||
attached to (or NULL if the method is not attached to any class) and
|
||||
\fBTcl_MethodDeclarerObject\fR which returns the object that the method is
|
||||
attached to (or NULL if the method is not attached to an object). The name of
|
||||
the method can be retrieved with \fBTcl_MethodName\fR, whether the method
|
||||
is exported is retrieved with \fBTcl_MethodIsPublic\fR,
|
||||
.VS TIP500
|
||||
and whether the method is private is retrieved with \fBTcl_MethodIsPrivate\fR.
|
||||
.VE TIP500
|
||||
The type of the method
|
||||
the method can be retrieved with \fBTcl_MethodName\fR and whether the method
|
||||
is exported is retrieved with \fBTcl_MethodIsPublic\fR. The type of the method
|
||||
can also be introspected upon to a limited degree; the function
|
||||
\fBTcl_MethodIsType\fR returns whether a method is of a particular type,
|
||||
assigning the per-method \fIclientData\fR to the variable pointed to by
|
||||
@@ -131,12 +117,8 @@ Methods are created by \fBTcl_NewMethod\fR and \fBTcl_NewInstanceMethod\fR,
|
||||
which
|
||||
create a method attached to a class or an object respectively. In both cases,
|
||||
the \fInameObj\fR argument gives the name of the method to create, the
|
||||
\fIflags\fR argument states whether the method should be exported
|
||||
initially
|
||||
.VS TIP500
|
||||
or be marked as a private method,
|
||||
.VE TIP500
|
||||
the \fImethodTypePtr\fR argument describes the implementation of
|
||||
\fIisPublic\fR argument states whether the method should be exported
|
||||
initially, the \fImethodTypePtr\fR argument describes the implementation of
|
||||
the method (see the \fBMETHOD TYPES\fR section below) and the \fIclientData\fR
|
||||
argument gives some implementation-specific data that is passed on to the
|
||||
implementation of the method when it is called.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2008 by Kevin B. Kenny.
|
||||
.\" Copyright (c) 2018 by Nathan Coulter.
|
||||
.\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -39,39 +38,43 @@ void
|
||||
.SH ARGUMENTS
|
||||
.AS Tcl_CmdDeleteProc *interp in
|
||||
.AP Tcl_Interp *interp in
|
||||
The relevant Interpreter.
|
||||
Interpreter in which to create or evaluate a command.
|
||||
.AP char *cmdName in
|
||||
Name of the command to create.
|
||||
Name of a new command to create.
|
||||
.AP Tcl_ObjCmdProc *proc in
|
||||
Called in order to evaluate a command. Is often just a small wrapper that uses
|
||||
\fBTcl_NRCallObjProc\fR to call \fInreProc\fR using a new trampoline. Behaves
|
||||
in the same way as the \fIproc\fR argument to \fBTcl_CreateObjCommand\fR(3)
|
||||
(\fIq.v.\fR).
|
||||
Implementation of a command that will be called whenever \fIcmdName\fR
|
||||
is invoked as a command in the unoptimized way.
|
||||
.AP Tcl_ObjCmdProc *nreProc in
|
||||
Called instead of \fIproc\fR when a trampoline is already in use.
|
||||
Implementation of a command that will be called whenever \fIcmdName\fR
|
||||
is invoked and requested to conserve the C stack.
|
||||
.AP ClientData clientData in
|
||||
Arbitrary one-word value passed to \fIproc\fR, \fInreProc\fR, \fIdeleteProc\fR
|
||||
and \fIobjProc\fR.
|
||||
Arbitrary one-word value that will be passed to \fIproc\fR, \fInreProc\fR,
|
||||
\fIdeleteProc\fR and \fIobjProc\fR.
|
||||
.AP Tcl_CmdDeleteProc *deleteProc in/out
|
||||
Called before \fIcmdName\fR is deleted from the interpreter, allowing for
|
||||
command-specific cleanup. May be NULL.
|
||||
Procedure to call before \fIcmdName\fR is deleted from the interpreter.
|
||||
This procedure allows for command-specific cleanup. If \fIdeleteProc\fR
|
||||
is \fBNULL\fR, then no procedure is called before the command is deleted.
|
||||
.AP int objc in
|
||||
Number of items in \fIobjv\fR.
|
||||
Count of parameters provided to the implementation of a command.
|
||||
.AP Tcl_Obj **objv in
|
||||
Words in the command.
|
||||
Pointer to an array of Tcl values. Each value holds the value of a
|
||||
single word in the command to execute.
|
||||
.AP Tcl_Obj *objPtr in
|
||||
A script or expression to evaluate.
|
||||
Pointer to a Tcl_Obj whose value is a script or expression to execute.
|
||||
.AP int flags in
|
||||
As described for \fITcl_EvalObjv\fR.
|
||||
.PP
|
||||
ORed combination of flag bits that specify additional options.
|
||||
\fBTCL_EVAL_GLOBAL\fR is the only flag that is currently supported.
|
||||
.\" TODO: This is a lie. But kbk didn't grasp TCL_EVAL_INVOKE and
|
||||
.\" TCL_EVAL_NOERR well enough to document them.
|
||||
.AP Tcl_Command cmd in
|
||||
Token to use instead of one derived from the first word of \fIobjv\fR in order
|
||||
to evaluate a command.
|
||||
Token for a command that is to be used instead of the currently
|
||||
executing command.
|
||||
.AP Tcl_Obj *resultPtr out
|
||||
Pointer to an unshared Tcl_Obj where the result of the evaluation is stored if
|
||||
the return code is TCL_OK.
|
||||
Pointer to an unshared Tcl_Obj where the result of expression
|
||||
evaluation is written.
|
||||
.AP Tcl_NRPostProc *postProcPtr in
|
||||
A function to push.
|
||||
Pointer to a function that will be invoked when the command currently
|
||||
executing in the interpreter designated by \fIinterp\fR completes.
|
||||
.AP ClientData data0 in
|
||||
.AP ClientData data1 in
|
||||
.AP ClientData data2 in
|
||||
@@ -81,51 +84,98 @@ to the function designated by \fIpostProcPtr\fR when it is invoked.
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
These functions provide an interface to the function stack that an interpreter
|
||||
iterates through to evaluate commands. The routine behind a command is
|
||||
implemented by an initial function and any additional functions that the
|
||||
routine pushes onto the stack as it progresses. The interpreter itself pushes
|
||||
functions onto the stack to react to the end of a routine and to exercise other
|
||||
forms of control such as switching between in-progress stacks and the
|
||||
evaluation of other scripts at additional levels without adding frames to the C
|
||||
stack. To execute a routine, the initial function for the routine is called
|
||||
and then a small bit of code called a \fItrampoline\fR iteratively takes
|
||||
functions off the stack and calls them, using the value of the last call as the
|
||||
value of the routine.
|
||||
This series of C functions provides an interface whereby commands that
|
||||
are implemented in C can be evaluated, and invoke Tcl commands scripts
|
||||
and scripts, without consuming space on the C stack. The non-recursive
|
||||
evaluation is done by installing a \fItrampoline\fR, a small piece of
|
||||
code that invokes a command or script, and then executes a series of
|
||||
callbacks when the command or script returns.
|
||||
.PP
|
||||
\fBTcl_NRCallObjProc\fR calls \fInreProc\fR using a new trampoline.
|
||||
The \fBTcl_NRCreateCommand\fR function creates a Tcl command in the
|
||||
interpreter designated by \fIinterp\fR that is prepared to handle
|
||||
nonrecursive evaluation with a trampoline. The \fIcmdName\fR argument
|
||||
gives the name of the new command. If \fIcmdName\fR contains any
|
||||
namespace qualifiers, then the new command is added to the specified
|
||||
namespace; otherwise, it is added to the global namespace. \fIproc\fR
|
||||
gives the procedure that will be called when the interpreter wishes to
|
||||
evaluate the command in an unoptimized manner, and \fInreProc\fR is
|
||||
the procedure that will be called when the interpreter wishes to
|
||||
evaluate the command using a trampoline. \fIdeleteProc\fR is a
|
||||
function that will be called before the command is deleted from the
|
||||
interpreter. When any of the three functions is invoked, it is passed
|
||||
the \fIclientData\fR parameter.
|
||||
.PP
|
||||
\fBTcl_NRCreateCommand\fR, an alternative to \fBTcl_CreateObjCommand\fR,
|
||||
resolves \fIcmdName\fR, which may contain namespace qualifiers, relative to the
|
||||
current namespace, creates a command by that name, and returns a token for the
|
||||
command which may be used in subsequent calls to \fBTcl_GetCommandName\fR.
|
||||
Except for a few cases noted below any existing command by the same name is
|
||||
first deleted. If \fIinterp\fR is in the process of being deleted
|
||||
\fBTcl_NRCreateCommand\fR does not create any command, does not delete any
|
||||
command, and returns NULL.
|
||||
\fBTcl_NRCreateCommand\fR deletes any existing command
|
||||
\fIname\fR already associated with the interpreter
|
||||
(however see below for an exception where the existing command
|
||||
is not deleted).
|
||||
It returns a token that may be used to refer
|
||||
to the command in subsequent calls to \fBTcl_GetCommandName\fR.
|
||||
If \fBTcl_NRCreateCommand\fR is called for an interpreter that is in
|
||||
the process of being deleted, then it does not create a new command,
|
||||
does not delete any existing command of the same name, and returns NULL.
|
||||
.PP
|
||||
\fBTcl_NREvalObj\fR pushes a function that is like \fBTcl_EvalObjEx\fR but
|
||||
consumes no space on the C stack.
|
||||
The \fIproc\fR and \fInreProc\fR function are expected to conform to
|
||||
all the rules set forth for the \fIproc\fR argument to
|
||||
\fBTcl_CreateObjCommand\fR(3) (\fIq.v.\fR).
|
||||
.PP
|
||||
\fBTcl_NREvalObjv\fR pushes a function that is like \fBTcl_EvalObjv\fR but
|
||||
consumes no space on the C stack.
|
||||
When a command that is written to cope with evaluation via trampoline
|
||||
is invoked without a trampoline on the stack, it will usually respond
|
||||
to the invocation by creating a trampoline and calling the
|
||||
trampoline-enabled implementation of the same command. This call is done by
|
||||
means of \fBTcl_NRCallObjProc\fR. In the call to
|
||||
\fBTcl_NRCallObjProc\fR, the \fIinterp\fR, \fIclientData\fR,
|
||||
\fIobjc\fR and \fIobjv\fR parameters should be the same ones that were
|
||||
passed to \fIproc\fR. The \fInreProc\fR parameter should designate the
|
||||
trampoline-enabled implementation of the command.
|
||||
.PP
|
||||
\fBTcl_NRCmdSwap\fR is like \fBTcl_NREvalObjv\fR, but uses \fIcmd\fR, a token
|
||||
previously returned by \fBTcl_CreateObjCommand\fR or
|
||||
\fBTcl_GetCommandFromObj\fR, instead of resolving the first word of \fIobjv\fR.
|
||||
. The name of this command must be the same as \fIobjv[0]\fR.
|
||||
\fBTcl_NREvalObj\fR arranges for the script contained in \fIobjPtr\fR
|
||||
to be evaluated in the interpreter designated by \fIinterp\fR after
|
||||
the current command (which must be trampoline-enabled) returns. It is
|
||||
the method by which a command may invoke a script without consuming
|
||||
space on the C stack. Similarly, \fBTcl_NREvalObjv\fR arranges to
|
||||
invoke a single Tcl command whose words have already been separated
|
||||
and substituted. The \fIobjc\fR and \fIobjv\fR parameters give the
|
||||
words of the command to be evaluated when execution reaches the
|
||||
trampoline.
|
||||
.PP
|
||||
\fBTcl_NRExprObj\fR pushes a function that evaluates \fIobjPtr\fR as an
|
||||
expression in the same manner as \fBTcl_ExprObj\fR but without consuming space
|
||||
on the C stack.
|
||||
\fBTcl_NRCmdSwap\fR allows for trampoline evaluation of a command whose
|
||||
resolution is already known. The \fIcmd\fR parameter gives a
|
||||
\fBTcl_Command\fR token (returned from \fBTcl_CreateObjCommand\fR or
|
||||
\fBTcl_GetCommandFromObj\fR) identifying the command to be invoked in
|
||||
the trampoline; this command must match the word in \fIobjv[0]\fR.
|
||||
The remaining arguments are as for \fBTcl_NREvalObjv\fR.
|
||||
.PP
|
||||
All of the functions return \fBTCL_OK\fR if the evaluation of the script,
|
||||
command, or expression has been scheduled successfully. Otherwise (for example
|
||||
if the command name cannot be resolved), they return \fBTCL_ERROR\fR and store
|
||||
a message as the interpreter's result.
|
||||
\fBTcl_NREvalObj\fR, \fBTcl_NREvalObjv\fR and \fBTcl_NRCmdSwap\fR
|
||||
all accept a \fIflags\fR parameter, which is an OR-ed-together set of
|
||||
bits to control evaluation. At the present time, the only supported flag
|
||||
available to callers is \fBTCL_EVAL_GLOBAL\fR.
|
||||
.\" TODO: Again, this is a lie. Do we want to explain TCL_EVAL_INVOKE
|
||||
.\" and TCL_EVAL_NOERR?
|
||||
If the \fBTCL_EVAL_GLOBAL\fR flag is set, the script or command is
|
||||
evaluated in the global namespace. If it is not set, it is evaluated
|
||||
in the current namespace.
|
||||
.PP
|
||||
\fBTcl_NRAddCallback\fR pushes \fIpostProcPtr\fR. The signature for
|
||||
\fBTcl_NRPostProc\fR is:
|
||||
\fBTcl_NRExprObj\fR arranges for the expression contained in \fIobjPtr\fR
|
||||
to be evaluated in the interpreter designated by \fIinterp\fR after
|
||||
the current command (which must be trampoline-enabled) returns. It is
|
||||
the method by which a command may evaluate a Tcl expression without consuming
|
||||
space on the C stack. The argument \fIresultPtr\fR is a pointer to an
|
||||
unshared Tcl_Obj where the result of expression evaluation is to be written.
|
||||
If expression evaluation returns any code other than TCL_OK, the
|
||||
\fIresultPtr\fR value is left untouched.
|
||||
.PP
|
||||
All of the routines return \fBTCL_OK\fR if command or expression invocation
|
||||
has been scheduled successfully. If for any reason the scheduling cannot
|
||||
be completed (for example, if the interpreter is unable to find
|
||||
the requested command), they return \fBTCL_ERROR\fR with an
|
||||
appropriate message left in the interpreter's result.
|
||||
.PP
|
||||
\fBTcl_NRAddCallback\fR arranges to have a C function called when the
|
||||
current trampoline-enabled command in the Tcl interpreter designated
|
||||
by \fIinterp\fR returns. The \fIpostProcPtr\fR argument is a pointer
|
||||
to the callback function, which must have arguments and return value
|
||||
consistent with the \fBTcl_NRPostProc\fR data type:
|
||||
.PP
|
||||
.CS
|
||||
typedef int
|
||||
@@ -135,13 +185,25 @@ typedef int
|
||||
int \fIresult\fR);
|
||||
.CE
|
||||
.PP
|
||||
\fIdata\fR is a pointer to an array containing \fIdata0\fR through \fIdata3\fR.
|
||||
\fIresult\fR is the value returned by the previous function implementing part
|
||||
the routine.
|
||||
When the trampoline invokes the callback function, the \fIdata\fR
|
||||
parameter will point to an array containing the four one-word
|
||||
quantities that were passed to \fBTcl_NRAddCallback\fR in the
|
||||
\fIdata0\fR through \fIdata3\fR parameters. The Tcl interpreter will
|
||||
be designated by the \fIinterp\fR parameter, and the \fIresult\fR
|
||||
parameter will contain the result (\fBTCL_OK\fR, \fBTCL_ERROR\fR,
|
||||
\fBTCL_RETURN\fR, \fBTCL_BREAK\fR or \fBTCL_CONTINUE\fR) that was
|
||||
returned by the command evaluation. The callback function is expected,
|
||||
in turn, either to return a \fIresult\fR to control further evaluation.
|
||||
.PP
|
||||
Multiple \fBTcl_NRAddCallback\fR invocations may request multiple
|
||||
callbacks, which may be to the same or different callback
|
||||
functions. If multiple callbacks are requested, they are executed in
|
||||
last-in, first-out order, that is, the most recently requested
|
||||
callback is executed first.
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
The following command uses \fBTcl_EvalObjEx\fR, which consumes space on the C
|
||||
stack, to evalute a script:
|
||||
The usual pattern for Tcl commands that invoke other Tcl commands
|
||||
is something like:
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
@@ -166,17 +228,28 @@ int
|
||||
\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:
|
||||
To enable a command like this one for trampoline-based evaluation,
|
||||
it must be split into three pieces:
|
||||
.IP \(bu
|
||||
A non-trampoline implementation, \fITheCmdNewObjProc\fR,
|
||||
which will simply create a trampoline
|
||||
and invoke the trampoline-based implementation.
|
||||
.IP \(bu
|
||||
A trampoline-enabled implementation, \fITheCmdNRObjProc\fR. This
|
||||
function will perform the initialization, request that the trampoline
|
||||
call the postprocessing routine after command evaluation, and finally,
|
||||
request that the trampoline call the inner command.
|
||||
.IP \(bu
|
||||
A postprocessing routine, \fITheCmdPostProc\fR. This function will
|
||||
perform the postprocessing formerly done after the return from the
|
||||
inner command in \fITheCmdObjProc\fR.
|
||||
.PP
|
||||
The non-trampoline implementation is simple and stylized, containing
|
||||
a single statement:
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
\fITheCmdOldObjProc\fR(
|
||||
\fITheCmdNewObjProc\fR(
|
||||
ClientData clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
@@ -187,6 +260,9 @@ int
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
The trampoline-enabled implementation requests postprocessing,
|
||||
and returns to the trampoline requesting command evaluation.
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
\fITheCmdNRObjProc\fR
|
||||
@@ -208,6 +284,9 @@ int
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
The postprocessing procedure does whatever the original command did
|
||||
upon return from the inner evaluation.
|
||||
.PP
|
||||
.CS
|
||||
int
|
||||
\fITheCmdNRPostProc\fR(
|
||||
@@ -224,13 +303,26 @@ int
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
Any function comprising a routine can push other functions, making it possible
|
||||
implement looping and sequencing constructs using the function stack.
|
||||
If \fItheCommand\fR is a command that results in multiple commands or
|
||||
scripts being evaluated, its postprocessing routine may schedule
|
||||
additional postprocessing and then request another command evaluation
|
||||
by means of \fBTcl_NREvalObj\fR or one of the other evaluation
|
||||
routines. Looping and sequencing constructs may be implemented in this way.
|
||||
.PP
|
||||
Finally, to install a trampoline-enabled command in the interpreter,
|
||||
\fBTcl_NRCreateCommand\fR is used in place of
|
||||
\fBTcl_CreateObjCommand\fR. It accepts two command procedures instead
|
||||
of one. The first is for use when no trampoline is yet on the stack,
|
||||
and the second is for use when there is already a trampoline in place.
|
||||
.PP
|
||||
.CS
|
||||
\fBTcl_NRCreateCommand\fR(interp, "theCommand",
|
||||
\fITheCmdNewObjProc\fR, \fITheCmdNRObjProc\fR, clientData,
|
||||
TheCmdDeleteProc);
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
Tcl_CreateCommand(3), Tcl_CreateObjCommand(3), Tcl_EvalObjEx(3), Tcl_GetCommandFromObj(3), Tcl_ExprObj(3)
|
||||
.SH KEYWORDS
|
||||
stackless, nonrecursive, execute, command, global, value, result, script
|
||||
.SH COPYRIGHT
|
||||
Copyright (c) 2008 by Kevin B. Kenny.
|
||||
Copyright (c) 2018 by Nathan Coulter.
|
||||
Copyright (c) 2008 by Kevin B. Kenny
|
||||
|
||||
+1
-1
@@ -257,7 +257,7 @@ The \fBincr\fR command first gets an integer from \fIx\fR's value
|
||||
by calling \fBTcl_GetIntFromObj\fR.
|
||||
This procedure checks whether the value is already an integer value.
|
||||
Since it is not, it converts the value
|
||||
by setting the value's internal representation
|
||||
by setting the value's \fIinternalRep.longValue\fR member
|
||||
to the integer \fB123\fR
|
||||
and setting the value's \fItypePtr\fR
|
||||
to point to the integer Tcl_ObjType structure.
|
||||
|
||||
+2
-17
@@ -7,7 +7,7 @@
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc, Tcl_ConsolePanic \- report fatal error and abort
|
||||
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc \- report fatal error and abort
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tcl.h>\fR
|
||||
@@ -21,9 +21,6 @@ void
|
||||
void
|
||||
\fBTcl_SetPanicProc\fR(\fIpanicProc\fR)
|
||||
.sp
|
||||
void
|
||||
\fBTcl_ConsolePanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR)
|
||||
.sp
|
||||
.SH ARGUMENTS
|
||||
.AS Tcl_PanicProc *panicProc
|
||||
.AP "const char*" format in
|
||||
@@ -57,14 +54,6 @@ message is sent to the debugger in stead. If the windows executable
|
||||
does not have a stderr channel (e.g. \fBwish.exe\fR), then a
|
||||
system dialog box is used to display the panic message.
|
||||
.PP
|
||||
If your application doesn't use \fBTcl_Main\fR or \fBTk_Main\fR
|
||||
and you want to implicitly use the stderr channel of your
|
||||
application's C runtime (in stead of the stderr channel of the
|
||||
C runtime used by Tcl), you can call \fBTcl_SetPanicProc\fR
|
||||
with \fBTcl_ConsolePanic\fR as its argument. On platforms which
|
||||
only have one C runtime (almost all platforms except Windows)
|
||||
\fBTcl_ConsolePanic\fR is equivalent to NULL.
|
||||
.PP
|
||||
\fBTcl_SetPanicProc\fR may be used to modify the behavior of
|
||||
\fBTcl_Panic\fR. The \fIpanicProc\fR argument should match the
|
||||
type \fBTcl_PanicProc\fR:
|
||||
@@ -93,11 +82,7 @@ have a panic message displayed the same way that panic messages from Tcl
|
||||
will be displayed.
|
||||
.PP
|
||||
\fBTcl_PanicVA\fR is the same as \fBTcl_Panic\fR except that instead of
|
||||
taking a variable number of arguments it takes an argument list. This
|
||||
function is deprecated and will be removed in Tcl 9.0.
|
||||
.PP
|
||||
This function can not be used in stub-enabled extensions. Its symbol
|
||||
entry in the stub table is deprecated and it will be removed in Tcl 9.0.
|
||||
taking a variable number of arguments it takes an argument list.
|
||||
.SH "SEE ALSO"
|
||||
abort(3), printf(3), exec(n), format(n)
|
||||
.SH KEYWORDS
|
||||
|
||||
+2
-2
@@ -103,8 +103,8 @@ the argument's value. The following values are acceptable values for
|
||||
\fBTCL_ARGV_CONSTANT\fR
|
||||
.
|
||||
The argument does not take any following value argument. If this argument is
|
||||
present, the \fIsrcPtr\fR field (casted to \fIint\fR) is copied to the variable
|
||||
pointed to by the \fIdstPtr\fR field. The \fIclientData\fR field is ignored.
|
||||
present, the int pointed to by the \fIsrcPtr\fR field is copied to the
|
||||
\fIdstPtr\fR field. The \fIclientData\fR field is ignored.
|
||||
.TP
|
||||
\fBTCL_ARGV_END\fR
|
||||
.
|
||||
|
||||
@@ -32,6 +32,8 @@ the command at global level instead of the current stack level.
|
||||
.PP
|
||||
\fBTcl_RecordAndEvalObj\fR is invoked to record a command as an event
|
||||
on the history list and then execute it using \fBTcl_EvalObjEx\fR
|
||||
(or \fBTcl_GlobalEvalObj\fR if the \fBTCL_EVAL_GLOBAL\fR bit is set
|
||||
in \fIflags\fR).
|
||||
It returns a completion code such as \fBTCL_OK\fR just like \fBTcl_EvalObjEx\fR,
|
||||
as well as a result value containing additional information
|
||||
(a result value or error message)
|
||||
|
||||
+71
-36
@@ -1,7 +1,6 @@
|
||||
'\"
|
||||
'\" Copyright (c) 1997 by Sun Microsystems, Inc.
|
||||
'\" Contributions from Don Porter, NIST, 2004. (not subject to US copyright)
|
||||
'\" Copyright (c) 2018 Nathan Coulter.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -10,9 +9,7 @@
|
||||
.so man.macros
|
||||
.BS
|
||||
.SH NAME
|
||||
Tcl_SaveInterpState, Tcl_RestoreInterpState, Tcl_DiscardInterpState,
|
||||
Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- Save and restore the
|
||||
state of an an interpreter.
|
||||
Tcl_SaveInterpState, Tcl_RestoreInterpState, Tcl_DiscardInterpState, Tcl_SaveResult, Tcl_RestoreResult, Tcl_DiscardResult \- save and restore an interpreter's state
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB#include <tcl.h>\fR
|
||||
@@ -33,53 +30,91 @@ int
|
||||
.SH ARGUMENTS
|
||||
.AS Tcl_InterpState savedPtr
|
||||
.AP Tcl_Interp *interp in
|
||||
The interpreter for the operation.
|
||||
Interpreter for which state should be saved.
|
||||
.AP int status in
|
||||
The return code for the state.
|
||||
Return code value to save as part of interpreter state.
|
||||
.AP Tcl_InterpState state in
|
||||
A token for saved state.
|
||||
Saved state token to be restored or discarded.
|
||||
.AP Tcl_SavedResult *savedPtr in
|
||||
A pointer to storage for saved state.
|
||||
Pointer to location where interpreter result should be saved or restored.
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
These routines save the state of an interpreter before a call to a routine such
|
||||
as \fBTcl_Eval\fR, and restore the state afterwards.
|
||||
These routines allows a C procedure to take a snapshot of the current
|
||||
state of an interpreter so that it can be restored after a call
|
||||
to \fBTcl_Eval\fR or some other routine that modifies the interpreter
|
||||
state. There are two triplets of routines meant to work together.
|
||||
.PP
|
||||
\fBTcl_SaveInterpState\fR saves the parts of \fIinterp\fR that comprise the
|
||||
result of a script, including the resulting value, the return code passed as
|
||||
\fIstatus\fR, and any options such as \fB\-errorinfo\fR and \fB\-errorcode\fR.
|
||||
It returns a token for the saved state. The interpreter result is not reset
|
||||
and no interpreter state is changed.
|
||||
The first triplet stores the snapshot of interpreter state in
|
||||
an opaque token returned by \fBTcl_SaveInterpState\fR. That token
|
||||
value may then be passed back to one of \fBTcl_RestoreInterpState\fR
|
||||
or \fBTcl_DiscardInterpState\fR, depending on whether the interp
|
||||
state is to be restored. So long as one of the latter two routines
|
||||
is called, Tcl will take care of memory management.
|
||||
.PP
|
||||
\fBTcl_RestoreInterpState\fR restores the state indicated by \fIstate\fR and
|
||||
returns the \fIstatus\fR originally passed in the corresponding call to
|
||||
\fBTcl_SaveInterpState\fR.
|
||||
The second triplet stores the snapshot of only the interpreter
|
||||
result (not its complete state) in memory allocated by the caller.
|
||||
These routines are passed a pointer to a \fBTcl_SavedResult\fR structure
|
||||
that is used to store enough information to restore the interpreter result.
|
||||
This structure can be allocated on the stack of the calling
|
||||
procedure. These routines do not save the state of any error
|
||||
information in the interpreter (e.g. the \fB\-errorcode\fR or
|
||||
\fB\-errorinfo\fR return options, when an error is in progress).
|
||||
.PP
|
||||
If a saved state is not restored, \fBTcl_DiscardInterpState\fR must be called
|
||||
to release it. A token used to discard or restore state must not be used
|
||||
again.
|
||||
Because the routines \fBTcl_SaveInterpState\fR,
|
||||
\fBTcl_RestoreInterpState\fR, and \fBTcl_DiscardInterpState\fR perform
|
||||
a superset of the functions provided by the other routines,
|
||||
any new code should only make use of the more powerful routines.
|
||||
The older, weaker routines \fBTcl_SaveResult\fR, \fBTcl_RestoreResult\fR,
|
||||
and \fBTcl_DiscardResult\fR continue to exist only for the sake
|
||||
of existing programs that may already be using them.
|
||||
.PP
|
||||
\fBTcl_SaveResult\fR, \fBTcl_RestoreResult\fR, and \fBTcl_DiscardResult\fR are
|
||||
deprecated. Instead use \fBTcl_SaveInterpState\fR,
|
||||
\fBTcl_RestoreInterpState\fR, and \fBTcl_DiscardInterpState\fR, which are more
|
||||
capable.
|
||||
\fBTcl_SaveInterpState\fR takes a snapshot of those portions of
|
||||
interpreter state that make up the full result of script evaluation.
|
||||
This include the interpreter result, the return code (passed in
|
||||
as the \fIstatus\fR argument, and any return options, including
|
||||
\fB\-errorinfo\fR and \fB\-errorcode\fR when an error is in progress.
|
||||
This snapshot is returned as an opaque token of type \fBTcl_InterpState\fR.
|
||||
The call to \fBTcl_SaveInterpState\fR does not itself change the
|
||||
state of the interpreter. Unlike \fBTcl_SaveResult\fR, it does
|
||||
not reset the interpreter.
|
||||
.PP
|
||||
\fBTcl_SaveResult\fR moves the result of \fIinterp\fR to the location
|
||||
\fIstatePtr\fR points to and returns the interpreter result to its initial
|
||||
state. It does not save options such as \fB\-errorcode\fR or
|
||||
\fB\-errorinfo\fR.
|
||||
\fBTcl_RestoreInterpState\fR accepts a \fBTcl_InterpState\fR token
|
||||
previously returned by \fBTcl_SaveInterpState\fR and restores the
|
||||
state of the interp to the state held in that snapshot. The return
|
||||
value of \fBTcl_RestoreInterpState\fR is the status value originally
|
||||
passed to \fBTcl_SaveInterpState\fR when the snapshot token was
|
||||
created.
|
||||
.PP
|
||||
\fBTcl_RestoreResult\fR clears any existing result or error in \fIinterp\fR and
|
||||
moves the result from \fIstatePtr\fR back to \fIinterp\fR. \fIstatePtr\fR is
|
||||
then in an undefined state and must not be used until passed again to
|
||||
\fBTcl_DiscardInterpState\fR is called to release a \fBTcl_InterpState\fR
|
||||
token previously returned by \fBTcl_SaveInterpState\fR when that
|
||||
snapshot is not to be restored to an interp.
|
||||
.PP
|
||||
The \fBTcl_InterpState\fR token returned by \fBTcl_SaveInterpState\fR
|
||||
must eventually be passed to either \fBTcl_RestoreInterpState\fR
|
||||
or \fBTcl_DiscardInterpState\fR to avoid a memory leak. Once
|
||||
the \fBTcl_InterpState\fR token is passed to one of them, the
|
||||
token is no longer valid and should not be used anymore.
|
||||
.PP
|
||||
\fBTcl_SaveResult\fR moves the string and value results
|
||||
of \fIinterp\fR into the location specified by \fIstatePtr\fR.
|
||||
\fBTcl_SaveResult\fR clears the result for \fIinterp\fR and
|
||||
leaves the result in its normal empty initialized state.
|
||||
.PP
|
||||
\fBTcl_RestoreResult\fR moves the string and value results from
|
||||
\fIstatePtr\fR back into \fIinterp\fR. Any result or error that was
|
||||
already in the interpreter will be cleared. The \fIstatePtr\fR is left
|
||||
in an uninitialized state and cannot be used until another call to
|
||||
\fBTcl_SaveResult\fR.
|
||||
.PP
|
||||
\fBTcl_DiscardResult\fR releases the state stored at \fBstatePtr\fR, which is
|
||||
then in an undefined state and must not be used until passed again to
|
||||
\fBTcl_DiscardResult\fR releases the saved interpreter state
|
||||
stored at \fBstatePtr\fR. The state structure is left in an
|
||||
uninitialized state and cannot be used until another call to
|
||||
\fBTcl_SaveResult\fR.
|
||||
.PP
|
||||
If a saved result is not restored, \fBTcl_DiscardResult\fR must be called to
|
||||
release it.
|
||||
Once \fBTcl_SaveResult\fR is called to save the interpreter
|
||||
result, either \fBTcl_RestoreResult\fR or
|
||||
\fBTcl_DiscardResult\fR must be called to properly clean up the
|
||||
memory associated with the saved state.
|
||||
.SH KEYWORDS
|
||||
result, state, interp
|
||||
|
||||
@@ -64,9 +64,6 @@ the event of an error it should set the interpreter's result to point to an
|
||||
error message. The result or error from the initialization procedure will
|
||||
be returned as the result of the \fBload\fR command that caused the
|
||||
initialization procedure to be invoked.
|
||||
.PP
|
||||
This function can not be used in stub-enabled extensions. Its symbol
|
||||
entry in the stub table is deprecated and it will be removed in Tcl 9.0.
|
||||
.SH KEYWORDS
|
||||
initialization procedure, package, static linking
|
||||
.SH "SEE ALSO"
|
||||
|
||||
+2
-3
@@ -37,7 +37,7 @@ Tcl_UniChar *
|
||||
Tcl_UniChar *
|
||||
\fBTcl_GetUnicode\fR(\fIobjPtr\fR)
|
||||
.sp
|
||||
int
|
||||
Tcl_UniChar
|
||||
\fBTcl_GetUniChar\fR(\fIobjPtr, index\fR)
|
||||
.sp
|
||||
int
|
||||
@@ -204,8 +204,7 @@ where the caller does not need the length of the unicode string
|
||||
representation.
|
||||
.PP
|
||||
\fBTcl_GetUniChar\fR returns the \fIindex\fR'th character in the
|
||||
value's Unicode representation. If the index is out of range or
|
||||
it references a low surrogate preceded by a high surrogate, it returns -1;
|
||||
value's Unicode representation.
|
||||
.PP
|
||||
\fBTcl_GetRange\fR returns a newly created value comprised of the
|
||||
characters between \fIfirst\fR and \fIlast\fR (inclusive) in the
|
||||
|
||||
@@ -28,10 +28,10 @@ First, the Tcl interpreter breaks the command into \fIwords\fR
|
||||
and performs substitutions as described below.
|
||||
These substitutions are performed in the same way for all
|
||||
commands.
|
||||
Secondly, the first word is used to locate a routine to
|
||||
carry out the command, and the remaining words of the command are
|
||||
passed to that routine.
|
||||
The routine is free to interpret each of its words
|
||||
Secondly, the first word is used to locate a command procedure to
|
||||
carry out the command, then all of the words of the command are
|
||||
passed to the command procedure.
|
||||
The command procedure is free to interpret each of its words
|
||||
in any way it likes, such as an integer, variable name, list,
|
||||
or Tcl script.
|
||||
Different commands interpret their words differently.
|
||||
|
||||
@@ -189,8 +189,6 @@ procedure (if any) returns. In non-interactive mode, after
|
||||
\fBTcl_Main\fR evaluates the startup script, and the main loop
|
||||
procedure (if any) returns, \fBTcl_Main\fR will also evaluate
|
||||
the \fBexit\fR command.
|
||||
.PP
|
||||
This function can not be used in stub-enabled extensions.
|
||||
.SH "SEE ALSO"
|
||||
tclsh(1), Tcl_GetStdChannel(3), Tcl_StandardChannels(3), Tcl_AppInit(3),
|
||||
exit(n), encoding(n)
|
||||
|
||||
+3
-9
@@ -45,9 +45,7 @@ int
|
||||
.AP Tcl_Condition *condPtr in
|
||||
A condition variable, which must be associated with a mutex lock.
|
||||
.AP Tcl_Mutex *mutexPtr in
|
||||
.VS TIP509
|
||||
A recursive mutex lock.
|
||||
.VE TIP509
|
||||
A mutex lock.
|
||||
.AP "const Tcl_Time" *timePtr in
|
||||
A time limit on the condition wait. NULL to wait forever.
|
||||
Note that a polling value of 0 seconds does not make much sense.
|
||||
@@ -142,12 +140,8 @@ of code by calling \fBTcl_MutexLock\fR and \fBTcl_MutexUnlock\fR.
|
||||
If one thread holds a mutex, any other thread calling \fBTcl_MutexLock\fR will
|
||||
block until \fBTcl_MutexUnlock\fR is called.
|
||||
A mutex can be destroyed after its use by calling \fBTcl_MutexFinalize\fR.
|
||||
.VS TIP509
|
||||
Mutexes are reentrant: they can be locked several times from the same
|
||||
thread. However there must be exactly one call to
|
||||
\fBTcl_MutexUnlock\fR for each call to \fBTcl_MutexLock\fR in order
|
||||
for a thread to release a mutex completely.
|
||||
.VE TIP509
|
||||
The result of locking a mutex twice from the same thread is undefined.
|
||||
On some platforms it will result in a deadlock.
|
||||
The \fBTcl_MutexLock\fR, \fBTcl_MutexUnlock\fR and \fBTcl_MutexFinalize\fR
|
||||
procedures are defined as empty macros if not compiling with threads enabled.
|
||||
For declaration of mutexes the \fBTCL_DECLARE_MUTEX\fR macro should be used.
|
||||
|
||||
+10
-4
@@ -13,13 +13,13 @@ Tcl_UniCharToUpper, Tcl_UniCharToLower, Tcl_UniCharToTitle, Tcl_UtfToUpper, Tcl_
|
||||
.nf
|
||||
\fB#include <tcl.h>\fR
|
||||
.sp
|
||||
int
|
||||
Tcl_UniChar
|
||||
\fBTcl_UniCharToUpper\fR(\fIch\fR)
|
||||
.sp
|
||||
int
|
||||
Tcl_UniChar
|
||||
\fBTcl_UniCharToLower\fR(\fIch\fR)
|
||||
.sp
|
||||
int
|
||||
Tcl_UniChar
|
||||
\fBTcl_UniCharToTitle\fR(\fIch\fR)
|
||||
.sp
|
||||
int
|
||||
@@ -33,7 +33,7 @@ int
|
||||
.SH ARGUMENTS
|
||||
.AS char *str in/out
|
||||
.AP int ch in
|
||||
The Unicode character to be converted.
|
||||
The Tcl_UniChar to be converted.
|
||||
.AP char *str in/out
|
||||
Pointer to UTF-8 string to be converted in place.
|
||||
.BE
|
||||
@@ -78,5 +78,11 @@ turns each character in the string into its lower-case equivalent.
|
||||
turns the first character in the string into its title-case equivalent
|
||||
and all following characters into their lower-case equivalents.
|
||||
|
||||
.SH BUGS
|
||||
.PP
|
||||
At this time, the case conversions are only defined for the ISO8859-1
|
||||
characters. Unicode characters above 0x00ff are not modified by these
|
||||
routines.
|
||||
|
||||
.SH KEYWORDS
|
||||
utf, unicode, toupper, tolower, totitle, case
|
||||
|
||||
@@ -48,16 +48,19 @@ int
|
||||
.SH ARGUMENTS
|
||||
.AS int ch
|
||||
.AP int ch in
|
||||
The Unicode character to be examined.
|
||||
The Tcl_UniChar to be examined.
|
||||
.BE
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
All of the routines described examine Unicode characters and return a
|
||||
All of the routines described examine Tcl_UniChars and return a
|
||||
boolean value. A non-zero return value means that the character does
|
||||
belong to the character class associated with the called routine. The
|
||||
rest of this document just describes the character classes associated
|
||||
with the various routines.
|
||||
.PP
|
||||
Note: A Tcl_UniChar is a Unicode character represented as an unsigned,
|
||||
fixed-size quantity.
|
||||
|
||||
.SH "CHARACTER CLASSES"
|
||||
.PP
|
||||
|
||||
@@ -63,7 +63,7 @@ const char *
|
||||
const char *
|
||||
\fBTcl_UtfPrev\fR(\fIsrc, start\fR)
|
||||
.sp
|
||||
int
|
||||
Tcl_UniChar
|
||||
\fBTcl_UniCharAtIndex\fR(\fIsrc, index\fR)
|
||||
.sp
|
||||
const char *
|
||||
@@ -77,7 +77,7 @@ int
|
||||
Buffer in which the UTF-8 representation of the Tcl_UniChar is stored. At most
|
||||
\fBTCL_UTF_MAX\fR bytes are stored in the buffer.
|
||||
.AP int ch in
|
||||
The Unicode character to be converted or examined.
|
||||
The Tcl_UniChar to be converted or examined.
|
||||
.AP Tcl_UniChar *chPtr out
|
||||
Filled with the Tcl_UniChar represented by the head of the UTF-8 string.
|
||||
.AP "const char" *src in
|
||||
@@ -121,8 +121,8 @@ case-insensitive (1).
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
These routines convert between UTF-8 strings and Unicode characters. An
|
||||
Unicode character represented as an unsigned, fixed-size
|
||||
These routines convert between UTF-8 strings and Tcl_UniChars. A
|
||||
Tcl_UniChar is a Unicode character represented as an unsigned, fixed-size
|
||||
quantity. A UTF-8 character is a Unicode character represented as
|
||||
a varying-length sequence of up to \fBTCL_UTF_MAX\fR bytes. A multibyte UTF-8
|
||||
sequence consists of a lead byte followed by some number of trail bytes.
|
||||
@@ -130,13 +130,9 @@ sequence consists of a lead byte followed by some number of trail bytes.
|
||||
\fBTCL_UTF_MAX\fR is the maximum number of bytes that it takes to
|
||||
represent one Unicode character in the UTF-8 representation.
|
||||
.PP
|
||||
\fBTcl_UniCharToUtf\fR stores the character \fIch\fR as a UTF-8 string
|
||||
\fBTcl_UniCharToUtf\fR stores the Tcl_UniChar \fIch\fR as a UTF-8 string
|
||||
in starting at \fIbuf\fR. The return value is the number of bytes stored
|
||||
in \fIbuf\fR. If ch is a high surrogate (range U+D800 - U+DBFF), then
|
||||
the return value will be 1 and a single byte in the range 0xF0 - 0xF4
|
||||
will be stored. If you still want to produce UTF-8 output for it (even
|
||||
though knowing it's an illegal code-point on its own), just call
|
||||
\fBTcl_UniCharToUtf\fR again specifying ch = -1.
|
||||
in \fIbuf\fR.
|
||||
.PP
|
||||
\fBTcl_UtfToUniChar\fR reads one UTF-8 character starting at \fIsrc\fR
|
||||
and stores it as a Tcl_UniChar in \fI*chPtr\fR. The return value is the
|
||||
@@ -144,9 +140,6 @@ number of bytes read from \fIsrc\fR. The caller must ensure that the
|
||||
source buffer is long enough such that this routine does not run off the
|
||||
end and dereference non-existent or random memory; if the source buffer
|
||||
is known to be null-terminated, this will not happen. If the input is
|
||||
a byte in the range 0x80 - 0x9F, \fBTcl_UtfToUniChar\fR assumes the
|
||||
cp1252 encoding, stores the corresponding Tcl_UniChar in \fI*chPtr\fR
|
||||
and returns 1. If the input is otherwise
|
||||
not in proper UTF-8 format, \fBTcl_UtfToUniChar\fR will store the first
|
||||
byte of \fIsrc\fR in \fI*chPtr\fR as a Tcl_UniChar between 0x0000 and
|
||||
0x00ff and return 1.
|
||||
@@ -207,7 +200,7 @@ of \fIlength\fR bytes is long enough to be decoded by
|
||||
\fBTcl_UtfToUniChar\fR, or 0 otherwise. This function does not guarantee
|
||||
that the UTF-8 string is properly formed. This routine is used by
|
||||
procedures that are operating on a byte at a time and need to know if a
|
||||
full Unicode character has been seen.
|
||||
full Tcl_UniChar has been seen.
|
||||
.PP
|
||||
\fBTcl_NumUtfChars\fR corresponds to \fBstrlen\fR for UTF-8 strings. It
|
||||
returns the number of Tcl_UniChars that are represented by the UTF-8 string
|
||||
@@ -215,12 +208,12 @@ returns the number of Tcl_UniChars that are represented by the UTF-8 string
|
||||
length is negative, all bytes up to the first null byte are used.
|
||||
.PP
|
||||
\fBTcl_UtfFindFirst\fR corresponds to \fBstrchr\fR for UTF-8 strings. It
|
||||
returns a pointer to the first occurrence of the Unicode character \fIch\fR
|
||||
returns a pointer to the first occurrence of the Tcl_UniChar \fIch\fR
|
||||
in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is
|
||||
considered part of the UTF-8 string.
|
||||
.PP
|
||||
\fBTcl_UtfFindLast\fR corresponds to \fBstrrchr\fR for UTF-8 strings. It
|
||||
returns a pointer to the last occurrence of the Unicode character \fIch\fR
|
||||
returns a pointer to the last occurrence of the Tcl_UniChar \fIch\fR
|
||||
in the null-terminated UTF-8 string \fIsrc\fR. The null terminator is
|
||||
considered part of the UTF-8 string.
|
||||
.PP
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH abstract n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
oo::abstract \- a class that does not allow direct instances of itself
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBoo::abstract\fI method \fR?\fIarg ...\fR?
|
||||
.fi
|
||||
.SH "CLASS HIERARCHY"
|
||||
.nf
|
||||
\fBoo::object\fR
|
||||
\(-> \fBoo::class\fR
|
||||
\(-> \fBoo::abstract\fR
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
Abstract classes are classes that can contain definitions, but which cannot be
|
||||
directly manufactured; they are intended to only ever be inherited from and
|
||||
instantiated indirectly. The characteristic methods of \fBoo::class\fR
|
||||
(\fBcreate\fR and \fBnew\fR) are not exported by an instance of
|
||||
\fBoo::abstract\fR.
|
||||
.PP
|
||||
Note that \fBoo::abstract\fR is not itself an instance of \fBoo::abstract\fR.
|
||||
.SS CONSTRUCTOR
|
||||
The \fBoo::abstract\fR class does not define an explicit constructor; this
|
||||
means that it is effectively the same as the constructor of the
|
||||
\fBoo::class\fR class.
|
||||
.SS DESTRUCTOR
|
||||
The \fBoo::abstract\fR class does not define an explicit destructor;
|
||||
destroying an instance of it is just like destroying an ordinary class (and
|
||||
will destroy all its subclasses).
|
||||
.SS "EXPORTED METHODS"
|
||||
The \fBoo::abstract\fR class defines no new exported methods.
|
||||
.SS "NON-EXPORTED METHODS"
|
||||
The \fBoo::abstract\fR class explicitly states that \fBcreate\fR,
|
||||
\fBcreateWithNamespace\fR, and \fBnew\fR are unexported.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
This example defines a simple class hierarchy and creates a new instance of
|
||||
it. It then invokes a method of the object before destroying the hierarchy and
|
||||
showing that the destruction is transitive.
|
||||
.PP
|
||||
.CS
|
||||
\fBoo::abstract\fR create fruit {
|
||||
method eat {} {
|
||||
puts "yummy!"
|
||||
}
|
||||
}
|
||||
oo::class create banana {
|
||||
superclass fruit
|
||||
method peel {} {
|
||||
puts "skin now off"
|
||||
}
|
||||
}
|
||||
set b [banana \fBnew\fR]
|
||||
$b peel \fI\(-> prints 'skin now off'\fR
|
||||
$b eat \fI\(-> prints 'yummy!'\fR
|
||||
set f [fruit new] \fI\(-> error 'unknown method "new"...'\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
oo::define(n), oo::object(n)
|
||||
.SH KEYWORDS
|
||||
abstract class, class, metaclass, object
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
+3
-9
@@ -20,11 +20,6 @@ Append all of the \fIvalue\fR arguments to the current value
|
||||
of variable \fIvarName\fR. If \fIvarName\fR does not exist,
|
||||
it is given a value equal to the concatenation of all the
|
||||
\fIvalue\fR arguments.
|
||||
.VS TIP508
|
||||
If \fIvarName\fR indicate an element that does not exist of an array that has
|
||||
a default value set, the concatenation of the default value and all the
|
||||
\fIvalue\fR arguments will be stored in the array element.
|
||||
.VE TIP508
|
||||
The result of this command is the new value stored in variable
|
||||
\fIvarName\fR.
|
||||
This command provides an efficient way to build up long
|
||||
@@ -49,7 +44,6 @@ puts $var
|
||||
concat(n), lappend(n)
|
||||
.SH KEYWORDS
|
||||
append, variable
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" End:
|
||||
|
||||
+1
-61
@@ -5,7 +5,7 @@
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH array n 8.7 Tcl "Tcl Built-In Commands"
|
||||
.TH array n 8.3 Tcl "Tcl Built-In Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
@@ -36,53 +36,6 @@ with an empty name, since the return value from
|
||||
\fBarray nextelement\fR will not indicate whether the search
|
||||
has been completed.
|
||||
.TP
|
||||
\fBarray default \fIsubcommand arrayName args...\fR
|
||||
.VS TIP508
|
||||
Manages the default value of the array. Arrays initially have no default
|
||||
value, but this command allows you to set one; the default value will be
|
||||
returned when reading from an element of the array \fIarrayName\fR if the read
|
||||
would otherwise result in an error. Note that this may cause the \fBappend\fR,
|
||||
\fBdict\fR, \fBincr\fR and \fBlappend\fR commands to change their behavior in
|
||||
relation to non-existing array elements.
|
||||
.RS
|
||||
.PP
|
||||
The \fIsubcommand\fR argument controls what exact operation will be performed
|
||||
on the default value of \fIarrayName\fR. Supported \fIsubcommand\fRs are:
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBarray default exists \fIarrayName\fR
|
||||
.VS TIP508
|
||||
This returns a boolean value indicating whether a default value has been set
|
||||
for the array \fIarrayName\fR. Returns a false value if \fIarrayName\fR does
|
||||
not exist. Raises an error if \fIarrayName\fR is an existing variable that is
|
||||
not an array.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBarray default get \fIarrayName\fR
|
||||
.VS TIP508
|
||||
This returns the current default value for the array \fIarrayName\fR. Raises
|
||||
an error if \fIarrayName\fR is an existing variable that is not an array, or
|
||||
if \fIarrayName\fR is an array without a default value.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBarray default set \fIarrayName value\fR
|
||||
.VS TIP508
|
||||
This sets the default value for the array \fIarrayName\fR to \fIvalue\fR.
|
||||
Returns the empty string. Raises an error if \fIarrayName\fR is an existing
|
||||
variable that is not an array, or if \fIarrayName\fR is an illegal name for an
|
||||
array. If \fIarrayName\fR does not currently exist, it is created as an empty
|
||||
array as well as having its default value set.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBarray default unset \fIarrayName\fR
|
||||
.VS TIP508
|
||||
This removes the default value for the array \fIarrayName\fR and returns the
|
||||
empty string. Does nothing if \fIarrayName\fR does not have a default
|
||||
value. Raises an error if \fIarrayName\fR is an existing variable that is not
|
||||
an array.
|
||||
.VE TIP508
|
||||
.RE
|
||||
.TP
|
||||
\fBarray donesearch \fIarrayName searchId\fR
|
||||
This command terminates an array search and destroys all the
|
||||
state associated with that search. \fISearchId\fR indicates
|
||||
@@ -94,15 +47,6 @@ been the return value from a previous invocation of
|
||||
Returns 1 if \fIarrayName\fR is an array variable, 0 if there
|
||||
is no variable by that name or if it is a scalar variable.
|
||||
.TP
|
||||
\fBarray for {\fIkeyVariable valueVariable\fB} \fIarrayName body\fP
|
||||
The first argument is a two element list of variable names for the
|
||||
key and value of each entry in the array. The second argument is the
|
||||
array name to iterate over. The third argument is the body to execute
|
||||
for each key and value returned.
|
||||
The ordering of the returned keys is undefined.
|
||||
If an array element is deleted or a new array element is inserted during
|
||||
the \fIarray for\fP process, the command will terminate with an error.
|
||||
.TP
|
||||
\fBarray get \fIarrayName\fR ?\fIpattern\fR?
|
||||
Returns a list containing pairs of elements. The first
|
||||
element in each pair is the name of an element in \fIarrayName\fR
|
||||
@@ -241,7 +185,3 @@ foreach color [lsort [\fBarray names\fR colorcount]] {
|
||||
list(n), string(n), variable(n), trace(n), foreach(n)
|
||||
.SH KEYWORDS
|
||||
array, element names, search
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH callback n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
callback, mymethod \- generate callbacks to methods
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBcallback\fR \fImethodName\fR ?\fIarg ...\fR?
|
||||
\fBmymethod\fR \fImethodName\fR ?\fIarg ...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
The \fBcallback\fR command,
|
||||
'\" Based on notes in the tcllib docs, we know the provenance of mymethod
|
||||
also called \fBmymethod\fR for compatibility with the ooutil and snit packages
|
||||
of Tcllib,
|
||||
and which should only be used from within the context of a call to a method
|
||||
(i.e. inside a method, constructor or destructor body) is used to generate a
|
||||
script fragment that will invoke the method, \fImethodName\fR, on the current
|
||||
object (as reported by \fBself\fR) when executed. Any additional arguments
|
||||
provided will be provided as leading arguments to the callback. The resulting
|
||||
script fragment shall be a proper list.
|
||||
.PP
|
||||
Note that it is up to the caller to ensure that the current object is able to
|
||||
handle the call of \fImethodName\fR; this command does not check that.
|
||||
\fImethodName\fR may refer to any exported or unexported method, but may not
|
||||
refer to a private method as those can only be invoked directly from within
|
||||
methods. If there is no such method present at the point when the callback is
|
||||
invoked, the standard \fBunknown\fR method handler will be called.
|
||||
.SH EXAMPLE
|
||||
This is a simple echo server class. The \fBcallback\fR command is used in two
|
||||
places, to arrange for the incoming socket connections to be handled by the
|
||||
\fIAccept\fR method, and to arrange for the incoming bytes on those
|
||||
connections to be handled by the \fIReceive\fR method.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create EchoServer {
|
||||
variable server clients
|
||||
constructor {port} {
|
||||
set server [socket -server [\fBcallback\fR Accept] $port]
|
||||
set clients {}
|
||||
}
|
||||
destructor {
|
||||
chan close $server
|
||||
foreach client [dict keys $clients] {
|
||||
chan close $client
|
||||
}
|
||||
}
|
||||
|
||||
method Accept {channel clientAddress clientPort} {
|
||||
dict set clients $channel [dict create \e
|
||||
address $clientAddress port $clientPort]
|
||||
chan event $channel readable [\fBcallback\fR Receive $channel]
|
||||
}
|
||||
method Receive {channel} {
|
||||
if {[chan gets $channel line] >= 0} {
|
||||
my echo $channel $line
|
||||
} else {
|
||||
chan close $channel
|
||||
dict unset clients $channel
|
||||
}
|
||||
}
|
||||
|
||||
method echo {channel line} {
|
||||
dict with clients $channel {
|
||||
chan puts $channel \e
|
||||
[format {[%s:%d] %s} $address $port $line]
|
||||
}
|
||||
}
|
||||
}
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
chan(n), fileevent(n), my(n), self(n), socket(n), trace(n)
|
||||
.SH KEYWORDS
|
||||
callback, object
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
@@ -41,7 +41,3 @@ current one:
|
||||
filename(n), glob(n), pwd(n)
|
||||
.SH KEYWORDS
|
||||
working directory
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2011-2015 Andreas Kupries
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH classvariable n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
classvariable \- create link from local variable to variable in class
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBclassvariable\fR \fIvariableName\fR ?\fI...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
The \fBclassvariable\fR command is available within methods. It takes a series
|
||||
of one or more variable names and makes them available in the method's scope;
|
||||
those variable names must not be qualified and must not refer to array
|
||||
elements. The originating scope for the variables is the namespace of the
|
||||
class that the method was defined by. In other words, the referenced variables
|
||||
are shared between all instances of that class.
|
||||
.PP
|
||||
Note: This command is equivalent to the command \fBtypevariable\fR provided by
|
||||
the snit package in tcllib for approximately the same purpose. If used in a
|
||||
method defined directly on a class instance (e.g., through the
|
||||
\fBoo::objdefine\fR \fBmethod\fR definition) this is very much like just
|
||||
using:
|
||||
.PP
|
||||
.CS
|
||||
namespace upvar [namespace current] $var $var
|
||||
.CE
|
||||
.PP
|
||||
for each variable listed to \fBclassvariable\fR.
|
||||
.SH EXAMPLE
|
||||
This class counts how many instances of it have been made.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create Counted {
|
||||
initialise {
|
||||
variable count 0
|
||||
}
|
||||
|
||||
variable number
|
||||
constructor {} {
|
||||
\fBclassvariable\fR count
|
||||
set number [incr count]
|
||||
}
|
||||
|
||||
method report {} {
|
||||
\fBclassvariable\fR count
|
||||
puts "This is instance $number of $count"
|
||||
}
|
||||
}
|
||||
|
||||
set a [Counted new]
|
||||
set b [Counted new]
|
||||
$a report
|
||||
\fI\(-> This is instance 1 of 2\fR
|
||||
set c [Counted new]
|
||||
$b report
|
||||
\fI\(-> This is instance 2 of 3\fR
|
||||
$c report
|
||||
\fI\(-> This is instance 3 of 3\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
global(n), namespace(n), oo::class(n), oo::define(n), upvar(n), variable(n)
|
||||
.SH KEYWORDS
|
||||
class, class variable, variable
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
+10
-29
@@ -452,19 +452,6 @@ If this situation occurs, the first occurrence of the time is chosen.
|
||||
(For this reason, it is wise to have the input string contain the
|
||||
time zone when converting local times. This caveat does not apply to
|
||||
UTC times.)
|
||||
.PP
|
||||
If the interpretation of the groups yields an impossible time because
|
||||
a field is out of range, enough of that field's unit will be added to
|
||||
or subtracted from the time to bring it in range. Thus, if attempting to
|
||||
scan or format day 0 of the month, one day will be subtracted from day
|
||||
1 of the month, yielding the last day of the previous month.
|
||||
.PP
|
||||
If the interpretation of the groups yields an impossible time because
|
||||
a Daylight Saving Time change skips over that time, or an ambiguous
|
||||
time because a Daylight Saving Time change skips back so that the clock
|
||||
observes the given time twice, and no time zone specifier (\fB%z\fR
|
||||
or \fB%Z\fR) is present in the format, the time is interpreted as
|
||||
if the clock had not changed.
|
||||
.SH "FORMAT GROUPS"
|
||||
.PP
|
||||
The following format groups are recognized by the \fBclock scan\fR and
|
||||
@@ -886,46 +873,40 @@ The \fIinputString\fR argument consists of zero or more specifications of the
|
||||
following form:
|
||||
.TP
|
||||
\fItime\fR
|
||||
.
|
||||
A time of day, which is of the form:
|
||||
.QW "\fIhh\fR?\fB:\fImm\fR?\fB:\fIss\fR?? ?\fImeridian\fR? ?\fIzone\fR?"
|
||||
or
|
||||
.QW "\fBhhmm \fR?\fBmeridian\fR? ?\fBzone\fR?" .
|
||||
If no \fImeridian\fR is specified, \fIhh\fR is interpreted on
|
||||
A time of day, which is of the form: \fBhh?:mm?:ss?? ?meridian? ?zone?\fR
|
||||
or \fBhhmm ?meridian? ?zone?\fR
|
||||
If no meridian is specified, \fBhh\fR is interpreted on
|
||||
a 24-hour clock.
|
||||
.TP
|
||||
\fIdate\fR
|
||||
.
|
||||
A specific month and day with optional year. The
|
||||
acceptable formats are
|
||||
.QW "\fImm\fB/\fIdd\fR?\fB/\fIyy\fR?" ,
|
||||
.QW "\fImonthname dd\fR?\fB, \fIyy\fR?" ,
|
||||
.QW "\fIday\fB, \fIdd monthname \fR?\fIyy\fR?" ,
|
||||
.QW "\fIdd monthname yy\fR" ,
|
||||
.QW "?\fICC\fR?\fIyymmdd\fR" ,
|
||||
.QW "\fBmm/dd\fR?\fB/yy\fR?" ,
|
||||
.QW "\fBmonthname dd\fR?\fB, yy\fR?" ,
|
||||
.QW "\fBday, dd monthname \fR?\fByy\fR?" ,
|
||||
.QW "\fBdd monthname yy\fR" ,
|
||||
.QW "?\fBCC\fR?\fByymmdd\fR" ,
|
||||
and
|
||||
.QW "\fIdd\fB-\fImonthname\fB-\fR?\fICC\fR?\fIyy\fR" .
|
||||
.QW "\fBdd-monthname-\fR?\fBCC\fR?\fByy\fR" .
|
||||
The default year is the current year. If the year is less
|
||||
than 100, we treat the years 00-68 as 2000-2068 and the years 69-99
|
||||
as 1969-1999. Not all platforms can represent the years 38-70, so
|
||||
an error may result if these years are used.
|
||||
.TP
|
||||
\fIISO 8601 point-in-time\fR
|
||||
.
|
||||
An ISO 8601 point-in-time specification, such as
|
||||
.QW \fICCyymmdd\fBT\fIhhmmss\fR,
|
||||
where \fBT\fR is the literal
|
||||
.QW T ,
|
||||
.QW "\fICCyymmdd hhmmss\fR" ,
|
||||
or
|
||||
.QW \fICCyymmdd\fBT\fIhh\fB:\fImm\fB:\fIss\fR .
|
||||
.QW \fICCyymmdd\fBT\fIhh:mm:ss\fR .
|
||||
Note that only these three formats are accepted.
|
||||
The command does \fInot\fR accept the full range of point-in-time
|
||||
specifications specified in ISO8601. Other formats can be recognized by
|
||||
giving an explicit \fB\-format\fR option to the \fBclock scan\fR command.
|
||||
.TP
|
||||
\fIrelative time\fR
|
||||
.
|
||||
A specification relative to the current time. The format is \fBnumber
|
||||
unit\fR. Acceptable units are \fByear\fR, \fBfortnight\fR,
|
||||
\fBmonth\fR, \fBweek\fR, \fBday\fR,
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ exception to occur.
|
||||
The exception causes the current script to be aborted
|
||||
out to the innermost containing loop command, which then
|
||||
continues with the next iteration of the loop.
|
||||
Continue exceptions are also handled in a few other situations, such
|
||||
Catch exceptions are also handled in a few other situations, such
|
||||
as the \fBcatch\fR command and the outermost scripts of procedure
|
||||
bodies.
|
||||
.SH EXAMPLE
|
||||
|
||||
-217
@@ -1,217 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2014-2018 Donal K. Fellows.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH "cookiejar" n 0.1 http "Tcl Bundled Packages"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
cookiejar \- Implementation of the Tcl http package cookie jar protocol
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fBpackage require\fR \fBcookiejar\fR ?\fB0.1\fR?
|
||||
|
||||
\fB::http::cookiejar configure\fR ?\fIoptionName\fR? ?\fIoptionValue\fR?
|
||||
\fB::http::cookiejar create\fR \fIname\fR ?\fIfilename\fR?
|
||||
\fB::http::cookiejar new\fR ?\fIfilename\fR?
|
||||
|
||||
\fIcookiejar\fR \fBdestroy\fR
|
||||
\fIcookiejar\fR \fBforceLoadDomainData\fR
|
||||
\fIcookiejar\fR \fBgetCookies\fR \fIprotocol host path\fR
|
||||
\fIcookiejar\fR \fBstoreCookie\fR \fIoptions\fR
|
||||
\fIcookiejar\fR \fBlookup\fR ?\fIhost\fR? ?\fIkey\fR?
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The cookiejar package provides an implementation of the http package's cookie
|
||||
jar protocol using an SQLite database. It provides one main command,
|
||||
\fB::http::cookiejar\fR, which is a TclOO class that should be instantiated to
|
||||
create a cookie jar that manages a particular HTTP session.
|
||||
.PP
|
||||
The database management policy can be controlled at the package level by the
|
||||
\fBconfigure\fR method on the \fB::http::cookiejar\fR class object:
|
||||
.TP
|
||||
\fB::http::cookiejar configure\fR ?\fIoptionName\fR? ?\fIoptionValue\fR?
|
||||
.
|
||||
If neither \fIoptionName\fR nor \fIoptionValue\fR are supplied, this returns a
|
||||
copy of the configuration as a Tcl dictionary. If just \fIoptionName\fR is
|
||||
supplied, just the value of the named option is returned. If both
|
||||
\fIoptionName\fR and \fIoptionValue\fR are given, the named option is changed
|
||||
to be the given value.
|
||||
.RS
|
||||
.PP
|
||||
Supported options are:
|
||||
.TP
|
||||
\fB\-domainfile \fIfilename\fR
|
||||
.
|
||||
A file (defaulting to within the cookiejar package) with a description of the
|
||||
list of top-level domains (e.g., \fB.com\fR or \fB.co.jp\fR). Such domains
|
||||
\fImust not\fR accept cookies set upon them. Note that the list of such
|
||||
domains is both security-sensitive and \fInot\fR constant and should be
|
||||
periodically refetched. Cookie jars maintain their own cache of the domain
|
||||
list.
|
||||
.TP
|
||||
\fB\-domainlist \fIurl\fR
|
||||
.
|
||||
A URL to fetch the list of top-level domains (e.g., \fB.com\fR or
|
||||
\fB.co.jp\fR) from. Such domains \fImust not\fR accept cookies set upon
|
||||
them. Note that the list of such domains is both security-sensitive and
|
||||
\fInot\fR constant and should be periodically refetched. Cookie jars maintain
|
||||
their own cache of the domain list.
|
||||
.TP
|
||||
\fB\-domainrefresh \fIintervalMilliseconds\fR
|
||||
.
|
||||
The number of milliseconds between checks of the \fI\-domainlist\fR for new
|
||||
domains.
|
||||
.TP
|
||||
\fB\-loglevel \fIlevel\fR
|
||||
.
|
||||
The logging level of this package. The logging level must be (in order of
|
||||
decreasing verbosity) one of \fBdebug\fR, \fBinfo\fR, \fBwarn\fR, or
|
||||
\fBerror\fR.
|
||||
.TP
|
||||
\fB\-offline \fIflag\fR
|
||||
.
|
||||
Allows the cookie managment engine to be placed into offline mode. In offline
|
||||
mode, the list of domains is read immediately from the file configured in the
|
||||
\fB\-domainfile\fR option, and the \fB\-domainlist\fR option is not used; it
|
||||
also makes the \fB\-domainrefresh\fR option be effectively ignored.
|
||||
.TP
|
||||
\fB\-purgeold \fIintervalMilliseconds\fR
|
||||
.
|
||||
The number of milliseconds between checks of the database for expired
|
||||
cookies; expired cookies are deleted.
|
||||
.TP
|
||||
\fB\-retain \fIcookieCount\fR
|
||||
.
|
||||
The maximum number of cookies to retain in the database.
|
||||
.TP
|
||||
\fB\-vacuumtrigger \fIdeletionCount\fR
|
||||
.
|
||||
A count of the number of persistent cookie deletions to go between vacuuming
|
||||
the database.
|
||||
.RE
|
||||
.PP
|
||||
Cookie jar instances may be made with any of the standard TclOO instance
|
||||
creation methods (\fBcreate\fR or \fBnew\fR).
|
||||
.TP
|
||||
\fB::http::cookiejar new\fR ?\fIfilename\fR?
|
||||
.
|
||||
If a \fIfilename\fR argument is provided, it is the name of a file containing
|
||||
an SQLite database that will contain the persistent cookies maintained by the
|
||||
cookie jar; the database will be created if the file does not already
|
||||
exist. If \fIfilename\fR is not supplied, the database will be held entirely within
|
||||
memory, which effectively forces all cookies within it to be session cookies.
|
||||
.SS "INSTANCE METHODS"
|
||||
.PP
|
||||
The following methods are supported on the instances:
|
||||
.TP
|
||||
\fIcookiejar\fR \fBdestroy\fR
|
||||
.
|
||||
This is the standard TclOO destruction method. It does \fInot\fR delete the
|
||||
SQLite database if it is written to disk. Callers are responsible for ensuring
|
||||
that the cookie jar is not in use by the http package at the time of
|
||||
destruction.
|
||||
.TP
|
||||
\fIcookiejar\fR \fBforceLoadDomainData\fR
|
||||
.
|
||||
This method causes the cookie jar to immediately load (and cache) the domain
|
||||
list data. The domain list will be loaded from the \fB\-domainlist\fR
|
||||
configured a the package level if that is enabled, and otherwise will be
|
||||
obtained from the \fB\-domainfile\fR configured at the package level.
|
||||
.TP
|
||||
\fIcookiejar\fR \fBgetCookies\fR \fIprotocol host path\fR
|
||||
.
|
||||
This method obtains the cookies for a particular HTTP request. \fIThis
|
||||
implements the http cookie jar protocol.\fR
|
||||
.TP
|
||||
\fIcookiejar\fR \fBpolicyAllow\fR \fIoperation domain path\fR
|
||||
.
|
||||
This method is called by the \fBstoreCookie\fR method to get a decision on
|
||||
whether to allow \fIoperation\fR to be performed for the \fIdomain\fR and
|
||||
\fIpath\fR. This is checked immediately before the database is updated but
|
||||
after the built-in security checks are done, and should return a boolean
|
||||
value; if the value is false, the operation is rejected and the database is
|
||||
not modified. The supported \fIoperation\fRs are:
|
||||
.RS
|
||||
.TP
|
||||
\fBdelete\fR
|
||||
.
|
||||
The \fIdomain\fR is seeking to delete a cookie.
|
||||
.TP
|
||||
\fBsession\fR
|
||||
.
|
||||
The \fIdomain\fR is seeking to create or update a session cookie.
|
||||
.TP
|
||||
\fBset\fR
|
||||
.
|
||||
The \fIdomain\fR is seeking to create or update a persistent cookie (with a
|
||||
defined lifetime).
|
||||
.PP
|
||||
The default implementation of this method just returns true, but subclasses of
|
||||
this class may impose their own rules.
|
||||
.RE
|
||||
.TP
|
||||
\fIcookiejar\fR \fBstoreCookie\fR \fIoptions\fR
|
||||
.
|
||||
This method stores a single cookie from a particular HTTP response. Cookies
|
||||
that fail security checks are ignored. \fIThis implements the http cookie jar
|
||||
protocol.\fR
|
||||
.TP
|
||||
\fIcookiejar\fR \fBlookup\fR ?\fIhost\fR? ?\fIkey\fR?
|
||||
.
|
||||
This method looks a cookie by exact host (or domain) matching. If neither
|
||||
\fIhost\fR nor \fIkey\fR are supplied, the list of hosts for which a cookie is
|
||||
stored is returned. If just \fIhost\fR (which may be a hostname or a domain
|
||||
name) is supplied, the list of cookie keys stored for that host is returned.
|
||||
If both \fIhost\fR and \fIkey\fR are supplied, the value for that key is
|
||||
returned; it is an error if no such host or key match exactly.
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
The simplest way of using a cookie jar is to just permanently configure it at
|
||||
the start of the application.
|
||||
.PP
|
||||
.CS
|
||||
package require http
|
||||
\fBpackage require cookiejar\fR
|
||||
|
||||
set cookiedb ~/.tclcookies.db
|
||||
http::configure -cookiejar [\fBhttp::cookiejar new\fR $cookiedb]
|
||||
|
||||
# No further explicit steps are required to use cookies
|
||||
set tok [http::geturl http://core.tcl.tk/]
|
||||
.CE
|
||||
.PP
|
||||
To only allow a particular domain to use cookies, perhaps because you only
|
||||
want to enable a particular host to create and manipulate sessions, create a
|
||||
subclass that imposes that policy.
|
||||
.PP
|
||||
.CS
|
||||
package require http
|
||||
\fBpackage require cookiejar\fR
|
||||
|
||||
oo::class create MyCookieJar {
|
||||
superclass \fBhttp::cookiejar\fR
|
||||
|
||||
method \fBpolicyAllow\fR {operation domain path} {
|
||||
return [expr {$domain eq "my.example.com"}]
|
||||
}
|
||||
}
|
||||
|
||||
set cookiedb ~/.tclcookies.db
|
||||
http::configure -cookiejar [MyCookieJar new $cookiedb]
|
||||
|
||||
# No further explicit steps are required to use cookies
|
||||
set tok [http::geturl http://core.tcl.tk/]
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
http(n), oo::class(n), sqlite3(n)
|
||||
.SH KEYWORDS
|
||||
cookie, internet, security policy, www
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
+6
-16
@@ -14,7 +14,7 @@ oo::copy \- create copies of objects and classes
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBoo::copy\fI sourceObject \fR?\fItargetObject\fR? ?\fItargetNamespace\fR?
|
||||
\fBoo::copy\fI sourceObject \fR?\fItargetObject\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
@@ -22,21 +22,11 @@ package require TclOO
|
||||
The \fBoo::copy\fR command creates a copy of an object or class. It takes the
|
||||
name of the object or class to be copied, \fIsourceObject\fR, and optionally
|
||||
the name of the object or class to create, \fItargetObject\fR, which will be
|
||||
resolved relative to the current namespace if not an absolute qualified name
|
||||
and
|
||||
.VS TIP473
|
||||
\fItargetNamespace\fR which is the name of the namespace that will hold the
|
||||
internal state of the object (\fBmy\fR command, etc.); it \fImust not\fR
|
||||
refer to an existing namespace.
|
||||
If either \fItargetObject\fR or \fItargetNamespace\fR is omitted or is given
|
||||
as the empty string, a new name is chosen. Names, unless specified, are
|
||||
chosen with the same algorithm used by the \fBnew\fR method of
|
||||
\fBoo::class\fR.
|
||||
.VE TIP473
|
||||
The copied object will be of the same class as the source object, and will have
|
||||
all its per-object methods copied. If it is a class, it will also have all the
|
||||
class methods in the class copied, but it will not have any of its instances
|
||||
copied.
|
||||
resolved relative to the current namespace if not an absolute qualified name.
|
||||
If \fItargetObject\fR is omitted, a new name is chosen. The copied object will
|
||||
be of the same class as the source object, and will have all its per-object
|
||||
methods copied. If it is a class, it will also have all the class methods in
|
||||
the class copied, but it will not have any of its instances copied.
|
||||
.PP
|
||||
.VS
|
||||
After the \fItargetObject\fR has been created and all definitions of its
|
||||
|
||||
+129
-508
@@ -1,5 +1,5 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2007-2018 Donal K. Fellows
|
||||
'\" Copyright (c) 2007 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -34,36 +34,11 @@ either the \fIdefScript\fR argument or by the \fIsubcommand\fR and following
|
||||
\fIarg\fR arguments; when the second is present, it is exactly as if all the
|
||||
arguments from \fIsubcommand\fR onwards are made into a list and that list is
|
||||
used as the \fIdefScript\fR argument.
|
||||
.PP
|
||||
Note that the constructor for \fBoo::class\fR will call \fBoo::define\fR on
|
||||
the script argument that it is provided. This is a convenient way to create
|
||||
and define a class in one step.
|
||||
.SH "CONFIGURING CLASSES"
|
||||
.SS "CONFIGURING CLASSES"
|
||||
.PP
|
||||
The following commands are supported in the \fIdefScript\fR for
|
||||
\fBoo::define\fR, each of which may also be used in the \fIsubcommand\fR form:
|
||||
.TP
|
||||
\fBclassmethod\fI name\fR ?\fIargList bodyScrip\fR?
|
||||
.VS TIP478
|
||||
This creates a class method, or (if \fIargList\fR and \fIbodyScript\fR are
|
||||
omitted) promotes an existing method on the class object to be a class
|
||||
method. The \fIname\fR, \fIargList\fR and \fIbodyScript\fR arguments are as in
|
||||
the \fBmethod\fR definition, below.
|
||||
.RS
|
||||
.PP
|
||||
Class methods can be called on either the class itself or on the instances of
|
||||
that class. When they are called, the current object (see the \fBsel\fR and
|
||||
\fBmy\fR commands) is the class on which they are called or the class of the
|
||||
instance on which they are called, depending on whether they are called on the
|
||||
class or an instance of the class, respectively. If called on a subclass or
|
||||
instance of the subclass, the current object is the subclass.
|
||||
.PP
|
||||
In a private definition context, the methods as invoked on classes are
|
||||
\fInot\fR private, but the methods as invoked on instances of classes are
|
||||
private.
|
||||
.RE
|
||||
.VE TIP478
|
||||
.TP
|
||||
\fBconstructor\fI argList bodyScript\fR
|
||||
.
|
||||
This creates or updates the constructor for a class. The formal arguments to
|
||||
@@ -74,11 +49,13 @@ namespace of the constructor will be a namespace that is unique to the object
|
||||
being constructed. Within the constructor, the \fBnext\fR command should be
|
||||
used to call the superclasses' constructors. If \fIbodyScript\fR is the empty
|
||||
string, the constructor will be deleted.
|
||||
.RS
|
||||
.PP
|
||||
Classes do not need to have a constructor defined. If none is specified, the
|
||||
superclass's constructor will be used instead.
|
||||
.RE
|
||||
.TP
|
||||
\fBdeletemethod\fI name\fR ?\fIname ...\fR
|
||||
.
|
||||
This deletes each of the methods called \fIname\fR from a class. The methods
|
||||
must have previously existed in that class. Does not affect the superclasses
|
||||
of the class, nor does it affect the subclasses or instances of the class
|
||||
(except when they have a call chain through the class being modified).
|
||||
.TP
|
||||
\fBdestructor\fI bodyScript\fR
|
||||
.
|
||||
@@ -104,6 +81,19 @@ class being defined. Note that the methods themselves may be actually defined
|
||||
by a superclass; subclass exports override superclass visibility, and may in
|
||||
turn be overridden by instances.
|
||||
.TP
|
||||
\fBfilter\fR ?\fI\-slotOperation\fR? ?\fImethodName ...\fR?
|
||||
.VS
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates the list of method names that are used to guard whether
|
||||
method call to instances of the class may be called and what the method's
|
||||
results are. Each \fImethodName\fR names a single filtering method (which may
|
||||
be exposed or not exposed); it is not an error for a non-existent method to be
|
||||
named since they may be defined by subclasses.
|
||||
.VS
|
||||
By default, this slot works by appending.
|
||||
.VE
|
||||
.TP
|
||||
\fBforward\fI name cmdName \fR?\fIarg ...\fR?
|
||||
.
|
||||
This creates or updates a forwarded method called \fIname\fR. The method is
|
||||
@@ -115,24 +105,8 @@ fully-qualified, the command will be searched for in each object's namespace,
|
||||
using the instances' namespace's path, or by looking in the global namespace.
|
||||
The method will be exported if \fIname\fR starts with a lower-case letter, and
|
||||
non-exported otherwise.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this command creates private forwarded methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBinitialise\fI script\fR
|
||||
.TP
|
||||
\fBinitialize\fI script\fR
|
||||
.VS TIP478
|
||||
This evaluates \fIscript\fR in a context which supports local variables and
|
||||
where the current namespace is the instance namespace of the class object
|
||||
itself. This is useful for setting up, e.g., class-scoped variables.
|
||||
.VE TIP478
|
||||
.TP
|
||||
\fBmethod\fI name \fR?\fIoption\fR? \fIargList bodyScript\fR
|
||||
\fBmethod\fI name argList bodyScript\fR
|
||||
.
|
||||
This creates or updates a method that is implemented as a procedure-like
|
||||
script. The name of the method is \fIname\fR, the formal arguments to the
|
||||
@@ -142,44 +116,32 @@ the body of the method is evaluated, the current namespace of the method will
|
||||
be a namespace that is unique to the current object. The method will be
|
||||
exported if \fIname\fR starts with a lower-case letter, and non-exported
|
||||
otherwise; this behavior can be overridden via \fBexport\fR and
|
||||
\fBunexport\fR
|
||||
.VS TIP519
|
||||
or by specifying \fB\-export\fR, \fB\-private\fR or \fB\-unexport\fR in the
|
||||
optional parameter \fIoption\fR.
|
||||
.VE TIP519
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below) or if the \fB\-private\fR flag is given for \fIoption\fR, this command
|
||||
creates private procedure-like methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
\fBunexport\fR.
|
||||
.TP
|
||||
\fBprivate \fIcmd arg...\fR
|
||||
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.VS
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates the list of additional classes that are to be mixed into
|
||||
all the instances of the class being defined. Each \fIclassName\fR argument
|
||||
names a single class that is to be mixed in.
|
||||
.VS
|
||||
By default, this slot works by replacement.
|
||||
.VE
|
||||
.TP
|
||||
\fBprivate \fIscript\fR
|
||||
\fBrenamemethod\fI fromName toName\fR
|
||||
.
|
||||
.VS TIP500
|
||||
This evaluates the \fIscript\fR (or the list of command and arguments given by
|
||||
\fIcmd\fR and \fIarg\fRs) in a context where the definitions made on the
|
||||
current class will be private definitions.
|
||||
.RS
|
||||
.PP
|
||||
The following class definition commands are affected by \fBprivate\fR:
|
||||
\fBforward\fR, \fBmethod\fR, \fBself\fR, and \fBvariable\fR. Nesting
|
||||
\fBprivate\fR inside \fBprivate\fR has no cumulative effect; the innermost
|
||||
definition context is just a private definition context. All other definition
|
||||
commands have no difference in behavior when used in a private definition
|
||||
context.
|
||||
.RE
|
||||
.VE TIP500
|
||||
This renames the method called \fIfromName\fR in a class to \fItoName\fR. The
|
||||
method must have previously existed in the class, and \fItoName\fR must not
|
||||
previously refer to a method in that class. Does not affect the superclasses
|
||||
of the class, nor does it affect the subclasses or instances of the class
|
||||
(except when they have a call chain through the class being modified). Does
|
||||
not change the export status of the method; if it was exported before, it will
|
||||
be afterwards.
|
||||
.TP
|
||||
\fBself\fI subcommand arg ...\fR
|
||||
.TP
|
||||
\fBself\fI script\fR
|
||||
.TP
|
||||
\fBself\fR
|
||||
.
|
||||
This command is equivalent to calling \fBoo::objdefine\fR on the class being
|
||||
defined (see \fBCONFIGURING OBJECTS\fR below for a description of the
|
||||
@@ -189,29 +151,20 @@ and
|
||||
.QW "\fBoo::define \fIcls \fBself \fIsubcommand ...\fR"
|
||||
operates identically to
|
||||
.QW "\fBoo::objdefine \fIcls subcommand ...\fR" .
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP470
|
||||
If no arguments at all are used, this gives the name of the class currently
|
||||
being configured.
|
||||
.VE TIP470
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), the definitions on the class object will also be made in a private
|
||||
definition context.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBsuperclass\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.
|
||||
.VS
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
allows the alteration of the superclasses of the class being defined.
|
||||
Each \fIclassName\fR argument names one class that is to be a superclass of
|
||||
the defined class. Note that objects must not be changed from being classes to
|
||||
being non-classes or vice-versa, that an empty parent class is equivalent to
|
||||
\fBoo::object\fR, and that the parent classes of \fBoo::object\fR and
|
||||
\fBoo::class\fR may not be modified.
|
||||
.VS
|
||||
By default, this slot works by replacement.
|
||||
.VE
|
||||
.TP
|
||||
\fBunexport\fI name \fR?\fIname ...\fR?
|
||||
.
|
||||
@@ -223,212 +176,24 @@ actually defined by a superclass; subclass unexports override superclass
|
||||
visibility, and may be overridden by instance unexports.
|
||||
.TP
|
||||
\fBvariable\fR ?\fI\-slotOperation\fR? ?\fIname ...\fR?
|
||||
.
|
||||
.VS
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below) arranges for each of the named
|
||||
variables to be automatically made
|
||||
available in the methods, constructor and destructor declared by the class
|
||||
being defined. Each variable name must not have any namespace
|
||||
separators and must not look like an array access. All variables will be
|
||||
actually present in the namespace of the instance object on which the method
|
||||
is executed. Note
|
||||
actually present in the instance object on which the method is executed. Note
|
||||
that the variable lists declared by a superclass or subclass are completely
|
||||
disjoint, as are variable lists declared by instances; the list of variable
|
||||
names is just for methods (and constructors and destructors) declared by this
|
||||
class. By default, this slot works by appending.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this slot manipulates the list of private variable bindings for this
|
||||
class. In a private variable binding, the name of the variable within the
|
||||
instance object is different to the name given in the definition; the name
|
||||
used in the definition is the name that you use to access the variable within
|
||||
the methods of this class, and the name of the variable in the instance
|
||||
namespace has a unique prefix that makes accidental use from other classes
|
||||
extremely unlikely.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.SS "ADVANCED CLASS CONFIGURATION OPTIONS"
|
||||
.PP
|
||||
The following definitions are also supported, but are not required in simple
|
||||
programs:
|
||||
.TP
|
||||
\fBdefinitionnamespace\fR ?\fIkind\fR? \fInamespaceName\fR
|
||||
.VS TIP524
|
||||
This allows control over what namespace will be used by the \fBoo::define\fR
|
||||
and \fBoo::objdefine\fR commands to look up the definition commands they
|
||||
use. When any object has a definition operation applied to it, \fIthe class that
|
||||
it is an instance of\fR (and its superclasses and mixins) is consulted for
|
||||
what definition namespace to use. \fBoo::define\fR gets the class definition
|
||||
namespace, and \fB::oo::objdefine\fR gets the instance definition namespace,
|
||||
but both otherwise use the identical lookup operation.
|
||||
.RS
|
||||
.PP
|
||||
This sets the definition namespace of kind \fIkind\fR provided by the current
|
||||
class to \fInamespaceName\fR. The \fInamespaceName\fR must refer to a
|
||||
currently existing namespace, or must be the empty string (to stop the current
|
||||
class from having such a namespace connected). The \fIkind\fR, if supplied,
|
||||
must be either \fB\-class\fR (the default) or \fB\-instance\fR to specify the
|
||||
whether the namespace for use with \fBoo::define\fR or \fBoo::objdefine\fR
|
||||
respectively is being set.
|
||||
.PP
|
||||
The class \fBoo::object\fR has its instance namespace locked to
|
||||
\fB::oo::objdefine\fR, and the class \fBoo::class\fR has its class namespace
|
||||
locked to \fB::oo::define\fR. A consequence of this is that effective use of
|
||||
this feature for classes requires the definition of a metaclass.
|
||||
.RE
|
||||
.VE TIP524
|
||||
.TP
|
||||
\fBdeletemethod\fI name\fR ?\fIname ...\fR?
|
||||
.
|
||||
This deletes each of the methods called \fIname\fR from a class. The methods
|
||||
must have previously existed in that class. Does not affect the superclasses
|
||||
of the class, nor does it affect the subclasses or instances of the class
|
||||
(except when they have a call chain through the class being modified) or the
|
||||
class object itself.
|
||||
.TP
|
||||
\fBfilter\fR ?\fI\-slotOperation\fR? ?\fImethodName ...\fR?
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
sets or updates the list of method names that are used to guard whether
|
||||
method call to instances of the class may be called and what the method's
|
||||
results are. Each \fImethodName\fR names a single filtering method (which may
|
||||
be exposed or not exposed); it is not an error for a non-existent method to be
|
||||
named since they may be defined by subclasses.
|
||||
By default, this slot works by appending.
|
||||
.TP
|
||||
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
sets or updates the list of additional classes that are to be mixed into
|
||||
all the instances of the class being defined. Each \fIclassName\fR argument
|
||||
names a single class that is to be mixed in.
|
||||
By default, this slot works by replacement.
|
||||
.TP
|
||||
\fBrenamemethod\fI fromName toName\fR
|
||||
.
|
||||
This renames the method called \fIfromName\fR in a class to \fItoName\fR. The
|
||||
method must have previously existed in the class, and \fItoName\fR must not
|
||||
previously refer to a method in that class. Does not affect the superclasses
|
||||
of the class, nor does it affect the subclasses or instances of the class
|
||||
(except when they have a call chain through the class being modified), or the
|
||||
class object itself. Does
|
||||
not change the export status of the method; if it was exported before, it will
|
||||
be afterwards.
|
||||
.SH "CONFIGURING OBJECTS"
|
||||
.VE
|
||||
.SS "CONFIGURING OBJECTS"
|
||||
.PP
|
||||
The following commands are supported in the \fIdefScript\fR for
|
||||
\fBoo::objdefine\fR, each of which may also be used in the \fIsubcommand\fR
|
||||
form:
|
||||
.TP
|
||||
\fBexport\fI name \fR?\fIname ...\fR?
|
||||
.
|
||||
This arranges for each of the named methods, \fIname\fR, to be exported
|
||||
(i.e. usable outside the object through the object's command) by the object
|
||||
being defined. Note that the methods themselves may be actually defined by a
|
||||
class or superclass; object exports override class visibility.
|
||||
.TP
|
||||
\fBforward\fI name cmdName \fR?\fIarg ...\fR?
|
||||
.
|
||||
This creates or updates a forwarded object method called \fIname\fR. The
|
||||
method is defined be forwarded to the command called \fIcmdName\fR, with
|
||||
additional arguments, \fIarg\fR etc., added before those arguments specified
|
||||
by the caller of the method. Forwarded methods should be deleted using the
|
||||
\fBmethod\fR subcommand. The method will be exported if \fIname\fR starts with
|
||||
a lower-case letter, and non-exported otherwise.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this command creates private forwarded methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBmethod\fI name \fR?\fIoption\fR? \fIargList bodyScript\fR
|
||||
.
|
||||
This creates, updates or deletes an object method. The name of the method is
|
||||
\fIname\fR, the formal arguments to the method (defined using the same format
|
||||
as for the Tcl \fBproc\fR command) will be \fIargList\fR, and the body of the
|
||||
method will be \fIbodyScript\fR. When the body of the method is evaluated, the
|
||||
current namespace of the method will be a namespace that is unique to the
|
||||
object. The method will be exported if \fIname\fR starts with a lower-case
|
||||
letter, and non-exported otherwise;
|
||||
.VS TIP519
|
||||
this can be overridden by specifying \fB\-export\fR, \fB\-private\fR or
|
||||
\fB\-unexport\fR in the optional parameter \fIoption\fR, or via the
|
||||
\fBexport\fR and \fBunexport\fR definitions.
|
||||
.VE TIP519
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below) or if the \fB\-private\fR flag is given for \fIoption\fR, this command
|
||||
creates private procedure-like methods.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.TP
|
||||
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
sets or updates a per-object list of additional classes that are to be
|
||||
mixed into the object. Each argument, \fIclassName\fR, names a single class
|
||||
that is to be mixed in.
|
||||
By default, this slot works by replacement.
|
||||
.TP
|
||||
\fBprivate \fIcmd arg...\fR
|
||||
.TP
|
||||
\fBprivate \fIscript\fR
|
||||
.VS TIP500
|
||||
This evaluates the \fIscript\fR (or the list of command and arguments given by
|
||||
\fIcmd\fR and \fIarg\fRs) in a context where the definitions made on the
|
||||
current object will be private definitions.
|
||||
.RS
|
||||
.PP
|
||||
The following class definition commands are affected by \fBprivate\fR:
|
||||
\fBforward\fR, \fBmethod\fR, and \fBvariable\fR. Nesting \fBprivate\fR inside
|
||||
\fBprivate\fR has no cumulative effect; the innermost definition context is
|
||||
just a private definition context. All other definition commands have no
|
||||
difference in behavior when used in a private definition context.
|
||||
.RE
|
||||
.VE TIP500
|
||||
.TP
|
||||
\fBunexport\fI name \fR?\fIname ...\fR?
|
||||
.
|
||||
This arranges for each of the named methods, \fIname\fR, to be not exported
|
||||
(i.e. not usable outside the object through the object's command, but instead
|
||||
just through the \fBmy\fR command visible in the object's context) by the
|
||||
object being defined. Note that the methods themselves may be actually defined
|
||||
by a class; instance unexports override class visibility.
|
||||
.TP
|
||||
\fBvariable\fR ?\fI\-slotOperation\fR? ?\fIname ...\fR?
|
||||
.
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below) arranges for each of the named
|
||||
variables to be automatically made available in the methods declared by the
|
||||
object being defined. Each variable name must not have any namespace
|
||||
separators and must not look like an array access. All variables will be
|
||||
actually present in the namespace of the object on which the method is
|
||||
executed. Note that the
|
||||
variable lists declared by the classes and mixins of which the object is an
|
||||
instance are completely disjoint; the list of variable names is just for
|
||||
methods declared by this object. By default, this slot works by appending.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP500
|
||||
If in a private definition context (see the \fBprivate\fR definition command,
|
||||
below), this slot manipulates the list of private variable bindings for this
|
||||
object. In a private variable binding, the name of the variable within the
|
||||
instance object is different to the name given in the definition; the name
|
||||
used in the definition is the name that you use to access the variable within
|
||||
the methods of this instance object, and the name of the variable in the
|
||||
instance namespace has a unique prefix that makes accidental use from
|
||||
superclass methods extremely unlikely.
|
||||
.VE TIP500
|
||||
.RE
|
||||
.SS "ADVANCED OBJECT CONFIGURATION OPTIONS"
|
||||
.PP
|
||||
The following definitions are also supported, but are not required in simple
|
||||
programs:
|
||||
.TP
|
||||
\fBclass\fI className\fR
|
||||
.
|
||||
This allows the class of an object to be changed after creation. Note that the
|
||||
@@ -438,77 +203,107 @@ well be in an inconsistent state unless additional configuration work is done.
|
||||
\fBdeletemethod\fI name\fR ?\fIname ...\fR
|
||||
.
|
||||
This deletes each of the methods called \fIname\fR from an object. The methods
|
||||
must have previously existed in that object (e.g., because it was created
|
||||
through \fBoo::objdefine method\fR). Does not affect the classes that the
|
||||
object is an instance of, or remove the exposure of those class-provided
|
||||
methods in the instance of that class.
|
||||
must have previously existed in that object. Does not affect the classes that
|
||||
the object is an instance of.
|
||||
.TP
|
||||
\fBexport\fI name \fR?\fIname ...\fR?
|
||||
.
|
||||
This arranges for each of the named methods, \fIname\fR, to be exported
|
||||
(i.e. usable outside the object through the object's command) by the object
|
||||
being defined. Note that the methods themselves may be actually defined by a
|
||||
class or superclass; object exports override class visibility.
|
||||
.TP
|
||||
\fBfilter\fR ?\fI\-slotOperation\fR? ?\fImethodName ...\fR?
|
||||
.
|
||||
.VS
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates the list of method names that are used to guard whether a
|
||||
method call to the object may be called and what the method's results are.
|
||||
Each \fImethodName\fR names a single filtering method (which may be exposed or
|
||||
not exposed); it is not an error for a non-existent method to be named. Note
|
||||
that the actual list of filters also depends on the filters set upon any
|
||||
classes that the object is an instance of.
|
||||
.VS
|
||||
By default, this slot works by appending.
|
||||
.VE
|
||||
.TP
|
||||
\fBforward\fI name cmdName \fR?\fIarg ...\fR?
|
||||
.
|
||||
This creates or updates a forwarded object method called \fIname\fR. The
|
||||
method is defined be forwarded to the command called \fIcmdName\fR, with
|
||||
additional arguments, \fIarg\fR etc., added before those arguments specified
|
||||
by the caller of the method. Forwarded methods should be deleted using the
|
||||
\fBmethod\fR subcommand. The method will be exported if \fIname\fR starts with
|
||||
a lower-case letter, and non-exported otherwise.
|
||||
.TP
|
||||
\fBmethod\fI name argList bodyScript\fR
|
||||
.
|
||||
This creates, updates or deletes an object method. The name of the method is
|
||||
\fIname\fR, the formal arguments to the method (defined using the same format
|
||||
as for the Tcl \fBproc\fR command) will be \fIargList\fR, and the body of the
|
||||
method will be \fIbodyScript\fR. When the body of the method is evaluated, the
|
||||
current namespace of the method will be a namespace that is unique to the
|
||||
object. The method will be exported if \fIname\fR starts with a lower-case
|
||||
letter, and non-exported otherwise.
|
||||
.TP
|
||||
\fBmixin\fR ?\fI\-slotOperation\fR? ?\fIclassName ...\fR?
|
||||
.VS
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below)
|
||||
.VE
|
||||
sets or updates a per-object list of additional classes that are to be
|
||||
mixed into the object. Each argument, \fIclassName\fR, names a single class
|
||||
that is to be mixed in.
|
||||
.VS
|
||||
By default, this slot works by replacement.
|
||||
.VE
|
||||
.TP
|
||||
\fBrenamemethod\fI fromName toName\fR
|
||||
.
|
||||
This renames the method called \fIfromName\fR in an object to \fItoName\fR.
|
||||
The method must have previously existed in the object, and \fItoName\fR must
|
||||
not previously refer to a method in that object. Does not affect the classes
|
||||
that the object is an instance of and cannot rename in an instance object the
|
||||
methods provided by those classes (though a \fBoo::objdefine forward\fRed
|
||||
method may provide an equivalent capability). Does not change the export
|
||||
status of the method; if it was exported before, it will be afterwards.
|
||||
that the object is an instance of. Does not change the export status of the
|
||||
method; if it was exported before, it will be afterwards.
|
||||
.TP
|
||||
\fBself \fR
|
||||
.VS TIP470
|
||||
This gives the name of the object currently being configured.
|
||||
.VE TIP470
|
||||
.SH "PRIVATE METHODS"
|
||||
.VS TIP500
|
||||
When a class or instance has a private method, that private method can only be
|
||||
invoked from within methods of that class or instance. Other callers of the
|
||||
object's methods \fIcannot\fR invoke private methods, it is as if the private
|
||||
methods do not exist. However, a private method of a class \fIcan\fR be
|
||||
invoked from the class's methods when those methods are being used on another
|
||||
instance object; this means that a class can use them to coordinate behaviour
|
||||
between several instances of itself without interfering with how other
|
||||
classes (especially either subclasses or superclasses) interact. Private
|
||||
methods precede all mixed in classes in the method call order (as reported by
|
||||
\fBself call\fR).
|
||||
.VE TIP500
|
||||
\fBunexport\fI name \fR?\fIname ...\fR?
|
||||
.
|
||||
This arranges for each of the named methods, \fIname\fR, to be not exported
|
||||
(i.e. not usable outside the object through the object's command, but instead
|
||||
just through the \fBmy\fR command visible in the object's context) by the
|
||||
object being defined. Note that the methods themselves may be actually defined
|
||||
by a class; instance unexports override class visibility.
|
||||
.TP
|
||||
\fBvariable\fR ?\fI\-slotOperation\fR? ?\fIname ...\fR?
|
||||
.VS
|
||||
This slot (see \fBSLOTTED DEFINITIONS\fR below) arranges for each of the named
|
||||
variables to be automatically made available in the methods declared by the
|
||||
object being defined. Each variable name must not have any namespace
|
||||
separators and must not look like an array access. All variables will be
|
||||
actually present in the object on which the method is executed. Note that the
|
||||
variable lists declared by the classes and mixins of which the object is an
|
||||
instance are completely disjoint; the list of variable names is just for
|
||||
methods declared by this object. By default, this slot works by appending.
|
||||
.SH "SLOTTED DEFINITIONS"
|
||||
Some of the configurable definitions of a class or object are \fIslotted
|
||||
definitions\fR. This means that the configuration is implemented by a slot
|
||||
object, that is an instance of the class \fBoo::Slot\fR, which manages a list
|
||||
of values (class names, variable names, etc.) that comprises the contents of
|
||||
the slot. The class defines five operations (as methods) that may be done on
|
||||
the slot. The class defines three operations (as methods) that may be done on
|
||||
the slot:
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fB\-append\fR ?\fImember ...\fR?
|
||||
.
|
||||
.VS
|
||||
This appends the given \fImember\fR elements to the slot definition.
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fB\-clear\fR
|
||||
.
|
||||
.VS
|
||||
This sets the slot definition to the empty list.
|
||||
.TP
|
||||
\fIslot\fR \fB\-prepend\fR ?\fImember ...\fR?
|
||||
.VS TIP516
|
||||
This prepends the given \fImember\fR elements to the slot definition.
|
||||
.VE TIP516
|
||||
.TP
|
||||
\fIslot\fR \fB\-remove\fR ?\fImember ...\fR?
|
||||
.VS TIP516
|
||||
This removes the given \fImember\fR elements from the slot definition.
|
||||
.VE TIP516
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fB\-set\fR ?\fImember ...\fR?
|
||||
.
|
||||
.VS
|
||||
This replaces the slot definition with the given \fImember\fR elements.
|
||||
.PP
|
||||
A consequence of this is that any use of a slot's default operation where the
|
||||
@@ -521,55 +316,20 @@ which is forwarded to the default operation of the slot (thus, for the class
|
||||
slot, this is forwarded to
|
||||
.QW "\fBmy \-append\fR" ),
|
||||
and these methods which provide the implementation interface:
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fBGet\fR
|
||||
.
|
||||
Returns a list that is the current contents of the slot, but does not modify
|
||||
the slot. This method must always be called from a stack frame created by a
|
||||
call to \fBoo::define\fR or \fBoo::objdefine\fR. This method \fIshould not\fR
|
||||
return an error unless it is called from outside a definition context or with
|
||||
the wrong number of arguments.
|
||||
.RS
|
||||
.PP
|
||||
.VS TIP516
|
||||
The elements of the list should be fully resolved, if that is a meaningful
|
||||
concept to the slot.
|
||||
.VE TIP516
|
||||
.RE
|
||||
.TP
|
||||
\fIslot\fR \fBResolve\fR \fIslotElement\fR
|
||||
.VS TIP516
|
||||
Returns \fIslotElement\fR with a resolution operation applied to it, but does
|
||||
not modify the slot. For slots of simple strings, this is an operation that
|
||||
does nothing, whereas for slots of classes, this maps a class name to its
|
||||
fully-qualified class name. This method must always be called from a stack
|
||||
frame created by a call to \fBoo::define\fR or \fBoo::objdefine\fR. This
|
||||
method \fIshould not\fR return an error unless it is called from outside a
|
||||
definition context or with the wrong number of arguments; unresolvable
|
||||
arguments should be returned as is (as not all slot operations strictly
|
||||
require that values are resolvable to work).
|
||||
.RS
|
||||
.PP
|
||||
Implementations \fIshould not\fR enforce uniqueness and ordering constraints
|
||||
in this method; that is the responsibility of the \fBSet\fR method.
|
||||
.RE
|
||||
.VE TIP516
|
||||
.VS
|
||||
Returns a list that is the current contents of the slot. This method must
|
||||
always be called from a stack frame created by a call to \fBoo::define\fR or
|
||||
\fBoo::objdefine\fR.
|
||||
.VE
|
||||
.TP
|
||||
\fIslot\fR \fBSet \fIelementList\fR
|
||||
.
|
||||
.VS
|
||||
Sets the contents of the slot to the list \fIelementList\fR and returns the
|
||||
empty string. This method must always be called from a stack frame created by
|
||||
a call to \fBoo::define\fR or \fBoo::objdefine\fR. This method may return an
|
||||
error if it rejects the change to the slot contents (e.g., because of invalid
|
||||
values) as well as if it is called from outside a definition context or with
|
||||
the wrong number of arguments.
|
||||
.RS
|
||||
.PP
|
||||
This method \fImay\fR reorder and filter the elements if this is necessary in
|
||||
order to satisfy the underlying constraints of the slot. (For example, slots
|
||||
of classes enforce a uniqueness constraint that places each element in the
|
||||
earliest location in the slot that it can.)
|
||||
.RE
|
||||
a call to \fBoo::define\fR or \fBoo::objdefine\fR.
|
||||
.PP
|
||||
The implementation of these methods is slot-dependent (and responsible for
|
||||
accessing the correct part of the class or object definition). Slots also have
|
||||
@@ -577,14 +337,7 @@ an unknown method handler to tie all these pieces together, and they hide
|
||||
their \fBdestroy\fR method so that it is not invoked inadvertently. It is
|
||||
\fIrecommended\fR that any user changes to the slot mechanism be restricted to
|
||||
defining new operations whose names start with a hyphen.
|
||||
.PP
|
||||
.VS TIP516
|
||||
Most slot operations will initially \fBResolve\fR their argument list, combine
|
||||
it with the results of the \fBGet\fR method, and then \fBSet\fR the result.
|
||||
Some operations omit one or both of the first two steps; omitting the third
|
||||
would result in an idempotent read-only operation (but the standard mechanism
|
||||
for reading from slots is via \fBinfo class\fR and \fBinfo object\fR).
|
||||
.VE TIP516
|
||||
.VE
|
||||
.SH EXAMPLES
|
||||
This example demonstrates how to use both forms of the \fBoo::define\fR and
|
||||
\fBoo::objdefine\fR commands (they work in the same way), as well as
|
||||
@@ -641,138 +394,6 @@ oo::class create B {
|
||||
inst m1 \fI\(-> prints "red brick"\fR
|
||||
inst m2 \fI\(-> prints "blue brick"\fR
|
||||
.CE
|
||||
.PP
|
||||
.VS TIP478
|
||||
This example shows how to create and use class variables. It is a class that
|
||||
counts how many instances of itself have been made.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create Counted
|
||||
\fBoo::define\fR Counted {
|
||||
\fBinitialise\fR {
|
||||
variable count 0
|
||||
}
|
||||
|
||||
\fBvariable\fR number
|
||||
\fBconstructor\fR {} {
|
||||
classvariable count
|
||||
set number [incr count]
|
||||
}
|
||||
|
||||
\fBmethod\fR report {} {
|
||||
classvariable count
|
||||
puts "This is instance $number of $count"
|
||||
}
|
||||
}
|
||||
|
||||
set a [Counted new]
|
||||
set b [Counted new]
|
||||
$a report
|
||||
\fI\(-> This is instance 1 of 2\fR
|
||||
set c [Counted new]
|
||||
$b report
|
||||
\fI\(-> This is instance 2 of 3\fR
|
||||
$c report
|
||||
\fI\(-> This is instance 3 of 3\fR
|
||||
.CE
|
||||
.PP
|
||||
This example demonstrates how to use class methods. (Note that the constructor
|
||||
for \fBoo::class\fR calls \fBoo::define\fR on the class.)
|
||||
.PP
|
||||
.CS
|
||||
oo::class create DBTable {
|
||||
\fBclassmethod\fR find {description} {
|
||||
puts "DB: locate row from [self] matching $description"
|
||||
return [my new]
|
||||
}
|
||||
\fBclassmethod\fR insert {description} {
|
||||
puts "DB: create row in [self] matching $description"
|
||||
return [my new]
|
||||
}
|
||||
\fBmethod\fR update {description} {
|
||||
puts "DB: update row [self] with $description"
|
||||
}
|
||||
\fBmethod\fR delete {} {
|
||||
puts "DB: delete row [self]"
|
||||
my destroy; # Just delete the object, not the DB row
|
||||
}
|
||||
}
|
||||
|
||||
oo::class create Users {
|
||||
\fBsuperclass\fR DBTable
|
||||
}
|
||||
oo::class create Groups {
|
||||
\fBsuperclass\fR DBTable
|
||||
}
|
||||
|
||||
set u1 [Users insert "username=abc"]
|
||||
\fI\(-> DB: create row from ::Users matching username=abc\fR
|
||||
set u2 [Users insert "username=def"]
|
||||
\fI\(-> DB: create row from ::Users matching username=def\fR
|
||||
$u2 update "group=NULL"
|
||||
\fI\(-> DB: update row ::oo::Obj124 with group=NULL\fR
|
||||
$u1 delete
|
||||
\fI\(-> DB: delete row ::oo::Obj123\fR
|
||||
set g [Group find "groupname=webadmins"]
|
||||
\fI\(-> DB: locate row ::Group with groupname=webadmins\fR
|
||||
$g update "emailaddress=admins"
|
||||
\fI\(-> DB: update row ::oo::Obj125 with emailaddress=admins\fR
|
||||
.CE
|
||||
.VE TIP478
|
||||
.PP
|
||||
.VS TIP524
|
||||
This example shows how to make a custom definition for a class. Note that it
|
||||
explicitly includes delegation to the existing definition commands via
|
||||
\fBnamespace path\fR.
|
||||
.PP
|
||||
.CS
|
||||
namespace eval myDefinitions {
|
||||
# Delegate to existing definitions where not overridden
|
||||
namespace path \fB::oo::define\fR
|
||||
|
||||
# A custom type of method
|
||||
proc exprmethod {name arguments body} {
|
||||
tailcall \fBmethod\fR $name $arguments [list expr $body]
|
||||
}
|
||||
|
||||
# A custom way of building a constructor
|
||||
proc parameters args {
|
||||
uplevel 1 [list \fBvariable\fR {*}$args]
|
||||
set body [join [lmap a $args {
|
||||
string map [list VAR $a] {
|
||||
set [my varname VAR] [expr {double($VAR)}]
|
||||
}
|
||||
}] ";"]
|
||||
tailcall \fBconstructor\fR $args $body
|
||||
}
|
||||
}
|
||||
|
||||
# Bind the namespace into a (very simple) metaclass for use
|
||||
oo::class create exprclass {
|
||||
\fBsuperclass\fR oo::class
|
||||
\fBdefinitionnamespace\fR myDefinitions
|
||||
}
|
||||
|
||||
# Use the custom definitions
|
||||
exprclass create quadratic {
|
||||
parameters a b c
|
||||
exprmethod evaluate {x} {
|
||||
($a * $x**2) + ($b * $x) + $c
|
||||
}
|
||||
}
|
||||
|
||||
# Showing the resulting class and object in action
|
||||
quadratic create quad 1 2 3
|
||||
for {set x 0} {$x <= 4} {incr x} {
|
||||
puts [format "quad(%d) = %.2f" $x [quad evaluate $x]]
|
||||
}
|
||||
\fI\(-> quad(0) = 3.00\fR
|
||||
\fI\(-> quad(1) = 6.00\fR
|
||||
\fI\(-> quad(2) = 11.00\fR
|
||||
\fI\(-> quad(3) = 18.00\fR
|
||||
\fI\(-> quad(4) = 27.00\fR
|
||||
.CE
|
||||
.VE TIP524
|
||||
.SH "SEE ALSO"
|
||||
next(n), oo::class(n), oo::object(n)
|
||||
.SH KEYWORDS
|
||||
|
||||
+1
-36
@@ -27,11 +27,6 @@ key maps to in the dictionary value contained in the given variable,
|
||||
writing the resulting dictionary value back to that variable.
|
||||
Non-existent keys are treated as if they map to an empty string. The
|
||||
updated dictionary value is returned.
|
||||
.VS TIP508
|
||||
If \fIdictionaryVarable\fR indicates an element that does not exist of an
|
||||
array that has a default value set, the default value and will be used as the
|
||||
value of the dictionary prior to the appending operation.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBdict create \fR?\fIkey value ...\fR?
|
||||
.
|
||||
@@ -129,11 +124,6 @@ resulting dictionary value back to that variable. Non-existent keys
|
||||
are treated as if they map to 0. It is an error to increment a value
|
||||
for an existing key if that value is not an integer. The updated
|
||||
dictionary value is returned.
|
||||
.VS TIP508
|
||||
If \fIdictionaryVarable\fR indicates an element that does not exist of an
|
||||
array that has a default value set, the default value and will be used as the
|
||||
value of the dictionary prior to the incrementing operation.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBdict info \fIdictionaryValue\fR
|
||||
.
|
||||
@@ -159,11 +149,6 @@ keys are treated as if they map to an empty list, and it is legal for
|
||||
there to be no items to append to the list. It is an error for the
|
||||
value that the key maps to to not be representable as a list. The
|
||||
updated dictionary value is returned.
|
||||
.VS TIP508
|
||||
If \fIdictionaryVarable\fR indicates an element that does not exist of an
|
||||
array that has a default value set, the default value and will be used as the
|
||||
value of the dictionary prior to the list-appending operation.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBdict map \fR{\fIkeyVariable valueVariable\fR} \fIdictionaryValue body\fR
|
||||
.
|
||||
@@ -221,11 +206,6 @@ value and places an updated dictionary value in that variable
|
||||
containing a mapping from the given key to the given value. When
|
||||
multiple keys are present, this operation creates or updates a chain
|
||||
of nested dictionaries. The updated dictionary value is returned.
|
||||
.VS TIP508
|
||||
If \fIdictionaryVarable\fR indicates an element that does not exist of an
|
||||
array that has a default value set, the default value and will be used as the
|
||||
value of the dictionary prior to the value insert/update operation.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBdict size \fIdictionaryValue\fR
|
||||
.
|
||||
@@ -241,11 +221,6 @@ through nested dictionaries to the mapping to remove. At least one key
|
||||
must be specified, but the last key on the key-path need not exist.
|
||||
All other components on the path must exist. The updated dictionary
|
||||
value is returned.
|
||||
.VS TIP508
|
||||
If \fIdictionaryVarable\fR indicates an element that does not exist of an
|
||||
array that has a default value set, the default value and will be used as the
|
||||
value of the dictionary prior to the value remove operation.
|
||||
.VE TIP508
|
||||
.TP
|
||||
\fBdict update \fIdictionaryVariable key varName \fR?\fIkey varName ...\fR? \fIbody\fR
|
||||
.
|
||||
@@ -261,11 +236,6 @@ are silently discarded), even if the result of \fIbody\fR is an error
|
||||
or some other kind of exceptional exit. The result of \fBdict
|
||||
update\fR is (unless some kind of error occurs) the result of the
|
||||
evaluation of \fIbody\fR.
|
||||
.VS TIP508
|
||||
If \fIdictionaryVarable\fR indicates an element that does not exist of an
|
||||
array that has a default value set, the default value and will be used as the
|
||||
value of the dictionary prior to the update operation.
|
||||
.VE TIP508
|
||||
.RS
|
||||
.PP
|
||||
Each \fIvarName\fR is mapped in the scope enclosing the \fBdict update\fR;
|
||||
@@ -300,11 +270,6 @@ dictionary be discarded, and this also happens if the contents of
|
||||
dictionaries no longer exists. The result of \fBdict with\fR is
|
||||
(unless some kind of error occurs) the result of the evaluation of
|
||||
\fIbody\fR.
|
||||
.VS TIP508
|
||||
If \fIdictionaryVarable\fR indicates an element that does not exist of an
|
||||
array that has a default value set, the default value and will be used as the
|
||||
value of the dictionary prior to the updating operation.
|
||||
.VE TIP508
|
||||
.RS
|
||||
.PP
|
||||
The variables are mapped in the scope enclosing the \fBdict with\fR;
|
||||
@@ -472,7 +437,7 @@ puts $foo
|
||||
# prints: \fIa b foo {a b} bar 2 baz 3\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
append(n), array(n), foreach(n), incr(n), list(n), lappend(n), lmap(n), set(n)
|
||||
append(n), array(n), foreach(n), mapeach(n), incr(n), list(n), lappend(n), set(n)
|
||||
.SH KEYWORDS
|
||||
dictionary, create, update, lookup, iterate, filter, map
|
||||
'\" Local Variables:
|
||||
|
||||
@@ -59,7 +59,3 @@ while {1} {
|
||||
file(n), open(n), close(n), fblocked(n), Tcl_StandardChannels(3)
|
||||
.SH KEYWORDS
|
||||
channel, end of file
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
-17
@@ -217,19 +217,6 @@ information is instead sent to the console, if one is present, or is
|
||||
discarded.
|
||||
.RS
|
||||
.PP
|
||||
Note that the current escape resp. quoting of arguments for windows works only
|
||||
with executables using CommandLineToArgv, CRT-library or similar, as well as
|
||||
with the windows batch files (excepting the newline, see below).
|
||||
Although it is the common escape algorithm, but, in fact, the way how the
|
||||
executable parses the command-line (resp. splits it into single arguments)
|
||||
is decisive.
|
||||
.PP
|
||||
Unfortunately, there is currently no way to supply newline character within
|
||||
an argument to the batch files (\fB.cmd\fR or \fB.bat\fR) or to the command
|
||||
processor (\fBcmd.exe /c\fR), because this causes truncation of command-line
|
||||
(also the argument chain) on the first newline character.
|
||||
But it works properly with an executable (using CommandLineToArgv, etc).
|
||||
.PP
|
||||
The Tk console text widget does not provide real standard IO capabilities.
|
||||
Under Tk, when redirecting from standard input, all applications will see an
|
||||
immediate end-of-file; information redirected to standard output or standard
|
||||
@@ -422,10 +409,6 @@ that sometimes pop up:
|
||||
With the file \fIcmp.bat\fR looking something like:
|
||||
.PP
|
||||
.CS
|
||||
@gcc %*
|
||||
.CE
|
||||
or like another variant using single parameters:
|
||||
.CS
|
||||
@gcc %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
.CE
|
||||
.SS "WORKING WITH COMMAND BUILT-INS"
|
||||
|
||||
@@ -49,7 +49,3 @@ if {[catch {main} msg options]} {
|
||||
exec(n)
|
||||
.SH KEYWORDS
|
||||
abort, exit, process
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
+2
-4
@@ -46,8 +46,7 @@ value is the form produced by the \fB%g\fR format specifier of Tcl's
|
||||
An expression consists of a combination of operands, operators, parentheses and
|
||||
commas, possibly with whitespace between any of these elements, which is
|
||||
ignored.
|
||||
An integer operand may be specified in decimal (the normal case, the optional
|
||||
first two characters are \fB0d\fR), binary
|
||||
An integer operand may be specified in decimal, binary
|
||||
(the first two characters are \fB0b\fR), octal
|
||||
(the first two characters are \fB0o\fR), or hexadecimal
|
||||
(the first two characters are \fB0x\fR) form. For
|
||||
@@ -126,8 +125,7 @@ applied to integers.
|
||||
.TP 20
|
||||
\fB**\fR
|
||||
.
|
||||
Exponentiation. Valid for numeric operands. The maximum exponent value
|
||||
that Tcl can handle if the first number is an integer > 1 is 268435455.
|
||||
Exponentiation. Valid for numeric operands.
|
||||
.TP 20
|
||||
\fB*\0\0/\0\0%\fR
|
||||
.
|
||||
|
||||
@@ -65,7 +65,3 @@ vwait forever
|
||||
gets(n), open(n), read(n), socket(n), Tcl_StandardChannels(3)
|
||||
.SH KEYWORDS
|
||||
blocking, nonblocking
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -154,7 +154,3 @@ fconfigure(n), gets(n), interp(n), puts(n), read(n), Tcl_StandardChannels(3)
|
||||
.SH KEYWORDS
|
||||
asynchronous I/O, blocking, channel, event handler, nonblocking, readable,
|
||||
script, writable.
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -176,7 +176,3 @@ file(n), glob(n)
|
||||
.SH KEYWORDS
|
||||
current directory, absolute file name, relative file name,
|
||||
volume-relative file name, portability
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -43,7 +43,3 @@ puts "Hello there, $name!"
|
||||
file(n), open(n), socket(n), Tcl_StandardChannels(3)
|
||||
.SH KEYWORDS
|
||||
blocking, buffer, channel, flush, nonblocking, output
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -102,7 +102,3 @@ for(n), while(n), break(n), continue(n)
|
||||
|
||||
.SH KEYWORDS
|
||||
foreach, iteration, list, loop
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
+8
-23
@@ -83,15 +83,12 @@ Specifies that the number should be padded on the left with
|
||||
zeroes instead of spaces.
|
||||
.TP 10
|
||||
\fB#\fR
|
||||
Requests an alternate output form. For \fBo\fR conversions,
|
||||
\fB0o\fR will be added to the beginning of the result unless
|
||||
it is zero. For \fBx\fR or \fBX\fR conversions, \fB0x\fR
|
||||
Requests an alternate output form. For \fBo\fR and \fBO\fR
|
||||
conversions it guarantees that the first digit is always \fB0\fR.
|
||||
For \fBx\fR or \fBX\fR conversions, \fB0x\fR or \fB0X\fR (respectively)
|
||||
will be added to the beginning of the result unless it is zero.
|
||||
For \fBb\fR conversions, \fB0b\fR
|
||||
will be added to the beginning of the result unless it is zero.
|
||||
For \fBd\fR conversions, \fB0d\fR there is no effect unless
|
||||
the \fB0\fR specifier is used as well: In that case, \fB0d\fR
|
||||
will be added to the beginning.
|
||||
For all floating-point conversions (\fBe\fR, \fBE\fR, \fBf\fR,
|
||||
\fBg\fR, and \fBG\fR) it guarantees that the result always
|
||||
has a decimal point.
|
||||
@@ -133,7 +130,7 @@ it must be a numeric string.
|
||||
.SS "OPTIONAL SIZE MODIFIER"
|
||||
.PP
|
||||
The fifth part of a conversion specifier is a size modifier,
|
||||
which must be \fBll\fR, \fBh\fR, \fBl\fR, or \fBL\fR.
|
||||
which must be \fBll\fR, \fBh\fR, or \fBl\fR.
|
||||
If it is \fBll\fR it specifies that an integer value is taken
|
||||
without truncation for conversion to a formatted substring.
|
||||
If it is \fBh\fR it specifies that an integer value is
|
||||
@@ -141,9 +138,7 @@ truncated to a 16-bit range before converting. This option is rarely useful.
|
||||
If it is \fBl\fR it specifies that the integer value is
|
||||
truncated to the same range as that produced by the \fBwide()\fR
|
||||
function of the \fBexpr\fR command (at least a 64-bit range).
|
||||
If it is \fBL\fR it specifies that an integer or double value is taken
|
||||
without truncation for conversion to a formatted substring.
|
||||
If neither \fBh\fR nor \fBl\fR nor \fBL\fR are present, the integer value is
|
||||
If neither \fBh\fR nor \fBl\fR are present, the integer value is
|
||||
truncated to the same range as that produced by the \fBint()\fR
|
||||
function of the \fBexpr\fR command (at least a 32-bit range, but
|
||||
determined by the value of the \fBwordSize\fR element of the
|
||||
@@ -174,7 +169,7 @@ for \fBx\fR and
|
||||
for \fBX\fR).
|
||||
.TP 10
|
||||
\fBb\fR
|
||||
Convert integer to unsigned binary string, using digits 0 and 1.
|
||||
Convert integer to binary string, using digits 0 and 1.
|
||||
.TP 10
|
||||
\fBc\fR
|
||||
Convert integer to the Unicode character it represents.
|
||||
@@ -203,19 +198,8 @@ precision, then convert number as for \fB%e\fR or
|
||||
Otherwise convert as for \fB%f\fR.
|
||||
Trailing zeroes and a trailing decimal point are omitted.
|
||||
.TP 10
|
||||
\fBa\fR or \fBA\fR
|
||||
Convert double to hexadecimal notation in the form
|
||||
\fI0x1.yyy\fBp\(+-\fIzz\fR, where the number of \fIy\fR's is
|
||||
determined by the precision (default: 13).
|
||||
If the \fBA\fR form is used then the hex characters
|
||||
are printed in uppercase.
|
||||
.TP 10
|
||||
\fB%\fR
|
||||
No conversion: just insert \fB%\fR.
|
||||
.TP 10
|
||||
\fBp\fR
|
||||
Shorthand form for \fB0x%zx\fR, so it outputs the integer in
|
||||
hexadecimal form with \fB0x\fR prefix.
|
||||
.SH "DIFFERENCES FROM ANSI SPRINTF"
|
||||
.PP
|
||||
The behavior of the format command is the same as the
|
||||
@@ -224,12 +208,13 @@ differences:
|
||||
.IP [1]
|
||||
Tcl guarantees that it will be working with UNICODE characters.
|
||||
.IP [2]
|
||||
\fB%n\fR specifier is not supported.
|
||||
\fB%p\fR and \fB%n\fR specifiers are not supported.
|
||||
.IP [3]
|
||||
For \fB%c\fR conversions the argument must be an integer value,
|
||||
which will then be converted to the corresponding character value.
|
||||
.IP [4]
|
||||
The size modifiers are ignored when formatting floating-point values.
|
||||
The \fBll\fR modifier has no \fBsprintf\fR counterpart.
|
||||
The \fBb\fR specifier has no \fBsprintf\fR counterpart.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
|
||||
@@ -56,7 +56,3 @@ proc accum {string} {
|
||||
namespace(n), upvar(n), variable(n)
|
||||
.SH KEYWORDS
|
||||
global, namespace, procedure, variable
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -100,7 +100,3 @@ the \fBevent\fR operation to retrieve some event,
|
||||
and the \fBadd\fR operation to add it to history and execute it.
|
||||
.SH KEYWORDS
|
||||
event, history, record
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
+10
-289
@@ -6,24 +6,22 @@
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH "http" n 2.9 http "Tcl Bundled Packages"
|
||||
.TH "http" n 2.7 http "Tcl Bundled Packages"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
http \- Client-side implementation of the HTTP/1.1 protocol
|
||||
.SH SYNOPSIS
|
||||
\fBpackage require http\fI ?\fB2.8\fR?
|
||||
\fBpackage require http ?2.7?\fR
|
||||
.\" See Also -useragent option documentation in body!
|
||||
.sp
|
||||
\fB::http::config\fR ?\fI\-option value\fR ...?
|
||||
\fB::http::config ?\fI\-option value\fR ...?
|
||||
.sp
|
||||
\fB::http::geturl \fIurl\fR ?\fI\-option value\fR ...?
|
||||
.sp
|
||||
\fB::http::formatQuery\fR \fIkey value\fR ?\fIkey value\fR ...?
|
||||
.sp
|
||||
\fB::http::quoteString\fR \fIvalue\fR
|
||||
.sp
|
||||
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
|
||||
.sp
|
||||
\fB::http::wait \fItoken\fR
|
||||
@@ -46,14 +44,12 @@ http \- Client-side implementation of the HTTP/1.1 protocol
|
||||
.sp
|
||||
\fB::http::register \fIproto port command\fR
|
||||
.sp
|
||||
\fB::http::registerError \fIport\fR ?\fImessage\fR?
|
||||
.sp
|
||||
\fB::http::unregister \fIproto\fR
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \fBhttp\fR package provides the client side of the HTTP/1.1
|
||||
protocol, as defined in RFC 7230 to RFC 7235, which supersede RFC 2616.
|
||||
protocol, as defined in RFC 2616.
|
||||
The package implements the GET, POST, and HEAD operations
|
||||
of HTTP/1.1. It allows configuration of a proxy host to get through
|
||||
firewalls. The package is compatible with the \fBSafesock\fR security
|
||||
@@ -99,28 +95,6 @@ comma-separated list of mime type patterns that you are
|
||||
willing to receive. For example,
|
||||
.QW "image/gif, image/jpeg, text/*" .
|
||||
.TP
|
||||
\fB\-cookiejar\fR \fIcommand\fR
|
||||
.VS TIP406
|
||||
The cookie store for the package to use to manage HTTP cookies.
|
||||
\fIcommand\fR is a command prefix list; if the empty list (the
|
||||
default value) is used, no cookies will be sent by requests or stored
|
||||
from responses. The command indicated by \fIcommand\fR, if supplied,
|
||||
must obey the \fBCOOKIE JAR PROTOCOL\fR described below.
|
||||
.VE TIP406
|
||||
.TP
|
||||
\fB\-pipeline\fR \fIboolean\fR
|
||||
.
|
||||
Specifies whether HTTP/1.1 transactions on a persistent socket will be
|
||||
pipelined. See the \fBPERSISTENT SOCKETS\fR section for details. The default
|
||||
is 1.
|
||||
.TP
|
||||
\fB\-postfresh\fR \fIboolean\fR
|
||||
.
|
||||
Specifies whether requests that use the \fBPOST\fR method will always use a
|
||||
fresh socket, overriding the \fB-keepalive\fR option of
|
||||
command \fBhttp::geturl\fR. See the \fBPERSISTENT SOCKETS\fR section for details.
|
||||
The default is 0.
|
||||
.TP
|
||||
\fB\-proxyhost\fR \fIhostname\fR
|
||||
.
|
||||
The name of the proxy host, if any. If this value is the
|
||||
@@ -142,47 +116,20 @@ an empty list. The default filter returns the values of the
|
||||
\fB\-proxyhost\fR and \fB\-proxyport\fR settings if they are
|
||||
non-empty.
|
||||
.TP
|
||||
\fB\-repost\fR \fIboolean\fR
|
||||
.
|
||||
Specifies what to do if a POST request over a persistent connection fails
|
||||
because the server has half-closed the connection. If boolean \fBtrue\fR, the
|
||||
request
|
||||
will be automatically retried; if boolean \fBfalse\fR it will not, and the
|
||||
application
|
||||
that uses \fBhttp::geturl\fR is expected to seek user confirmation before
|
||||
retrying the POST. The value \fBtrue\fR should be used only under certain
|
||||
conditions. See the \fBPERSISTENT SOCKETS\fR section for details. The
|
||||
default is 0.
|
||||
.TP
|
||||
\fB\-urlencoding\fR \fIencoding\fR
|
||||
.
|
||||
The \fIencoding\fR used for creating the x-url-encoded URLs with
|
||||
\fB::http::formatQuery\fR and \fB::http::quoteString\fR.
|
||||
The default is \fButf-8\fR, as specified by RFC
|
||||
\fB::http::formatQuery\fR. The default is \fButf-8\fR, as specified by RFC
|
||||
2718. Prior to http 2.5 this was unspecified, and that behavior can be
|
||||
returned by specifying the empty string (\fB{}\fR), although
|
||||
\fIiso8859-1\fR is recommended to restore similar behavior but without the
|
||||
\fB::http::formatQuery\fR or \fB::http::quoteString\fR
|
||||
throwing an error processing non-latin-1 characters.
|
||||
\fB::http::formatQuery\fR throwing an error processing non-latin-1
|
||||
characters.
|
||||
.TP
|
||||
\fB\-useragent\fR \fIstring\fR
|
||||
.
|
||||
The value of the User-Agent header in the HTTP request. In an unsafe
|
||||
interpreter, the default value depends upon the operating system, and
|
||||
the version numbers of \fBhttp\fR and \fBTcl\fR, and is (for example)
|
||||
.QW "\fBMozilla/5.0 (Windows; U; Windows NT 10.0) http/2.8.12 Tcl/8.6.8\fR" .
|
||||
A safe interpreter cannot determine its operating system, and so the default
|
||||
in a safe interpreter is to use a Windows 10 value with the current version
|
||||
numbers of \fBhttp\fR and \fBTcl\fR.
|
||||
.TP
|
||||
\fB\-zip\fR \fIboolean\fR
|
||||
.
|
||||
If the value is boolean \fBtrue\fR, then by default requests will send a header
|
||||
.QW "\fBAccept-Encoding: gzip,deflate,compress\fR" .
|
||||
If the value is boolean \fBfalse\fR, then by default this header will not be sent.
|
||||
In either case the default can be overridden for an individual request by
|
||||
supplying a custom \fBAccept-Encoding\fR header in the \fB-headers\fR option
|
||||
of \fBhttp::geturl\fR. The default is 1.
|
||||
The value of the User-Agent header in the HTTP request. The default is
|
||||
.QW "\fBTcl http client package 2.7\fR" .
|
||||
.RE
|
||||
.TP
|
||||
\fB::http::geturl\fR \fIurl\fR ?\fIoptions\fR?
|
||||
@@ -280,7 +227,7 @@ Pragma: no-cache
|
||||
.TP
|
||||
\fB\-keepalive\fR \fIboolean\fR
|
||||
.
|
||||
If boolean \fBtrue\fR, attempt to keep the connection open for servicing
|
||||
If true, attempt to keep the connection open for servicing
|
||||
multiple requests. Default is 0.
|
||||
.TP
|
||||
\fB\-method\fR \fItype\fR
|
||||
@@ -387,11 +334,6 @@ encodes the keys and values, and generates one string that has the
|
||||
proper & and = separators. The result is suitable for the
|
||||
\fB\-query\fR value passed to \fB::http::geturl\fR.
|
||||
.TP
|
||||
\fB::http::quoteString\fR \fIvalue\fR
|
||||
.
|
||||
This procedure does x-url-encoding of string. It takes a single argument and
|
||||
encodes it.
|
||||
.TP
|
||||
\fB::http::reset\fR \fItoken\fR ?\fIwhy\fR?
|
||||
.
|
||||
This command resets the HTTP transaction identified by \fItoken\fR, if any.
|
||||
@@ -473,17 +415,6 @@ set token [::http::geturl https://my.secure.site/]
|
||||
.CE
|
||||
.RE
|
||||
.TP
|
||||
\fB::http::registerError\fR \fIport\fR ?\fImessage\fR?
|
||||
.
|
||||
This procedure allows a registered protocol handler to deliver an error
|
||||
message for use by \fBhttp\fR. Calling this command does not raise an
|
||||
error. The command is useful when a registered protocol detects an problem
|
||||
(for example, an invalid TLS certificate) that will cause an error to
|
||||
propagate to \fBhttp\fR. The command allows \fBhttp\fR to provide a
|
||||
precise error message rather than a general one. The command returns the
|
||||
value provided by the last call with argument \fImessage\fR, or the empty
|
||||
string if no such call has been made.
|
||||
.TP
|
||||
\fB::http::unregister\fR \fIproto\fR
|
||||
.
|
||||
This procedure unregisters a protocol handler that was previously
|
||||
@@ -573,14 +504,6 @@ The following elements of
|
||||
the array are supported:
|
||||
.RS
|
||||
.TP
|
||||
\fBbinary\fR
|
||||
.
|
||||
This is boolean \fBtrue\fR if (after decoding any compression specified
|
||||
by the
|
||||
.QW "Content-Encoding"
|
||||
response header) the HTTP response is binary. It is boolean \fBfalse\fR
|
||||
if the HTTP response is text.
|
||||
.TP
|
||||
\fBbody\fR
|
||||
.
|
||||
The contents of the URL. This will be empty if the \fB\-channel\fR
|
||||
@@ -679,208 +602,6 @@ A copy of the \fBContent-Type\fR meta-data value.
|
||||
.
|
||||
The requested URL.
|
||||
.RE
|
||||
.SH "PERSISTENT CONNECTIONS"
|
||||
.PP
|
||||
.SS "BASICS"
|
||||
.PP
|
||||
See RFC 7230 Sec 6, which supersedes RFC 2616 Sec 8.1.
|
||||
.PP
|
||||
A persistent connection allows multiple HTTP/1.1 transactions to be
|
||||
carried over the same TCP connection. Pipelining allows a
|
||||
client to make multiple requests over a persistent connection without
|
||||
waiting for each response. The server sends responses in the same order
|
||||
that the requests were received.
|
||||
.PP
|
||||
If a POST request fails to complete, typically user confirmation is
|
||||
needed before sending the request again. The user may wish to verify
|
||||
whether the server was modified by the failed POST request, before
|
||||
sending the same request again.
|
||||
.PP
|
||||
A HTTP request will use a persistent socket if the call to
|
||||
\fBhttp::geturl\fR has the option \fB-keepalive true\fR. It will use
|
||||
pipelining where permitted if the \fBhttp::config\fR option
|
||||
\fB-pipeline\fR is boolean \fBtrue\fR (its default value).
|
||||
.PP
|
||||
The http package maintains no more than one persistent connection to each
|
||||
server (i.e. each value of
|
||||
.QW "domain:port" ).
|
||||
If \fBhttp::geturl\fR is called to make a request over a persistent
|
||||
connection while the connection is busy with another request, the new
|
||||
request will be held in a queue until the connection is free.
|
||||
.PP
|
||||
The http package does not support HTTP/1.0 persistent connections
|
||||
controlled by the \fBKeep-Alive\fR header.
|
||||
.SS "SPECIAL CASES"
|
||||
.PP
|
||||
This subsection discusses issues related to closure of the
|
||||
persistent connection by the server, automatic retry of failed requests,
|
||||
the special treatment necessary for POST requests, and the options for
|
||||
dealing with these cases.
|
||||
.PP
|
||||
In accordance with RFC 7230, \fBhttp::geturl\fR does not pipeline
|
||||
requests that use the POST method. If a POST uses a persistent
|
||||
connection and is not the first request on that connection,
|
||||
\fBhttp::geturl\fR waits until it has received the response for the previous
|
||||
request; or (if \fBhttp::config\fR option \fB-postfresh\fR is boolean \fBtrue\fR) it
|
||||
uses a new connection for each POST.
|
||||
.PP
|
||||
If the server is processing a number of pipelined requests, and sends a
|
||||
response header
|
||||
.QW "\fBConnection: close\fR"
|
||||
with one of the responses (other than the last), then subsequent responses
|
||||
are unfulfilled. \fBhttp::geturl\fR will send the unfulfilled requests again
|
||||
over a new connection.
|
||||
.PP
|
||||
A difficulty arises when a HTTP client sends a request over a persistent
|
||||
connection that has been idle for a while. The HTTP server may
|
||||
half-close an apparently idle connection while the client is sending a
|
||||
request, but before the request arrives at the server: in this case (an
|
||||
.QW "asynchronous close event" )
|
||||
the request will fail. The difficulty arises because the client cannot
|
||||
be certain whether the POST modified the state of the server. For HEAD or
|
||||
GET requests, \fBhttp::geturl\fR opens another connection and retransmits
|
||||
the failed request. However, if the request was a POST, RFC 7230 forbids
|
||||
automatic retry by default, suggesting either user confirmation, or
|
||||
confirmation by user-agent software that has semantic understanding of
|
||||
the application. The \fBhttp::config\fR option \fB-repost\fR allows for
|
||||
either possibility.
|
||||
.PP
|
||||
Asynchronous close events can occur only in a short interval of time. The
|
||||
\fBhttp\fR package monitors each persistent connection for closure by the
|
||||
server. Upon detection, the connection is also closed at the client end,
|
||||
and subsequent requests will use a fresh connection.
|
||||
.PP
|
||||
If the \fBhttp::geturl\fR command is called with option \fB-keepalive true\fR,
|
||||
then it will both try to use an existing persistent connection
|
||||
(if one is available), and it will send the server a
|
||||
.QW "\fBConnection: keep-alive\fR"
|
||||
request header asking to keep the connection open for future requests.
|
||||
.PP
|
||||
The \fBhttp::config\fR options \fB-pipeline\fR, \fB-postfresh\fR, and
|
||||
\fB-repost\fR relate to persistent connections.
|
||||
.PP
|
||||
Option \fB-pipeline\fR, if boolean \fBtrue\fR, will pipeline GET and HEAD requests
|
||||
made
|
||||
over a persistent connection. POST requests will not be pipelined - if the
|
||||
POST is not the first transaction on the connection, its request will not
|
||||
be sent until the previous response has finished. GET and HEAD requests
|
||||
made after a POST will not be sent until the POST response has been
|
||||
delivered, and will not be sent if the POST fails.
|
||||
.PP
|
||||
Option \fB-postfresh\fR, if boolean \fBtrue\fR, will override the \fBhttp::geturl\fR option
|
||||
\fB-keepalive\fR, and always open a fresh connection for a POST request.
|
||||
.PP
|
||||
Option \fB-repost\fR, if \fBtrue\fR, permits automatic retry of a POST request
|
||||
that fails because it uses a persistent connection that the server has
|
||||
half-closed (an
|
||||
.QW "asynchronous close event" ).
|
||||
Subsequent GET and HEAD requests in a failed pipeline will also be retried.
|
||||
\fIThe -repost option should be used only if the application understands
|
||||
that the retry is appropriate\fR - specifically, the application must know
|
||||
that if the failed POST successfully modified the state of the server, a repeat POST
|
||||
would have no adverse effect.
|
||||
.VS TIP406
|
||||
.SH "COOKIE JAR PROTOCOL"
|
||||
.PP
|
||||
Cookies are short key-value pairs used to implement sessions within the
|
||||
otherwise-stateless HTTP protocol. (See RFC 6265 for details; Tcl does not
|
||||
implement the Cookie2 protocol as that is rarely seen in the wild.)
|
||||
.PP
|
||||
Cookie storage managment commands \(em
|
||||
.QW "cookie jars"
|
||||
\(em must support these subcommands which form the HTTP cookie storage
|
||||
management protocol. Note that \fIcookieJar\fR below does not have to be a
|
||||
command name; it is properly a command prefix (a Tcl list of words that will
|
||||
be expanded in place) and admits many possible implementations.
|
||||
.PP
|
||||
Though not formally part of the protocol, it is expected that particular
|
||||
values of \fIcookieJar\fR will correspond to sessions; it is up to the caller
|
||||
of \fB::http::config\fR to decide what session applies and to manage the
|
||||
deletion of said sessions when they are no longer desired (which should be
|
||||
when they not configured as the current cookie jar).
|
||||
.TP
|
||||
\fIcookieJar \fBgetCookies \fIprotocol host requestPath\fR
|
||||
.
|
||||
This command asks the cookie jar what cookies should be supplied for a
|
||||
particular request. It should take the \fIprotocol\fR (typically \fBhttp\fR or
|
||||
\fBhttps\fR), \fIhost\fR name and \fIrequestPath\fR (parsed from the \fIurl\fR
|
||||
argument to \fB::http::geturl\fR) and return a list of cookie keys and values
|
||||
that describe the cookies to supply to the remote host. The list must have an
|
||||
even number of elements.
|
||||
.RS
|
||||
.PP
|
||||
There should only ever be at most one cookie with a particular key for any
|
||||
request (typically the one with the most specific \fIhost\fR/domain match and
|
||||
most specific \fIrequestPath\fR/path match), but there may be many cookies
|
||||
with different names in any request.
|
||||
.RE
|
||||
.TP
|
||||
\fIcookieJar \fBstoreCookie \fIcookieDictionary\fR
|
||||
.
|
||||
This command asks the cookie jar to store a particular cookie that was
|
||||
returned by a request; the result of this command is ignored. The cookie
|
||||
(which will have been parsed by the http package) is described by a
|
||||
dictionary, \fIcookieDictionary\fR, that may have the following keys:
|
||||
.RS
|
||||
.TP
|
||||
\fBdomain\fR
|
||||
.
|
||||
This is always present. Its value describes the domain hostname \fIor
|
||||
prefix\fR that the cookie should be returned for. The checking of the domain
|
||||
against the origin (below) should be careful since sites that issue cookies
|
||||
should only do so for domains related to themselves. Cookies that do not obey
|
||||
a relevant origin matching rule should be ignored.
|
||||
.TP
|
||||
\fBexpires\fR
|
||||
.
|
||||
This is optional. If present, the cookie is intended to be a persistent cookie
|
||||
and the value of the option is the Tcl timestamp (in seconds from the same
|
||||
base as \fBclock seconds\fR) of when the cookie expires (which may be in the
|
||||
past, which should result in the cookie being deleted immediately). If absent,
|
||||
the cookie is intended to be a session cookie that should be not persisted
|
||||
beyond the lifetime of the cookie jar.
|
||||
.TP
|
||||
\fBhostonly\fR
|
||||
.
|
||||
This is always present. Its value is a boolean that describes whether the
|
||||
cookie is a single host cookie (true) or a domain-level cookie (false).
|
||||
.TP
|
||||
\fBhttponly\fR
|
||||
.
|
||||
This is always present. Its value is a boolean that is true when the site
|
||||
wishes the cookie to only ever be used with HTTP (or HTTPS) traffic.
|
||||
.TP
|
||||
\fBkey\fR
|
||||
.
|
||||
This is always present. Its value is the \fIkey\fR of the cookie, which is
|
||||
part of the information that must be return when sending this cookie back in a
|
||||
future request.
|
||||
.TP
|
||||
\fBorigin\fR
|
||||
.
|
||||
This is always present. Its value describes where the http package believes it
|
||||
received the cookie from, which may be useful for checking whether the
|
||||
cookie's domain is valid.
|
||||
.TP
|
||||
\fBpath\fR
|
||||
.
|
||||
This is always present. Its value describes the path prefix of requests to the
|
||||
cookie domain where the cookie should be returned.
|
||||
.TP
|
||||
\fBsecure\fR
|
||||
.
|
||||
This is always present. Its value is a boolean that is true when the cookie
|
||||
should only used on requests sent over secure channels (typically HTTPS).
|
||||
.TP
|
||||
\fBvalue\fR
|
||||
.
|
||||
This is always present. Its value is the value of the cookie, which is part of
|
||||
the information that must be return when sending this cookie back in a future
|
||||
request.
|
||||
.PP
|
||||
Other keys may always be ignored; they have no meaning in this protocol.
|
||||
.RE
|
||||
.VE TIP406
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
This example creates a procedure to copy a URL to a file while printing a
|
||||
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2014-2018 Donal K. Fellows.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH "idna" n 0.1 http "Tcl Bundled Packages"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
tcl::idna \- Support for normalization of Internationalized Domain Names
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require tcl::idna 1.0
|
||||
|
||||
\fBtcl::idna decode\fR \fIhostname\fR
|
||||
\fBtcl::idna encode\fR \fIhostname\fR
|
||||
\fBtcl::idna puny decode\fR \fIstring\fR ?\fIcase\fR?
|
||||
\fBtcl::idna puny encode\fR \fIstring\fR ?\fIcase\fR?
|
||||
\fBtcl::idna version\fR
|
||||
.fi
|
||||
.SH DESCRIPTION
|
||||
This package provides an implementation of the punycode scheme used in
|
||||
Internationalised Domain Names, and some access commands. (See RFC 3492 for a
|
||||
description of punycode.)
|
||||
.TP
|
||||
\fBtcl::idna decode\fR \fIhostname\fR
|
||||
.
|
||||
This command takes the name of a host that potentially contains
|
||||
punycode-encoded character sequences, \fIhostname\fR, and returns the hostname
|
||||
as might be displayed to the user. Note that there are often UNICODE
|
||||
characters that have extremely similar glyphs, so care should be taken with
|
||||
displaying hostnames to users.
|
||||
.TP
|
||||
\fBtcl::idna encode\fR \fIhostname\fR
|
||||
.
|
||||
This command takes the name of a host as might be displayed to the user,
|
||||
\fIhostname\fR, and returns the version of the hostname with characters not
|
||||
permitted in basic hostnames encoded with punycode.
|
||||
.TP
|
||||
\fBtcl::idna puny\fR \fIsubcommand ...\fR
|
||||
.
|
||||
This command provides direct access to the basic punycode encoder and
|
||||
decoder. It supports two \fIsubcommand\fRs:
|
||||
.RS
|
||||
.TP
|
||||
\fBtcl::idna puny decode\fR \fIstring\fR ?\fIcase\fR?
|
||||
.
|
||||
This command decodes the punycode-encoded string, \fIstring\fR, and returns
|
||||
the result. If \fIcase\fR is provided, it is a boolean to make the case be
|
||||
folded to upper case (if \fIcase\fR is true) or lower case (if \fIcase\fR is
|
||||
false) during the decoding process; if omitted, no case transformation is
|
||||
applied.
|
||||
.TP
|
||||
\fBtcl::idna puny encode\fR \fIstring\fR ?\fIcase\fR?
|
||||
.
|
||||
This command encodes the string, \fIstring\fR, and returns the
|
||||
punycode-encoded version of the string. If \fIcase\fR is provided, it is a
|
||||
boolean to make the case be folded to upper case (if \fIcase\fR is true) or
|
||||
lower case (if \fIcase\fR is false) during the encoding process; if omitted,
|
||||
no case transformation is applied.
|
||||
.RE
|
||||
.TP
|
||||
\fBtcl::idna version\fR
|
||||
.
|
||||
This returns the version of the \fBtcl::idna\fR package.
|
||||
.SH "EXAMPLE"
|
||||
.PP
|
||||
This is an example of how punycoding of a string works:
|
||||
.PP
|
||||
.CS
|
||||
package require tcl::idna
|
||||
|
||||
puts [\fBtcl::idna puny encode\fR "abc\(->def"]
|
||||
# prints: \fIabcdef-kn2c\fR
|
||||
puts [\fBtcl::idna puny decode\fR "abcdef-kn2c"]
|
||||
# prints: \fIabc\(->def\fR
|
||||
.CE
|
||||
'\" TODO: show how it handles a real domain name
|
||||
.SH "SEE ALSO"
|
||||
http(n), cookiejar(n)
|
||||
.SH KEYWORDS
|
||||
internet, www
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
@@ -27,11 +27,6 @@ and also returned as result.
|
||||
Starting with the Tcl 8.5 release, the variable \fIvarName\fR passed
|
||||
to \fBincr\fR may be unset, and in that case, it will be set to
|
||||
the value \fIincrement\fR or to the default increment value of \fB1\fR.
|
||||
.VS TIP508
|
||||
If \fIvarName\fR indicate an element that does not exist of an array that has
|
||||
a default value set, the sum of the default value and the \fIincrement\fR (or
|
||||
1) will be stored in the array element.
|
||||
.VE TIP508
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Add one to the contents of the variable \fIx\fR:
|
||||
@@ -64,7 +59,3 @@ an error if it is not):
|
||||
expr(n), set(n)
|
||||
.SH KEYWORDS
|
||||
add, increment, variable, value
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
|
||||
+317
-335
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -201,7 +201,7 @@ slave interpreter identified by \fIpath\fR. If no arguments are
|
||||
given, option and current setting are returned. If \fB\-frame\fR
|
||||
is given, the debug setting is set to the given boolean if provided
|
||||
and the current setting is returned.
|
||||
This only affects the output of \fBinfo frame\fR, in that exact
|
||||
This only effects the output of \fBinfo frame\fR, in that exact
|
||||
frame-level information for command invocation at the bytecode level
|
||||
is only captured with this setting on.
|
||||
.RS
|
||||
@@ -236,7 +236,7 @@ attempts are silently ignored. This is needed to maintain the
|
||||
consistency of the underlying interpreter's state.
|
||||
.RE
|
||||
.TP
|
||||
\fBinterp\fR \fBdelete \fR?\fIpath ...\fR?
|
||||
\fBinterp\fR \fBdelete \fR?\fIpath ...?\fR
|
||||
.
|
||||
Deletes zero or more interpreters given by the optional \fIpath\fR
|
||||
arguments, and for each interpreter, it also deletes its slaves. The
|
||||
|
||||
@@ -42,7 +42,3 @@ set data {1 {2 3} 4 {5 {6 7} 8}}
|
||||
list(n), lappend(n), split(n)
|
||||
.SH KEYWORDS
|
||||
element, join, list, separator
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -22,12 +22,6 @@ and appends each of the \fIvalue\fR arguments to that list as a separate
|
||||
element, with spaces between elements.
|
||||
If \fIvarName\fR does not exist, it is created as a list with elements
|
||||
given by the \fIvalue\fR arguments.
|
||||
.VS TIP508
|
||||
If \fIvarName\fR indicate an element that does not exist of an array that has
|
||||
a default value set, list that is comprised of the default value with all the
|
||||
\fIvalue\fR arguments appended as elements will be stored in the array
|
||||
element.
|
||||
.VE TIP508
|
||||
\fBLappend\fR is similar to \fBappend\fR except that the \fIvalue\fRs
|
||||
are appended as list elements rather than raw text.
|
||||
This command provides a relatively efficient way to build up
|
||||
@@ -53,7 +47,3 @@ list(n), lindex(n), linsert(n), llength(n), lset(n),
|
||||
lsort(n), lrange(n)
|
||||
.SH KEYWORDS
|
||||
append, element, list, variable
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
.SH NAME
|
||||
lindex \- Retrieve an element from a list
|
||||
.SH SYNOPSIS
|
||||
\fBlindex \fIlist\fR ?\fIindex ...\fR?
|
||||
\fBlindex \fIlist ?index ...?\fR
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
|
||||
-124
@@ -1,124 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2011-2015 Andreas Kupries
|
||||
'\" Copyright (c) 2018 Donal K. Fellows
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH link n 0.3 TclOO "TclOO Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
link \- create link from command to method of object
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBlink\fR \fImethodName\fR ?\fI...\fR?
|
||||
\fBlink\fR \fB{\fIcommandName methodName\fB}\fR ?\fI...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
The \fBlink\fR command is available within methods. It takes a series of one
|
||||
or more method names (\fImethodName ...\fR) and/or pairs of command- and
|
||||
method-name (\fB{\fIcommandName methodName\fB}\fR) and makes the named methods
|
||||
available as commands without requiring the explicit use of the name of the
|
||||
object or the \fBmy\fR command. The method does not need to exist at the time
|
||||
that the link is made; if the link command is invoked when the method does not
|
||||
exist, the standard \fBunknown\fR method handling system is used.
|
||||
.PP
|
||||
The command name under which the method becomes available defaults to the
|
||||
method name, except where explicitly specified through an alias/method pair.
|
||||
Formally, every argument must be a list; if the list has two elements, the
|
||||
first element is the name of the command to create and the second element is
|
||||
the name of the method of the current object to which the command links;
|
||||
otherwise, the name of the command and the name of the method are the same
|
||||
string (the first element of the list).
|
||||
.PP
|
||||
If the name of the command is not a fully-qualified command name, it will be
|
||||
resolved with respect to the current namespace (i.e., the object namespace).
|
||||
.SH EXAMPLES
|
||||
This demonstrates linking a single method in various ways. First it makes a
|
||||
simple link, then a renamed link, then an external link. Note that the method
|
||||
itself is unexported, but that it can still be called directly from outside
|
||||
the class.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create ABC {
|
||||
method Foo {} {
|
||||
puts "This is Foo in [self]"
|
||||
}
|
||||
|
||||
constructor {} {
|
||||
\fBlink\fR Foo
|
||||
# The method foo is now directly accessible as foo here
|
||||
\fBlink\fR {bar Foo}
|
||||
# The method foo is now directly accessible as bar
|
||||
\fBlink\fR {::ExternalCall Foo}
|
||||
# The method foo is now directly accessible in the global
|
||||
# namespace as ExternalCall
|
||||
}
|
||||
|
||||
method grill {} {
|
||||
puts "Step 1:"
|
||||
Foo
|
||||
puts "Step 2:"
|
||||
bar
|
||||
}
|
||||
}
|
||||
|
||||
ABC create abc
|
||||
abc grill
|
||||
\fI\(-> Step 1:\fR
|
||||
\fI\(-> This is foo in ::abc\fR
|
||||
\fI\(-> Step 2:\fR
|
||||
\fI\(-> This is foo in ::abc\fR
|
||||
# Direct access via the linked command
|
||||
puts "Step 3:"; ExternalCall
|
||||
\fI\(-> Step 3:\fR
|
||||
\fI\(-> This is foo in ::abc\fR
|
||||
.CE
|
||||
.PP
|
||||
This example shows that multiple linked commands can be made in a call to
|
||||
\fBlink\fR, and that they can handle arguments.
|
||||
.PP
|
||||
.CS
|
||||
oo::class create Ex {
|
||||
constructor {} {
|
||||
\fBlink\fR a b c
|
||||
# The methods a, b, and c (defined below) are all now
|
||||
# directly acessible within methods under their own names.
|
||||
}
|
||||
|
||||
method a {} {
|
||||
puts "This is a"
|
||||
}
|
||||
method b {x} {
|
||||
puts "This is b($x)"
|
||||
}
|
||||
method c {y z} {
|
||||
puts "This is c($y,$z)"
|
||||
}
|
||||
|
||||
method call {p q r} {
|
||||
a
|
||||
b $p
|
||||
c $q $r
|
||||
}
|
||||
}
|
||||
|
||||
set o [Ex new]
|
||||
$o 3 5 7
|
||||
\fI\(-> This is a\fR
|
||||
\fI\(-> This is b(3)\fR
|
||||
\fI\(-> This is c(5,7)\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
interp(n), my(n), oo::class(n), oo::define(n)
|
||||
.SH KEYWORDS
|
||||
command, method, object
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
@@ -53,7 +53,3 @@ list(n), lappend(n), lindex(n), linsert(n), lsearch(n),
|
||||
lset(n), lsort(n), lrange(n), lreplace(n)
|
||||
.SH KEYWORDS
|
||||
element, list, length
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2018 by Peter Spjuth. All rights reserved.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH lpop n 8.7 Tcl "Tcl Built-In Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
lpop \- Get and remove an element in a list
|
||||
.SH SYNOPSIS
|
||||
\fBlpop \fIvarName ?index ...?\fR
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \fBlpop\fR command accepts a parameter, \fIvarName\fR, which
|
||||
it interprets as the name of a variable containing a Tcl list.
|
||||
It also accepts one or more \fIindices\fR into
|
||||
the list. If no indices are presented, it defaults to "end".
|
||||
.PP
|
||||
When presented with a single index, the \fBlpop\fR command
|
||||
addresses the \fIindex\fR'th element in it, removes if from the list
|
||||
and returns the element.
|
||||
.PP
|
||||
If \fIindex\fR is negative or greater or equal than the number
|
||||
of elements in \fI$varName\fR, then an error occurs.
|
||||
.PP
|
||||
The interpretation of each simple \fIindex\fR value is the same as
|
||||
for the command \fBstring index\fR, supporting simple index
|
||||
arithmetic and indices relative to the end of the list.
|
||||
.PP
|
||||
If additional \fIindex\fR arguments are supplied, then each argument is
|
||||
used in turn to address an element within a sublist designated
|
||||
by the previous indexing operation,
|
||||
allowing the script to remove elements in sublists.
|
||||
The command,
|
||||
.PP
|
||||
.CS
|
||||
\fBlpop\fR a 1 2
|
||||
.CE
|
||||
.PP
|
||||
gets and removes element 2 of sublist 1.
|
||||
.PP
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
In each of these examples, the initial value of \fIx\fR is:
|
||||
.PP
|
||||
.CS
|
||||
set x [list [list a b c] [list d e f] [list g h i]]
|
||||
\fI\(-> {a b c} {d e f} {g h i}\fR
|
||||
.CE
|
||||
.PP
|
||||
The indicated value becomes the new value of \fIx\fR
|
||||
(except in the last case, which is an error which leaves the value of
|
||||
\fIx\fR unchanged.)
|
||||
.PP
|
||||
.CS
|
||||
\fBlpop\fR x 0
|
||||
\fI\(-> {d e f} {g h i}\fR
|
||||
\fBlpop\fR x 2
|
||||
\fI\(-> {a b c} {d e f}\fR
|
||||
\fBlpop\fR x end
|
||||
\fI\(-> {a b c} {d e f}\fR
|
||||
\fBlpop\fR x end-1
|
||||
\fI\(-> {a b c} {g h i}\fR
|
||||
\fBlpop\fR x 2 1
|
||||
\fI\(-> {a b c} {d e f} {g i}\fR
|
||||
\fBlpop\fR x 2 3 j
|
||||
\fI\(-> list index out of range\fR
|
||||
.CE
|
||||
.PP
|
||||
In the following examples, the initial value of \fIx\fR is:
|
||||
.PP
|
||||
.CS
|
||||
set x [list [list [list a b] [list c d]] \e
|
||||
[list [list e f] [list g h]]]
|
||||
\fI\(-> {{a b} {c d}} {{e f} {g h}}\fR
|
||||
.CE
|
||||
.PP
|
||||
The indicated value becomes the new value of \fIx\fR.
|
||||
.PP
|
||||
.CS
|
||||
\fBlpop\fR x 1 1 0
|
||||
\fI\(-> {{a b} {c d}} {{e f} h}\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n),
|
||||
lsort(n), lrange(n), lreplace(n), lset(n)
|
||||
string(n)
|
||||
.SH KEYWORDS
|
||||
element, index, list, remove, pop, stack, queue
|
||||
'\"Local Variables:
|
||||
'\"mode: nroff
|
||||
'\"End:
|
||||
@@ -76,7 +76,3 @@ lset(n), lreplace(n), lsort(n),
|
||||
string(n)
|
||||
.SH KEYWORDS
|
||||
element, list, range, sublist
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
+1
-4
@@ -33,9 +33,6 @@ is identical to \fBlist element ...\fR.
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
list(n), lappend(n), linsert(n), llength(n), lset(n)
|
||||
|
||||
.SH KEYWORDS
|
||||
element, index, list
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
+10
-30
@@ -17,7 +17,7 @@ lreplace \- Replace elements in a list with new elements
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlreplace\fR returns a new list formed by replacing zero or more elements of
|
||||
\fBlreplace\fR returns a new list formed by replacing one or more elements of
|
||||
\fIlist\fR with the \fIelement\fR arguments.
|
||||
\fIfirst\fR and \fIlast\fR are index values specifying the first and
|
||||
last elements of the range to replace.
|
||||
@@ -27,26 +27,23 @@ supporting simple index arithmetic and indices relative to the
|
||||
end of the list.
|
||||
0 refers to the first element of the
|
||||
list, and \fBend\fR refers to the last element of the list.
|
||||
If \fIlist\fR is empty, then \fIfirst\fR and \fIlast\fR are ignored.
|
||||
.PP
|
||||
If either \fIfirst\fR or \fIlast\fR is less than zero, it is considered
|
||||
to refer to before the first element of the list. This allows \fBlreplace\fR
|
||||
to prepend elements to \fIlist\fR.
|
||||
.VS TIP505
|
||||
If either \fIfirst\fR or \fIlast\fR indicates a position greater than the
|
||||
index of the last element of the list, it is treated as if it is an
|
||||
index one greater than the last element. This allows \fBlreplace\fR to
|
||||
append elements to \fIlist\fR.
|
||||
.VE TIP505
|
||||
If \fIfirst\fR is less than zero, it is considered to refer to before the
|
||||
first element of the list. For non-empty lists, the element indicated
|
||||
by \fIfirst\fR must exist or \fIfirst\fR must indicate before the
|
||||
start of the list.
|
||||
.PP
|
||||
If \fIlast\fR is less than \fIfirst\fR, then any specified elements
|
||||
will be inserted into the list before the element specified by \fIfirst\fR
|
||||
will be inserted into the list before the point specified by \fIfirst\fR
|
||||
with no elements being deleted.
|
||||
.PP
|
||||
The \fIelement\fR arguments specify zero or more new elements to
|
||||
The \fIelement\fR arguments specify zero or more new arguments to
|
||||
be added to the list in place of those that were deleted.
|
||||
Each \fIelement\fR argument will become a separate element of
|
||||
the list. If no \fIelement\fR arguments are specified, then the elements
|
||||
between \fIfirst\fR and \fIlast\fR are simply deleted.
|
||||
between \fIfirst\fR and \fIlast\fR are simply deleted. If \fIlist\fR
|
||||
is empty, any \fIelement\fR arguments are added to the end of the list.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Replacing an element of a list with another:
|
||||
@@ -81,26 +78,9 @@ proc lremove {listVariable value} {
|
||||
set var [\fBlreplace\fR $var $idx $idx]
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
.VS TIP505
|
||||
Appending elements to the list; note that \fBend+2\fR will initially
|
||||
be treated as if it is \fB6\fR here, but both that and \fB12345\fR are greater
|
||||
than the index of the final item so they behave identically:
|
||||
.PP
|
||||
.CS
|
||||
% set var {a b c d e}
|
||||
a b c d e
|
||||
% set var [\fBlreplace\fR $var 12345 end+2 f g h i]
|
||||
a b c d e f g h i
|
||||
.CE
|
||||
.VE TIP505
|
||||
.SH "SEE ALSO"
|
||||
list(n), lappend(n), lindex(n), linsert(n), llength(n), lsearch(n),
|
||||
lset(n), lrange(n), lsort(n),
|
||||
string(n)
|
||||
.SH KEYWORDS
|
||||
element, list, replace
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
.\" End:
|
||||
|
||||
@@ -148,19 +148,6 @@ or \fB\-not\fR.
|
||||
These options are used to search lists of lists. They may be used
|
||||
with any other options.
|
||||
.TP
|
||||
\fB\-stride\0\fIstrideLength\fR
|
||||
.
|
||||
If this option is specified, the list is treated as consisting of
|
||||
groups of \fIstrideLength\fR elements and the groups are searched by
|
||||
either their first element or, if the \fB\-index\fR option is used,
|
||||
by the element within each group given by the first index passed to
|
||||
\fB\-index\fR (which is then ignored by \fB\-index\fR). The resulting
|
||||
index always points to the first element in a group.
|
||||
.PP
|
||||
The list length must be an integer multiple of \fIstrideLength\fR, which
|
||||
in turn must be at least 1. A \fIstrideLength\fR of 1 is the default and
|
||||
indicates no grouping.
|
||||
.TP
|
||||
\fB\-index\fR\0\fIindexList\fR
|
||||
.
|
||||
This option is designed for use when searching within nested lists.
|
||||
@@ -221,13 +208,6 @@ It is also possible to search inside elements:
|
||||
\fBlsearch\fR -index 1 -all -inline {{a abc} {b bcd} {c cde}} *bc*
|
||||
\fI\(-> {a abc} {b bcd}\fR
|
||||
.CE
|
||||
.PP
|
||||
The same thing for a flattened list:
|
||||
.PP
|
||||
.CS
|
||||
\fBlsearch\fR -stride 2 -index 1 -all -inline {a abc b bcd c cde} *bc*
|
||||
\fI\(-> {a abc b bcd}\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
foreach(n), list(n), lappend(n), lindex(n), linsert(n), llength(n),
|
||||
lset(n), lsort(n), lrange(n), lreplace(n),
|
||||
|
||||
+4
-5
@@ -151,11 +151,10 @@ is the same as
|
||||
.QW "\fB** 2 [** 3 4]\fR" .
|
||||
Each \fInumber\fR may be
|
||||
any numeric value, though the second number must not be fractional if the
|
||||
first is negative. The maximum exponent value that Tcl can handle if the
|
||||
first number is an integer > 1 is 268435455. If no arguments are given,
|
||||
the result will be one, and if only one argument is given, the result will
|
||||
be that argument. The result will have an integral value only when all
|
||||
arguments are integral values.
|
||||
first is negative. If no arguments are given, the result will be one, and if
|
||||
only one argument is given, the result will be that argument. The
|
||||
result will have an integral value only when all arguments are
|
||||
integral values.
|
||||
.SS "COMPARISON OPERATORS"
|
||||
.PP
|
||||
The behaviors of the comparison operator commands (most of which operate
|
||||
|
||||
+27
-178
@@ -11,9 +11,9 @@
|
||||
.SH NAME
|
||||
msgcat \- Tcl message catalog
|
||||
.SH SYNOPSIS
|
||||
\fBpackage require Tcl 8.7\fR
|
||||
\fBpackage require Tcl 8.5\fR
|
||||
.sp
|
||||
\fBpackage require msgcat 1.7\fR
|
||||
\fBpackage require msgcat 1.6\fR
|
||||
.sp
|
||||
\fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR?
|
||||
.sp
|
||||
@@ -23,15 +23,9 @@ msgcat \- Tcl message catalog
|
||||
\fB::msgcat::mcexists\fR ?\fB-exactnamespace\fR? ?\fB-exactlocale\fR? \fIsrc-string\fR
|
||||
.VE "TIP 412"
|
||||
.sp
|
||||
.VS "TIP 490"
|
||||
\fB::msgcat::mcpackagenamespaceget\fR
|
||||
.VE "TIP 490"
|
||||
.sp
|
||||
\fB::msgcat::mclocale \fR?\fInewLocale\fR?
|
||||
.sp
|
||||
.VS "TIP 499"
|
||||
\fB::msgcat::mcpreferences\fR ?\fIlocale preference\fR? ...
|
||||
.VE "TIP 499"
|
||||
\fB::msgcat::mcpreferences\fR
|
||||
.sp
|
||||
.VS "TIP 412"
|
||||
\fB::msgcat::mcloadedlocales subcommand\fR ?\fIlocale\fR?
|
||||
@@ -56,10 +50,6 @@ msgcat \- Tcl message catalog
|
||||
.sp
|
||||
\fB::msgcat::mcforgetpackage\fR
|
||||
.VE "TIP 412"
|
||||
.sp
|
||||
.VS "TIP 499"
|
||||
\fB::msgcat::mcutil subcommand\fR ?\fIlocale\fR?
|
||||
.VS "TIP 499"
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
@@ -81,11 +71,6 @@ In \fBmsgcat\fR, there is a global locale initialized by the system locale of th
|
||||
Each package may decide to use the global locale or to use a package specific locale.
|
||||
.PP
|
||||
The global locale may be changed on demand, for example by a user initiated language change or within a multi user application like a web server.
|
||||
.PP
|
||||
.VS tip490
|
||||
Object oriented programming is supported by the use of a package namespace.
|
||||
.VE tip490
|
||||
.PP
|
||||
.SH COMMANDS
|
||||
.TP
|
||||
\fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR?
|
||||
@@ -110,17 +95,6 @@ use the result. If an application is written for a single language in
|
||||
this fashion, then it is easy to add support for additional languages
|
||||
later simply by defining new message catalog entries.
|
||||
.RE
|
||||
.VS "TIP 490"
|
||||
.TP
|
||||
\fB::msgcat::mcn \fInamespace\fR \fIsrc-string\fR ?\fIarg arg ...\fR?
|
||||
.
|
||||
Like \fB::msgcat::mc\fR, but with the message namespace specified as first argument.
|
||||
.PP
|
||||
.RS
|
||||
\fBmcn\fR may be used for cases where the package namespace is not the namespace of the caller.
|
||||
An example is shown within the description of the command \fB::msgcat::mcpackagenamespaceget\fR below.
|
||||
.RE
|
||||
.PP
|
||||
.TP
|
||||
\fB::msgcat::mcmax ?\fIsrc-string src-string ...\fR?
|
||||
.
|
||||
@@ -128,69 +102,29 @@ Given several source strings, \fB::msgcat::mcmax\fR returns the length
|
||||
of the longest translated string. This is useful when designing
|
||||
localized GUIs, which may require that all buttons, for example, be a
|
||||
fixed width (which will be the width of the widest button).
|
||||
.VS "TIP 412"
|
||||
.TP
|
||||
\fB::msgcat::mcexists\fR ?\fB-exactnamespace\fR? ?\fB-exactlocale\fR? ?\fB-namespace\fR \fInamespace\fR? \fIsrc-string\fR
|
||||
\fB::msgcat::mcexists\fR ?\fB-exactnamespace\fR? ?\fB-exactlocale\fR? \fIsrc-string\fR
|
||||
.
|
||||
.VS "TIP 412"
|
||||
Return true, if there is a translation for the given \fIsrc-string\fR.
|
||||
.PP
|
||||
.RS
|
||||
The search may be limited by the option \fB\-exactnamespace\fR to only check the current namespace and not any parent namespaces.
|
||||
.PP
|
||||
It may also be limited by the option \fB\-exactlocale\fR to only check the first prefered locale (e.g. first element returned by \fB::msgcat::mcpreferences\fR if global locale is used).
|
||||
.PP
|
||||
.RE
|
||||
.VE "TIP 412"
|
||||
.VS "TIP 490"
|
||||
An explicit package namespace may be specified by the option \fB-namespace\fR.
|
||||
The namespace of the caller is used if not explicitly specified.
|
||||
.RE
|
||||
.PP
|
||||
.VE "TIP 490"
|
||||
.VS "TIP 490"
|
||||
.TP
|
||||
\fB::msgcat::mcpackagenamespaceget\fR
|
||||
.
|
||||
Return the package namespace of the caller.
|
||||
This command handles all cases described in section \fBOBJECT ORIENTED PROGRAMMING\fR.
|
||||
.PP
|
||||
.RS
|
||||
Example usage is a tooltip package, which saves the caller package namespace to update the translation each time the tooltip is shown:
|
||||
.CS
|
||||
proc ::tooltip::tooltip {widget message} {
|
||||
...
|
||||
set messagenamespace [uplevel 1 {::msgcat::mcpackagenamespaceget}]
|
||||
...
|
||||
bind $widget [list ::tooltip::show $widget $messagenamespace $message]
|
||||
}
|
||||
|
||||
proc ::tooltip::show {widget messagenamespace message} {
|
||||
...
|
||||
set message [::msgcat::mcn $messagenamespace $message]
|
||||
...
|
||||
}
|
||||
.CE
|
||||
.RE
|
||||
.PP
|
||||
.VE "TIP 490"
|
||||
.TP
|
||||
\fB::msgcat::mclocale \fR?\fInewLocale\fR?
|
||||
.
|
||||
If \fInewLocale\fR is omitted, the current locale is returned, otherwise the current locale
|
||||
is set to \fInewLocale\fR.
|
||||
.PP
|
||||
.RS
|
||||
If the new locale is set to \fInewLocale\fR, the corresponding preferences are calculated and set.
|
||||
For example, if the current locale is en_US_funky, then \fB::msgcat::mcpreferences\fR returns \fB{en_us_funky en_us en {}}\fR.
|
||||
.PP
|
||||
The same result may be acheved by \fB::msgcat::mcpreferences\fR {*}[\fB::msgcat::mcutil getpreferences\fR \fInewLocale\fR].
|
||||
.PP
|
||||
The current locale is always the first element of the list returned by \fBmcpreferences\fR.
|
||||
.PP
|
||||
msgcat stores and compares the locale in a
|
||||
This function sets the locale to \fInewLocale\fR. If \fInewLocale\fR
|
||||
is omitted, the current locale is returned, otherwise the current locale
|
||||
is set to \fInewLocale\fR. msgcat stores and compares the locale in a
|
||||
case-insensitive manner, and returns locales in lowercase.
|
||||
The initial locale is determined by the locale specified in
|
||||
the user's environment. See \fBLOCALE SPECIFICATION\fR
|
||||
below for a description of the locale string format.
|
||||
.RS
|
||||
.PP
|
||||
.VS "TIP 412"
|
||||
If the locale is set, the preference list of locales is evaluated.
|
||||
@@ -198,26 +132,16 @@ Locales in this list are loaded now, if not jet loaded.
|
||||
.VE "TIP 412"
|
||||
.RE
|
||||
.TP
|
||||
\fB::msgcat::mcpreferences\fR ?\fIlocale preference\fR? ...
|
||||
\fB::msgcat::mcpreferences\fR
|
||||
.
|
||||
Without arguments, returns an ordered list of the locales preferred by
|
||||
the user.
|
||||
The list is ordered from most specific to least preference.
|
||||
.PP
|
||||
.VS "TIP 499"
|
||||
.RS
|
||||
A set of locale preferences may be given to set the list of locale preferences.
|
||||
The current locale is also set, which is the first element of the locale preferences list.
|
||||
.PP
|
||||
Locale preferences are loaded now, if not jet loaded.
|
||||
.PP
|
||||
As an example, the user may prefer French or English text. This may be configured by:
|
||||
.CS
|
||||
::msgcat::mcpreferences fr en {}
|
||||
.CE
|
||||
.RE
|
||||
.PP
|
||||
.VS "TIP 499"
|
||||
Returns an ordered list of the locales preferred by
|
||||
the user, based on the user's language specification.
|
||||
The list is ordered from most specific to least
|
||||
preference. The list is derived from the current
|
||||
locale set in msgcat by \fB::msgcat::mclocale\fR, and
|
||||
cannot be set independently. For example, if the
|
||||
current locale is en_US_funky, then \fB::msgcat::mcpreferences\fR
|
||||
returns \fB{en_us_funky en_us en {}}\fR.
|
||||
.TP
|
||||
\fB::msgcat:mcloadedlocales subcommand\fR ?\fIlocale\fR?
|
||||
.
|
||||
@@ -308,22 +232,6 @@ Note that this routine is only called if the concerned package did not set a pac
|
||||
The calling package clears all its state within the \fBmsgcat\fR package including all settings and translations.
|
||||
.VE "TIP 412"
|
||||
.PP
|
||||
.VS "TIP 499"
|
||||
.TP
|
||||
\fB::msgcat::mcutil getpreferences\fR \fIlocale\fR
|
||||
.
|
||||
Return the preferences list of the given locale as described in section \fBLOCALE SPECIFICATION\fR.
|
||||
An example is the composition of a preference list for the bilingual region "Biel/Bienne" as a concatenation of swiss german and swiss french:
|
||||
.CS
|
||||
% concat [lrange [msgcat::mcutil getpreferences fr_CH] 0 end-1] [msgcat::mcutil getpreferences de_CH]
|
||||
fr_ch fr de_ch de {}
|
||||
.CE
|
||||
.TP
|
||||
\fB::msgcat::mcutil getsystemlocale\fR
|
||||
.
|
||||
The system locale is returned as described by the section \fBLOCALE SPECIFICATION\fR.
|
||||
.VE "TIP 499"
|
||||
.PP
|
||||
.SH "LOCALE SPECIFICATION"
|
||||
.PP
|
||||
The locale is specified to \fBmsgcat\fR by a locale string
|
||||
@@ -529,7 +437,7 @@ formatting substitution is done directly.
|
||||
# human-oriented versions by \fBmsgcat::mcset\fR
|
||||
.CE
|
||||
.VS "TIP 412"
|
||||
.SH "PACKAGE PRIVATE LOCALE"
|
||||
.SH Package private locale
|
||||
.PP
|
||||
A package using \fBmsgcat\fR may choose to use its own package private
|
||||
locale and its own set of loaded locales, independent to the global
|
||||
@@ -553,22 +461,10 @@ This command may cause the load of locales.
|
||||
.
|
||||
Return the package private locale or the global locale, if no package private locale is set.
|
||||
.TP
|
||||
\fB::msgcat::mcpackagelocale preferences\fR ?\fIlocale preference\fR? ...
|
||||
\fB::msgcat::mcpackagelocale preferences\fR
|
||||
.
|
||||
With no parameters, return the package private preferences or the global preferences,
|
||||
Return the package private preferences or the global preferences,
|
||||
if no package private locale is set.
|
||||
The package locale state (set or not) is not changed (in contrast to the command \fB::msgcat::mcpackagelocale set\fR).
|
||||
.PP
|
||||
.RS
|
||||
.VS "TIP 499"
|
||||
If a set of locale preferences is given, it is set as package locale preference list.
|
||||
The package locale is set to the first element of the preference list.
|
||||
A package locale is activated, if it was not set so far.
|
||||
.PP
|
||||
Locale preferences are loaded now for the package, if not jet loaded.
|
||||
.VE "TIP 499"
|
||||
.RE
|
||||
.PP
|
||||
.TP
|
||||
\fB::msgcat::mcpackagelocale loaded\fR
|
||||
.
|
||||
@@ -592,7 +488,7 @@ Returns true, if the given locale is loaded for the package.
|
||||
.
|
||||
Clear any loaded locales of the package not present in the package preferences.
|
||||
.PP
|
||||
.SH "CHANGING PACKAGE OPTIONS"
|
||||
.SH Changing package options
|
||||
.PP
|
||||
Each package using msgcat has a set of options within \fBmsgcat\fR.
|
||||
The package options are described in the next sectionPackage options.
|
||||
@@ -667,7 +563,7 @@ A generic unknown handler is used if set to the empty string. This consists in r
|
||||
See section \fBcallback invocation\fR below.
|
||||
The appended arguments are identical to \fB::msgcat::mcunknown\fR.
|
||||
.RE
|
||||
.SH "Callback invocation"
|
||||
.SS Callback invocation
|
||||
A package may decide to register one or multiple callbacks, as described above.
|
||||
.PP
|
||||
Callbacks are invoked, if:
|
||||
@@ -681,54 +577,7 @@ Callbacks are invoked, if:
|
||||
If a called routine fails with an error, the \fBbgerror\fR routine for the interpreter is invoked after command completion.
|
||||
Only exception is the callback \fBunknowncmd\fR, where an error causes the invoking \fBmc\fR-command to fail with that error.
|
||||
.PP
|
||||
.VS tip490
|
||||
.SH "OBJECT ORIENTED PROGRAMMING"
|
||||
\fBmsgcat\fR supports packages implemented by object oriented programming.
|
||||
Objects and classes should be defined within a package namespace.
|
||||
.PP
|
||||
There are 3 supported cases where package namespace sensitive commands of msgcat (\fBmc\fR, \fBmcexists\fR, \fBmcpackagelocale\fR, \fBmcforgetpackage\fR, \fBmcpackagenamespaceget\fR, \fBmcpackageconfig\fR, \fBmcset\fR and \fBmcmset\fR) may be called:
|
||||
.PP
|
||||
.TP
|
||||
\fB1) In class definition script\fR
|
||||
.
|
||||
\fBmsgcat\fR command is called within a class definition script.
|
||||
.CS
|
||||
namespace eval ::N2 {
|
||||
mcload $dir/msgs
|
||||
oo::class create C1 {puts [mc Hi!]}
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
.TP
|
||||
\fB2) method defined in a class\fR
|
||||
.
|
||||
\fBmsgcat\fR command is called from a method in an object and the method is defined in a class.
|
||||
.CS
|
||||
namespace eval ::N3Class {
|
||||
mcload $dir/msgs
|
||||
oo::class create C1
|
||||
oo::define C1 method m1 {
|
||||
puts [mc Hi!]
|
||||
}
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
.TP
|
||||
\fB3) method defined in a classless object\fR
|
||||
.
|
||||
\fBmsgcat\fR command is called from a method of a classless object.
|
||||
.CS
|
||||
namespace eval ::N4 {
|
||||
mcload $dir/msgs
|
||||
oo::object create O1
|
||||
oo::objdefine O1 method m1 {} {
|
||||
puts [mc Hi!]
|
||||
}
|
||||
}
|
||||
.CE
|
||||
.PP
|
||||
.VE tip490
|
||||
.SH EXAMPLES
|
||||
.SS Examples
|
||||
Packages which display a GUI may update their widgets when the global locale changes.
|
||||
To register to a callback, use:
|
||||
.CS
|
||||
@@ -794,9 +643,9 @@ proc ::tcl::clock::LocalizeFormat { locale format } {
|
||||
.PP
|
||||
The message catalog code was developed by Mark Harrison.
|
||||
.SH "SEE ALSO"
|
||||
format(n), scan(n), namespace(n), package(n), oo::class(n), oo::object
|
||||
format(n), scan(n), namespace(n), package(n)
|
||||
.SH KEYWORDS
|
||||
internationalization, i18n, localization, l10n, message, text, translation, class, object
|
||||
internationalization, i18n, localization, l10n, message, text, translation
|
||||
.\" Local Variables:
|
||||
.\" mode: nroff
|
||||
.\" End:
|
||||
|
||||
@@ -9,45 +9,25 @@
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
my, myclass \- invoke any method of current object or its class
|
||||
my \- invoke any method of current object
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
package require TclOO
|
||||
|
||||
\fBmy\fI methodName\fR ?\fIarg ...\fR?
|
||||
\fBmyclass\fI methodName\fR ?\fIarg ...\fR?
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
The \fBmy\fR command is used to allow methods of objects to invoke methods
|
||||
of the object (or its class),
|
||||
.VS TIP478
|
||||
and he \fBmyclass\fR command is used to allow methods of objects to invoke
|
||||
methods of the current class of the object \fIas an object\fR.
|
||||
.VE TIP478
|
||||
In particular, the set of valid values for
|
||||
The \fBmy\fR command is used to allow methods of objects to invoke any method
|
||||
of the object (or its class). In particular, the set of valid values for
|
||||
\fImethodName\fR is the set of all methods supported by an object and its
|
||||
superclasses, including those that are not exported
|
||||
.VS TIP500
|
||||
and private methods of the object or class when used within another method
|
||||
defined by that object or class.
|
||||
.VE TIP500
|
||||
superclasses, including those that are not exported. The object upon which the
|
||||
method is invoked is always the one that is the current context of the method
|
||||
(i.e. the object that is returned by \fBself object\fR) from which the
|
||||
\fBmy\fR command is invoked.
|
||||
.PP
|
||||
The object upon which the method is invoked via \fBmy\fR is the one that owns
|
||||
the namespace that the \fBmy\fR command is contained in initially (\fBNB:\fR the link
|
||||
remains if the command is renamed), which is the currently invoked object by
|
||||
default.
|
||||
.VS TIP478
|
||||
Similarly, the object on which the method is invoked via \fBmyclass\fR is the
|
||||
object that is the current class of the object that owns the namespace that
|
||||
the \fBmyclass\fR command is contained in initially. As with \fBmy\fR, the
|
||||
link remains even if the command is renamed into another namespace, and
|
||||
defaults to being the manufacturing class of the current object.
|
||||
.VE TIP478
|
||||
.PP
|
||||
Each object has its own \fBmy\fR and \fBmyclass\fR commands, contained in its
|
||||
instance namespace.
|
||||
Each object has its own \fBmy\fR command, contained in its instance namespace.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
This example shows basic use of \fBmy\fR to use the \fBvariables\fR method of
|
||||
@@ -60,71 +40,16 @@ oo::class create c {
|
||||
puts [incr counter]
|
||||
}
|
||||
}
|
||||
|
||||
c create o
|
||||
o count \fI\(-> prints "1"\fR
|
||||
o count \fI\(-> prints "2"\fR
|
||||
o count \fI\(-> prints "3"\fR
|
||||
.CE
|
||||
.PP
|
||||
This example shows how you can use \fBmy\fR to make callbacks to private
|
||||
methods from outside the object (from a \fBtrace\fR), using
|
||||
\fBnamespace code\fR to enter the correct context. (See the \fBcallback\fR
|
||||
command for the recommended way of doing this.)
|
||||
.PP
|
||||
.CS
|
||||
oo::class create HasCallback {
|
||||
method makeCallback {} {
|
||||
return [namespace code {
|
||||
\fBmy\fR Callback
|
||||
}]
|
||||
}
|
||||
|
||||
method Callback {args} {
|
||||
puts "callback: $args"
|
||||
}
|
||||
}
|
||||
|
||||
set o [HasCallback new]
|
||||
trace add variable xyz write [$o makeCallback]
|
||||
set xyz "called" \fI\(-> prints "callback: xyz {} write"\fR
|
||||
.CE
|
||||
.PP
|
||||
.VS TIP478
|
||||
This example shows how to access a private method of a class from an instance
|
||||
of that class. (See the \fBclassmethod\fR declaration in \fBoo::define\fR for
|
||||
a higher level interface for doing this.)
|
||||
.PP
|
||||
.CS
|
||||
oo::class create CountedSteps {
|
||||
self {
|
||||
variable count
|
||||
method Count {} {
|
||||
return [incr count]
|
||||
}
|
||||
}
|
||||
method advanceTwice {} {
|
||||
puts "in [self] step A: [\fBmyclass\fR Count]"
|
||||
puts "in [self] step B: [\fBmyclass\fR Count]"
|
||||
}
|
||||
}
|
||||
|
||||
CountedSteps create x
|
||||
CountedSteps create y
|
||||
x advanceTwice \fI\(-> prints "in ::x step A: 1"\fR
|
||||
\fI\(-> prints "in ::x step B: 2"\fR
|
||||
y advanceTwice \fI\(-> prints "in ::y step A: 3"\fR
|
||||
\fI\(-> prints "in ::y step B: 4"\fR
|
||||
x advanceTwice \fI\(-> prints "in ::x step A: 5"\fR
|
||||
\fI\(-> prints "in ::x step B: 6"\fR
|
||||
y advanceTwice \fI\(-> prints "in ::y step A: 7"\fR
|
||||
\fI\(-> prints "in ::y step B: 8"\fR
|
||||
.CE
|
||||
.VE TIP478
|
||||
.SH "SEE ALSO"
|
||||
next(n), oo::object(n), self(n)
|
||||
.SH KEYWORDS
|
||||
method, method visibility, object, private method, public method
|
||||
|
||||
.\" Local variables:
|
||||
.\" mode: nroff
|
||||
.\" fill-column: 78
|
||||
|
||||
@@ -112,7 +112,6 @@ oo::class create theSuperclass {
|
||||
puts "in the superclass, args = $args"
|
||||
}
|
||||
}
|
||||
|
||||
oo::class create theSubclass {
|
||||
superclass theSuperclass
|
||||
method example {args} {
|
||||
@@ -122,7 +121,6 @@ oo::class create theSubclass {
|
||||
puts "after chaining from subclass"
|
||||
}
|
||||
}
|
||||
|
||||
theSubclass create obj
|
||||
oo::objdefine obj method example args {
|
||||
puts "per-object method, args = $args"
|
||||
@@ -169,7 +167,6 @@ oo::class create cache {
|
||||
\fI# Compute value, insert into cache, and return it\fR
|
||||
return [set ValueCache($key) [\fBnext\fR {*}$args]]
|
||||
}
|
||||
|
||||
method flushCache {} {
|
||||
my variable ValueCache
|
||||
unset ValueCache
|
||||
@@ -181,12 +178,10 @@ oo::class create cache {
|
||||
oo::object create demo
|
||||
oo::objdefine demo {
|
||||
mixin cache
|
||||
|
||||
method compute {a b c} {
|
||||
after 3000 \fI;# Simulate deep thought\fR
|
||||
return [expr {$a + $b * $c}]
|
||||
}
|
||||
|
||||
method compute2 {a b c} {
|
||||
after 3000 \fI;# Simulate deep thought\fR
|
||||
return [expr {$a * $b + $c}]
|
||||
|
||||
@@ -48,7 +48,3 @@ At least one \fB\-load\fR or \fB\-source\fR parameter must be given.
|
||||
package(n)
|
||||
.SH KEYWORDS
|
||||
auto-load, index, package, version
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
@@ -43,9 +43,6 @@ close $pipeline
|
||||
|
||||
.SH "SEE ALSO"
|
||||
exec(n), open(n)
|
||||
|
||||
.SH KEYWORDS
|
||||
file, pipeline, process identifier
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
platform \- System identification support code and utilities
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fBpackage require platform\fR ?\fB1.0.10\fR?
|
||||
\fBpackage require platform ?1.0.10?\fR
|
||||
.sp
|
||||
\fBplatform::generic\fR
|
||||
\fBplatform::identify\fR
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
platform::shell \- System identification support code and utilities
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fBpackage require platform::shell\fR ?\fB1.1.4\fR?
|
||||
\fBpackage require platform::shell ?1.1.4?\fR
|
||||
.sp
|
||||
\fBplatform::shell::generic \fIshell\fR
|
||||
\fBplatform::shell::identify \fIshell\fR
|
||||
@@ -55,7 +55,3 @@ This command returns the contents of \fBtcl_platform(platform)\fR for
|
||||
the specified Tcl shell.
|
||||
.SH KEYWORDS
|
||||
operating system, cpu architecture, platform, architecture
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" fill-column: 78
|
||||
'\" End:
|
||||
|
||||
+6
-6
@@ -12,9 +12,9 @@
|
||||
tcl::prefix \- facilities for prefix matching
|
||||
.SH SYNOPSIS
|
||||
.nf
|
||||
\fB::tcl::prefix all\fR \fItable string\fR
|
||||
\fB::tcl::prefix longest\fR \fItable string\fR
|
||||
\fB::tcl::prefix match\fR ?\fIoption ...\fR? \fItable string\fR
|
||||
\fB::tcl::prefix all\fR \fItable\fR \fIstring\fR
|
||||
\fB::tcl::prefix longest\fR \fItable\fR \fIstring\fR
|
||||
\fB::tcl::prefix match\fR \fI?option ...?\fR \fItable\fR \fIstring\fR
|
||||
.fi
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
@@ -22,17 +22,17 @@ tcl::prefix \- facilities for prefix matching
|
||||
This document describes commands looking up a prefix in a list of strings.
|
||||
The following commands are supported:
|
||||
.TP
|
||||
\fB::tcl::prefix all\fR \fItable string\fR
|
||||
\fB::tcl::prefix all\fR \fItable\fR \fIstring\fR
|
||||
.
|
||||
Returns a list of all elements in \fItable\fR that begin with the prefix
|
||||
\fIstring\fR.
|
||||
.TP
|
||||
\fB::tcl::prefix longest\fR \fItable string\fR
|
||||
\fB::tcl::prefix longest\fR \fItable\fR \fIstring\fR
|
||||
.
|
||||
Returns the longest common prefix of all elements in \fItable\fR that
|
||||
begin with the prefix \fIstring\fR.
|
||||
.TP
|
||||
\fB::tcl::prefix match\fR ?\fIoptions\fR? \fItable string\fR
|
||||
\fB::tcl::prefix match\fR ?\fIoptions\fR? \fItable\fR \fIstring\fR
|
||||
.
|
||||
If \fIstring\fR equals one element in \fItable\fR or is a prefix to exactly
|
||||
one element, the matched element is returned. If not, the result depends
|
||||
|
||||
-150
@@ -1,150 +0,0 @@
|
||||
'\"
|
||||
'\" Copyright (c) 2017 Frederic Bonnet.
|
||||
'\"
|
||||
'\" See the file "license.terms" for information on usage and redistribution
|
||||
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
'\"
|
||||
.TH process n 8.7 Tcl "Tcl Built-In Commands"
|
||||
.so man.macros
|
||||
.BS
|
||||
'\" Note: do not modify the .SH NAME line immediately below!
|
||||
.SH NAME
|
||||
tcl::process \- Subprocess management
|
||||
.SH SYNOPSIS
|
||||
\fB::tcl::process \fIoption \fR?\fIarg arg ...\fR?
|
||||
.BE
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
This command provides a way to manage subprocesses created by the \fBopen\fR
|
||||
and \fBexec\fR commands, as identified by the process identifiers (PIDs) of
|
||||
those subprocesses. The legal \fIoptions\fR (which may be abbreviated) are:
|
||||
.TP
|
||||
\fB::tcl::process autopurge\fR ?\fIflag\fR?
|
||||
.
|
||||
Automatic purge facility. If \fIflag\fR is specified as a boolean value then
|
||||
it activates or deactivate autopurge. In all cases it returns the current
|
||||
status as a boolean value. When autopurge is active,
|
||||
\fBTcl_ReapDetachedProcs\fR is called each time the \fBexec\fR command is
|
||||
executed or a pipe channel created by \fBopen\fR is closed. When autopurge is
|
||||
inactive, \fB::tcl::process\fR purge must be called explicitly. By default
|
||||
autopurge is active.
|
||||
.TP
|
||||
\fB::tcl::process list\fR
|
||||
.
|
||||
Returns the list of subprocess PIDs. This includes all currently executing
|
||||
subprocesses and all terminated subprocesses that have not yet had their
|
||||
corresponding process table entries purged.
|
||||
.TP
|
||||
\fB::tcl::process purge\fR ?\fIpids\fR?
|
||||
.
|
||||
Cleans up all data associated with terminated subprocesses. If \fIpids\fR is
|
||||
specified as a list of PIDs then the command only cleanup data for the matching
|
||||
subprocesses if they exist, and raises an error otherwise. If a process listed is
|
||||
still active, this command does nothing to that process.
|
||||
.TP
|
||||
\fB::tcl::process status\fR ?\fIswitches\fR? ?\fIpids\fR?
|
||||
.
|
||||
Returns a dictionary mapping subprocess PIDs to their respective status. If
|
||||
\fIpids\fR is specified as a list of PIDs then the command only returns the
|
||||
status of the matching subprocesses if they exist, and raises an error
|
||||
otherwise. For active processes, the status is an empty value. For terminated
|
||||
processes, the status is a list with the following format:
|
||||
.QW "\fB{\fIcode\fR ?\fImsg errorCode\fR?\fB}\fR" ,
|
||||
where:
|
||||
.RS
|
||||
.TP
|
||||
\fIcode\fR\0
|
||||
.
|
||||
is a standard Tcl return code, i.e., \fB0\fR for TCL_OK and \fB1\fR
|
||||
for TCL_ERROR,
|
||||
.TP
|
||||
\fImsg\fR\0
|
||||
.
|
||||
is the human-readable error message,
|
||||
.TP
|
||||
\fIerrorCode\fR\0
|
||||
.
|
||||
uses the same format as the \fBerrorCode\fR global variable
|
||||
.PP
|
||||
Note that \fBmsg\fR and \fBerrorCode\fR are only present for abnormally
|
||||
terminated processes (i.e. those where the \fIcode\fR is nonzero). Under the
|
||||
hood this command calls \fBTcl_WaitPid\fR with the \fBWNOHANG\fR flag set for
|
||||
non-blocking behavior, unless the \fB\-wait\fR switch is set (see below).
|
||||
.PP
|
||||
Additionally, \fB::tcl::process status\fR accepts the following switches:
|
||||
.TP
|
||||
\fB\-wait\fR\0
|
||||
.
|
||||
By default the command returns immediately (the underlying \fBTcl_WaitPid\fR is
|
||||
called with the \fBWNOHANG\fR flag set) unless this switch is set. If \fIpids\fR
|
||||
is specified as a list of PIDs then the command waits until the status of the
|
||||
matching subprocesses are available. If \fIpids\fR was not specified, this
|
||||
command will wait for all known subprocesses.
|
||||
.TP
|
||||
\fB\-\|\-\fR
|
||||
.
|
||||
Marks the end of switches. The argument following this one will
|
||||
be treated as the first \fIarg\fR even if it starts with a \fB\-\fR.
|
||||
.RE
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
These show the use of \fB::tcl::process\fR. Some of the results from
|
||||
\fB::tcl::process status\fR are split over multiple lines for readability.
|
||||
.PP
|
||||
.CS
|
||||
\fB::tcl::process autopurge\fR
|
||||
\fI\(-> true\fR
|
||||
\fB::tcl::process autopurge\fR false
|
||||
\fI\(-> false\fR
|
||||
|
||||
set pid1 [exec command1 a b c | command2 d e f &]
|
||||
\fI\(-> 123 456\fR
|
||||
set chan [open "|command1 a b c | command2 d e f"]
|
||||
\fI\(-> file123\fR
|
||||
set pid2 [pid $chan]
|
||||
\fI\(-> 789 1011\fR
|
||||
|
||||
\fB::tcl::process list\fR
|
||||
\fI\(-> 123 456 789 1011\fR
|
||||
|
||||
\fB::tcl::process status\fR
|
||||
\fI\(-> 123 0
|
||||
456 {1 "child killed: write on pipe with no readers" {
|
||||
CHILDKILLED 456 SIGPIPE "write on pipe with no readers"}}
|
||||
789 {1 "child suspended: background tty read" {
|
||||
CHILDSUSP 789 SIGTTIN "background tty read"}}
|
||||
1011 {}\fR
|
||||
|
||||
\fB::tcl::process status\fR 123
|
||||
\fI\(-> 123 0\fR
|
||||
|
||||
\fB::tcl::process status\fR 1011
|
||||
\fI\(-> 1011 {}\fR
|
||||
|
||||
\fB::tcl::process status\fR -wait
|
||||
\fI\(-> 123 0
|
||||
456 {1 "child killed: write on pipe with no readers" {
|
||||
CHILDKILLED 456 SIGPIPE "write on pipe with no readers"}}
|
||||
789 {1 "child suspended: background tty read" {
|
||||
CHILDSUSP 789 SIGTTIN "background tty read"}}
|
||||
1011 {1 "child process exited abnormally" {
|
||||
CHILDSTATUS 1011 -1}}\fR
|
||||
|
||||
\fB::tcl::process status\fR 1011
|
||||
\fI\(-> 1011 {1 "child process exited abnormally" {
|
||||
CHILDSTATUS 1011 -1}}\fR
|
||||
|
||||
\fB::tcl::process purge\fR
|
||||
exec command1 1 2 3 &
|
||||
\fI\(-> 1213\fR
|
||||
\fB::tcl::process list\fR
|
||||
\fI\(-> 1213\fR
|
||||
.CE
|
||||
.SH "SEE ALSO"
|
||||
exec(n), open(n), pid(n),
|
||||
Tcl_DetachPids(3), Tcl_WaitPid(3), Tcl_ReapDetachedProcs(3)
|
||||
.SH "KEYWORDS"
|
||||
background, child, detach, process, wait
|
||||
'\" Local Variables:
|
||||
'\" mode: nroff
|
||||
'\" End:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user