├── win
├── gitmanifest.in
├── svnmanifest.in
├── sampleUuid.h.in
├── x86_64-w64-mingw32-nmakehlp.exe
├── makefile.vc
├── targets.vc
├── rules-ext.vc
└── nmakehlp.c
├── .fossil-settings
├── manifest
├── crlf-glob
├── crnl-glob
├── binary-glob
└── ignore-glob
├── tea.pdf
├── aclocal.m4
├── .project
├── pkgIndex.tcl.in
├── tea
├── toman.tcl
├── codingstyle.txt
├── introduction.txt
├── app_config_options.txt
├── stubs.txt
├── app_makefiles.txt
├── writingdocs.txt
├── writingtests.txt
├── packages.txt
├── makefiles.txt
└── design.txt
├── tests
├── sample.test
├── tclsample.test
└── all.tcl
├── generic
├── sample.h
├── sample.c
└── tclsample.c
├── .github
└── workflows
│ └── linux-build.yml
├── license.terms
├── doc
├── sha1.n
└── man.macros
├── README.sha
├── README
├── .travis.yml
├── configure.ac
├── Makefile.in
└── ChangeLog
/win/gitmanifest.in:
--------------------------------------------------------------------------------
1 | git-
--------------------------------------------------------------------------------
/win/svnmanifest.in:
--------------------------------------------------------------------------------
1 | svn-r
--------------------------------------------------------------------------------
/.fossil-settings/manifest:
--------------------------------------------------------------------------------
1 | u
2 |
--------------------------------------------------------------------------------
/.fossil-settings/crlf-glob:
--------------------------------------------------------------------------------
1 | win/*.vc
2 |
--------------------------------------------------------------------------------
/.fossil-settings/crnl-glob:
--------------------------------------------------------------------------------
1 | win/*.vc
2 |
--------------------------------------------------------------------------------
/win/sampleUuid.h.in:
--------------------------------------------------------------------------------
1 | #define SAMPLE_VERSION_UUID \
2 |
--------------------------------------------------------------------------------
/.fossil-settings/binary-glob:
--------------------------------------------------------------------------------
1 | *.bmp
2 | *.gif
3 | *.png
4 |
--------------------------------------------------------------------------------
/tea.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tcltk/sampleextension/main/tea.pdf
--------------------------------------------------------------------------------
/win/x86_64-w64-mingw32-nmakehlp.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tcltk/sampleextension/main/win/x86_64-w64-mingw32-nmakehlp.exe
--------------------------------------------------------------------------------
/aclocal.m4:
--------------------------------------------------------------------------------
1 | #
2 | # Include the TEA standard macro set
3 | #
4 |
5 | builtin(include,tclconfig/tcl.m4)
6 |
7 | #
8 | # Add here whatever m4 macros you want to define for your package
9 | #
10 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | sampleextension
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.fossil-settings/ignore-glob:
--------------------------------------------------------------------------------
1 | *.a
2 | *.dll
3 | *.dylib
4 | *.exe
5 | *.exp
6 | *.lib
7 | *.o
8 | *.obj
9 | *.res
10 | *.sl
11 | *.so
12 | Makefile
13 | config.cache
14 | config.log
15 | config.status
16 | pkgIndex.tcl
17 | */versions.vc
18 | win/Release*
19 | win/Debug*
20 | win/nmhlp-out.txt
21 | tclconfig/*
22 | *~
--------------------------------------------------------------------------------
/pkgIndex.tcl.in:
--------------------------------------------------------------------------------
1 | # -*- tcl -*-
2 | # Tcl package index file, version 1.1
3 | #
4 | if {[package vsatisfies [package provide Tcl] 9.0-]} {
5 | package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \
6 | [list load [file join $dir @PKG_LIB_FILE9@] [string totitle @PACKAGE_NAME@]]
7 | } else {
8 | package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \
9 | [list load [file join $dir @PKG_LIB_FILE8@] [string totitle @PACKAGE_NAME@]]
10 | }
11 |
--------------------------------------------------------------------------------
/tea/toman.tcl:
--------------------------------------------------------------------------------
1 | # Small script to assemble the separate chapters to a single file
2 | #
3 | proc putfile {filename} {
4 | set infile [open $filename]
5 | puts $::outfile [read $infile]
6 | close $infile
7 | }
8 |
9 | set outfile [open "teadoc.man" "w"]
10 |
11 | puts $outfile \
12 | {[manpage_begin {TEA documentation} n 0.2]
13 | [moddesc TEA]
14 | [titledesc {TEA documentation}]}
15 |
16 | putfile introduction.txt
17 | putfile design.txt
18 | putfile codingstyle.txt
19 | putfile packages.txt
20 | putfile stubs.txt
21 | putfile makefiles.txt
22 | putfile writingtests.txt
23 | putfile writingdocs.txt
24 | putfile app_makefiles.txt
25 | putfile app_config_options.txt
26 |
27 | puts $outfile {[manpage_end]}
28 | close $outfile
29 |
30 |
--------------------------------------------------------------------------------
/tests/sample.test:
--------------------------------------------------------------------------------
1 | # Commands covered: sha1
2 | #
3 | # This file contains a collection of tests for one or more of the Tcl
4 | # built-in commands. Sourcing this file into Tcl runs the tests and
5 | # generates output for errors. No output means no errors were found.
6 | #
7 | # Copyright (c) 2000 by Scriptics Corporation.
8 | #
9 | # See the file "license.terms" for information on usage and redistribution
10 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 |
12 | if {[lsearch [namespace children] ::tcltest] == -1} {
13 | package require tcltest
14 | namespace import ::tcltest::*
15 | }
16 |
17 | package require sample
18 |
19 | test sha-1.1 {Use of -string operand} {
20 | set result [sha1 -string foo]
21 | } {0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33}
22 |
23 | test sha-1.2 {Use of -init operand} {
24 | set result [catch {sha1 -init}]
25 | } {0}
26 |
27 |
28 | # cleanup
29 | ::tcltest::cleanupTests
30 | return
31 |
--------------------------------------------------------------------------------
/tests/tclsample.test:
--------------------------------------------------------------------------------
1 | # Commands covered: sha1
2 | #
3 | # This file contains a collection of tests for one or more of the Tcl
4 | # built-in commands. Sourcing this file into Tcl runs the tests and
5 | # generates output for errors. No output means no errors were found.
6 | #
7 | # Copyright (c) 2000 by Scriptics Corporation.
8 | #
9 | # See the file "license.terms" for information on usage and redistribution
10 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 |
12 | if {[lsearch [namespace children] ::tcltest] == -1} {
13 | package require tcltest
14 | namespace import ::tcltest::*
15 | }
16 |
17 | package require sample
18 |
19 | test sha-1.1 {incorrect command usage} {
20 | list [catch {sha1} errMsg] $errMsg
21 | } {1 {wrong # args: should be either:
22 | sha1 ?-log2base log2base? -string string
23 | or
24 | sha1 ?-log2base log2base? ?-copychan chanID? -chan chanID
25 | or
26 | sha1 -init (returns descriptor)
27 | sha1 -update descriptor ?-maxbytes n? ?-copychan chanID? -chan chanID
28 | (any number of -update calls, returns number of bytes read)
29 | sha1 ?-log2base log2base? -final descriptor
30 | The default log2base is 4 (hex)}}
31 |
32 | test sha-1.2 {incorrect usage of -log2base option} {
33 | list [catch {sha1 -log2base 0 -string foo} errMsg] $errMsg
34 | } {1 {parameter to -log2base "0" must be integer in range 1...6}}
35 |
36 | # cleanup
37 | ::tcltest::cleanupTests
38 | return
39 |
--------------------------------------------------------------------------------
/generic/sample.h:
--------------------------------------------------------------------------------
1 | /*
2 | * sample.h --
3 | *
4 | * This header file contains the function declarations needed for
5 | * all of the source files in this package.
6 | *
7 | * Copyright (c) 1998-1999 Scriptics Corporation.
8 | * Copyright (c) 2003 ActiveState Corporation.
9 | *
10 | * See the file "license.terms" for information on usage and redistribution
11 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 | *
13 | */
14 |
15 | #ifndef _SAMPLE
16 | #define _SAMPLE
17 |
18 | #include
19 |
20 | #ifdef HAVE_INTTYPES_H
21 | # include
22 | typedef uint32_t sha_uint32_t;
23 | #else
24 | # if ((1<<31)<0)
25 | typedef unsigned long sha_uint32_t;
26 | # else
27 | typedef unsigned int sha_uint32_t;
28 | # endif
29 | #endif
30 |
31 |
32 | /*
33 | * For C++ compilers, use extern "C"
34 | */
35 |
36 | #ifdef __cplusplus
37 | extern "C" {
38 | #endif
39 |
40 | typedef struct {
41 | sha_uint32_t state[5];
42 | sha_uint32_t count[2];
43 | unsigned char buffer[64];
44 | } SHA1_CTX;
45 |
46 | MODULE_SCOPE void SHA1Init(SHA1_CTX* context);
47 | MODULE_SCOPE void SHA1Update(SHA1_CTX* context, unsigned char* data, Tcl_Size len);
48 | MODULE_SCOPE void SHA1Final(SHA1_CTX* context, unsigned char digest[20]);
49 |
50 | /*
51 | * Only the _Init function is exported.
52 | */
53 |
54 | extern DLLEXPORT int Sample_Init(Tcl_Interp * interp);
55 |
56 | /*
57 | * end block for C++
58 | */
59 |
60 | #ifdef __cplusplus
61 | }
62 | #endif
63 |
64 | #endif /* _SAMPLE */
65 |
--------------------------------------------------------------------------------
/.github/workflows/linux-build.yml:
--------------------------------------------------------------------------------
1 | name: Linux
2 | on: [push]
3 | permissions:
4 | contents: read
5 | defaults:
6 | run:
7 | shell: bash
8 | jobs:
9 | build:
10 | runs-on: ubuntu-24.04
11 | strategy:
12 | matrix:
13 | compiler:
14 | - "gcc"
15 | - "g++"
16 | - "clang"
17 | steps:
18 | - name: Checkout
19 | uses: actions/checkout@v4
20 | - name: Setup Environment (compiler=${{ matrix.compiler }})
21 | run: |
22 | sudo apt-get install tcl8.6-dev
23 | mkdir "$HOME/install dir"
24 | curl https://core.tcl-lang.org/tclconfig/tarball/main/tclconfig.tar.gz >tclconfig.tar.gz
25 | tar xfz tclconfig.tar.gz
26 | echo "CFGOPT=--with-tcl=/usr/lib/tcl8.6" >> $GITHUB_ENV
27 | echo "CC=$COMPILER" >> $GITHUB_ENV
28 | env:
29 | COMPILER: ${{ matrix.compiler }}
30 | OPTS: ${{ matrix.compiler }}
31 | - name: Configure
32 | run: |
33 | ./configure $CFGOPT "--prefix=$HOME/install dir" "--exec-prefix=$HOME/install dir" || {
34 | cat config.log
35 | echo "::error::Failure during Configure"
36 | exit 1
37 | }
38 | - name: Build
39 | run: |
40 | make || {
41 | echo "::error::Failure during Build"
42 | exit 1
43 | }
44 | - name: Run Tests
45 | run: |
46 | make test || {
47 | echo "::error::Failure during Test"
48 | exit 1
49 | }
50 | env:
51 | ERROR_ON_FAILURES: 1
52 | - name: Test-Drive Installation
53 | run: |
54 | make install || {
55 | echo "::error::Failure during Install"
56 | exit 1
57 | }
58 | - name: Create Distribution Package
59 | run: |
60 | make dist || {
61 | echo "::error::Failure during Distribute"
62 | exit 1
63 | }
64 |
--------------------------------------------------------------------------------
/tea/codingstyle.txt:
--------------------------------------------------------------------------------
1 | [section {Chapter 3. RECOMMENDED CODING STYLE}]
2 |
3 | We do not want to say too much about coding style, and certainly we do
4 | not want to prescribe any particular style. Just make sure for yourself
5 | that:
6 | [list_begin bullet]
7 |
8 | [bullet]
9 | you have added appropriate and clear comments to the code
10 |
11 | [bullet]
12 | you have used well-defined and clear constructs, not too many C macros
13 | and such, which can make it difficult to understand the code
14 |
15 | [bullet]
16 | you do not rely on compiler-specific features (extensions to the
17 | standard language that are very uncommon for instance)
18 |
19 | [bullet]
20 | you dare show it to other people, as other people will definitely see
21 | it and read your code.
22 |
23 | [list_end]
24 |
25 | A very good example of coding style is Tcl itself: the code is
26 | well-documented, the layout is clean, with a bit of study you can really
27 | understand what is going on. More textual descriptions of a
28 | recommended coding style for C and for Tcl can be found in:
29 | ....
30 |
31 | [para]
32 | We can add a few conventions here, almost trivial, perhaps, but since
33 | they are very often used, it will help people to understand your code
34 | better:
35 |
36 | [list_begin bullet]
37 |
38 | [bullet]
39 | For the use of namespaces (highly recommended to avoid name clashes),
40 | read the tutorial by Will Duquette.
41 |
42 | [bullet]
43 | Avoid the use of global variables, use namespace variables instead.
44 |
45 | [bullet]
46 | For "public" routines use names that start with a lowercase letter
47 | and add these to a [namespace export] command
48 |
49 | [bullet]
50 | For "private" routines use names that start with an uppercase letter
51 |
52 | [list_end]
53 |
54 | If you implement your extension in C, remember to use the Tcl_Obj
55 | interface: it is much faster than the old pre-8.0 interface that used
56 | strings. This means that you may need to pay quite some attention to
57 | issues like reference counts, but it is certainly worth the effort.
58 |
--------------------------------------------------------------------------------
/tea/introduction.txt:
--------------------------------------------------------------------------------
1 | [comment {
2 | Remarks:
3 | - What makes tkimg special - its own stubs - why?
4 | }]
5 |
6 | [description]
7 | The Tcl Extension Architecture is meant to help developers set up a
8 | standardised environment so that any user can compile the extension
9 | without any knowledge of the extension. This way a lot of work can be
10 | saved.
11 |
12 | This document describes the various aspects of TEA in detail.
13 |
14 | [section {Chapter 1. OVERVIEW}]
15 |
16 | TEA relies heavily on the GNU tool [emph autoconf]. An intimate
17 | knowledge of this tool is, fortunately, not required, but for complicated
18 | extensions that rely on many things specific to a particular platform,
19 | it may be necessary to add your own checks and procedures to the
20 | existing TEA macro library.
21 |
22 | The structure of this document is as follows:
23 | [sectref {Chapter 2. DESIGN AND CODING}] describes the typical
24 | organisation in files and directories of an extension.
25 |
26 | [para]
27 | [sectref {Chapter 3. RECOMMENDED CODING STYLE}] holds information
28 | about what you should and should not do when coding an extension.
29 |
30 | [para]
31 | [sectref {Chapter 4. TCL PACKAGES}] highlights the package mechanism
32 | that is used by Tcl, whereas [sectref {Chapter 5. TCL STUBS}] explains
33 | the stubs mechanism, important for creating compiled extensions that are
34 | independent of the particular Tcl version.
35 |
36 | [para]
37 | [sectref {Chapter 6. CONFIGURE AND MAKE FILES}] is perhaps the most
38 | important chapter, as this describes how to create the input for the
39 | [emph autoconf] tool.
40 |
41 | [para]
42 | The subjects of [sectref {Chapter 7. WRITING AND RUNNING TESTS}] and
43 | [sectref {Chapter 8. DOCUMENTATION}] may not among most programmers'
44 | favourites, but they are very important to users. And everybody at some
45 | point is a user!
46 |
47 | [para]
48 | [sectref {Appendix A. Explanation of make files and the make utility}]
49 | is meant especially for those programmers not familiar to
50 | make files, because their development environment shields the
51 | complexities from them.
52 |
--------------------------------------------------------------------------------
/tests/all.tcl:
--------------------------------------------------------------------------------
1 | # all.tcl --
2 | #
3 | # This file contains a top-level script to run all of the Tcl
4 | # tests. Execute it by invoking "source all.test" when running tcltest
5 | # in this directory.
6 | #
7 | # Copyright (c) 1998-2000 by Scriptics Corporation.
8 | # All rights reserved.
9 |
10 | if {[lsearch [namespace children] ::tcltest] == -1} {
11 | package require tcltest
12 | namespace import ::tcltest::*
13 | }
14 |
15 | set ::tcltest::testSingleFile false
16 | set ::tcltest::testsDirectory [file dir [info script]]
17 |
18 | # We need to ensure that the testsDirectory is absolute
19 | if {[catch {::tcltest::normalizePath ::tcltest::testsDirectory}]} {
20 | # The version of tcltest we have here does not support
21 | # 'normalizePath', so we have to do this on our own.
22 |
23 | set oldpwd [pwd]
24 | catch {cd $::tcltest::testsDirectory}
25 | set ::tcltest::testsDirectory [pwd]
26 | cd $oldpwd
27 | }
28 |
29 | set chan $::tcltest::outputChannel
30 |
31 | puts $chan "Tests running in interp: [info nameofexecutable]"
32 | puts $chan "Tests running with pwd: [pwd]"
33 | puts $chan "Tests running in working dir: $::tcltest::testsDirectory"
34 | if {[llength $::tcltest::skip] > 0} {
35 | puts $chan "Skipping tests that match: $::tcltest::skip"
36 | }
37 | if {[llength $::tcltest::match] > 0} {
38 | puts $chan "Only running tests that match: $::tcltest::match"
39 | }
40 |
41 | if {[llength $::tcltest::skipFiles] > 0} {
42 | puts $chan "Skipping test files that match: $::tcltest::skipFiles"
43 | }
44 | if {[llength $::tcltest::matchFiles] > 0} {
45 | puts $chan "Only sourcing test files that match: $::tcltest::matchFiles"
46 | }
47 |
48 | set timeCmd {clock format [clock seconds]}
49 | puts $chan "Tests began at [eval $timeCmd]"
50 |
51 | # source each of the specified tests
52 | foreach file [lsort [::tcltest::getMatchingFiles]] {
53 | set tail [file tail $file]
54 | puts $chan $tail
55 | if {[catch {source $file} msg]} {
56 | puts $chan $msg
57 | }
58 | }
59 |
60 | # cleanup
61 | puts $chan "\nTests ended at [eval $timeCmd]"
62 | ::tcltest::cleanupTests 1
63 | return
64 |
65 |
--------------------------------------------------------------------------------
/license.terms:
--------------------------------------------------------------------------------
1 | This software is copyrighted by the Scriptics Corporation, and other
2 | parties. The following terms apply to all files associated with the
3 | software unless explicitly disclaimed in individual files.
4 |
5 | The authors hereby grant permission to use, copy, modify, distribute,
6 | and license this software and its documentation for any purpose, provided
7 | that existing copyright notices are retained in all copies and that this
8 | notice is included verbatim in any distributions. No written agreement,
9 | license, or royalty fee is required for any of the authorized uses.
10 | Modifications to this software may be copyrighted by their authors
11 | and need not follow the licensing terms described here, provided that
12 | the new terms are clearly indicated on the first page of each file where
13 | they apply.
14 |
15 | IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
16 | FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
17 | ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
18 | DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
19 | POSSIBILITY OF SUCH DAMAGE.
20 |
21 | THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
22 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
24 | IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
25 | NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
26 | MODIFICATIONS.
27 |
28 | GOVERNMENT USE: If you are acquiring this software on behalf of the
29 | U.S. government, the Government shall have only "Restricted Rights"
30 | in the software and related documentation as defined in the Federal
31 | Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
32 | are acquiring the software on behalf of the Department of Defense, the
33 | software shall be classified as "Commercial Computer Software" and the
34 | Government shall have only "Restricted Rights" as defined in Clause
35 | 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
36 | authors grant the U.S. Government and others acting in its behalf
37 | permission to use and distribute the software in accordance with the
38 | terms specified in this license.
39 |
--------------------------------------------------------------------------------
/win/makefile.vc:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------- -*- makefile -*-
2 | #
3 | # Sample makefile for building Tcl extensions.
4 | #
5 | # Basic build, test and install
6 | # nmake /f makefile.vc INSTALLDIR=c:\path\to\tcl
7 | # nmake /f makefile.vc INSTALLDIR=c:\path\to\tcl test
8 | # nmake /f makefile.vc INSTALLDIR=c:\path\to\tcl install
9 | #
10 | # For other build options (debug, static etc.),
11 | # See TIP 477 (https://core.tcl-lang.org/tips/doc/main/tip/477.md) for
12 | # detailed documentation.
13 | #
14 | # See the file "license.terms" for information on usage and redistribution
15 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 | #
17 | #------------------------------------------------------------------------------
18 |
19 | # The name of the package
20 | PROJECT = sample
21 |
22 | !include "rules-ext.vc"
23 |
24 | # Define the object files and resource file that make up the extension.
25 | # Note the resource file does not makes sense if doing a static library build
26 | # hence it is under that condition. TMP_DIR is the output directory
27 | # defined by rules for object files.
28 | PRJ_OBJS = \
29 | $(TMP_DIR)\tclsample.obj \
30 | $(TMP_DIR)\sample.obj
31 |
32 | # Define any additional compiler flags that might be required for the project
33 | PRJ_DEFINES = -D_CRT_SECURE_NO_DEPRECATE
34 | PRJ_DEFINES = $(PRJ_DEFINES) -I$(TMP_DIR)
35 |
36 | # Define the standard targets
37 | !include "$(_RULESDIR)\targets.vc"
38 |
39 | # We must define a pkgindex target that will create a pkgIndex.tcl
40 | # file in the $(OUT_DIR) directory. We can just redirect to the
41 | # default-pkgindex target for our sample extension.
42 | pkgindex: default-pkgindex
43 |
44 | $(ROOT)\manifest.uuid:
45 | copy $(WIN_DIR)\gitmanifest.in $(ROOT)\manifest.uuid
46 | git rev-parse HEAD >>$(ROOT)\manifest.uuid
47 |
48 | $(TMP_DIR)\sampleUuid.h: $(ROOT)\manifest.uuid
49 | copy $(WIN_DIR)\sampleUuid.h.in+$(ROOT)\manifest.uuid $(TMP_DIR)\sampleUuid.h
50 |
51 |
52 | # The default install target only installs binaries and scripts so add
53 | # an additional target for our documentation. Note this *adds* a target
54 | # since no commands are listed after it. The original targets for
55 | # install (from targets.vc) will remain.
56 | install: default-install-docs-n
57 |
58 | # Explicit dependency rules
59 | $(GENERICDIR)\tclsample.c : $(GENERICDIR)\sample.h $(TMP_DIR)\sampleUuid.h
60 |
--------------------------------------------------------------------------------
/doc/sha1.n:
--------------------------------------------------------------------------------
1 | '\"
2 | .so man.macros
3 | .TH sha1 n 4.1 "Tcl-Extensions"
4 | .HS sha1 tcl
5 | .BS
6 | '\" Note: do not modify the .SH NAME line immediately below!
7 | .SH NAME
8 | sha1 \- manipulate sha1 message digests
9 | .SH SYNOPSIS
10 | \fBpackage require sample\fR ?\fB0.6\fR?
11 | .sp
12 | \fBsha1\fR ?\fB\-log2base \fIlog2base\fR? \fB\-string \fIstring\fR
13 | .br
14 | or
15 | .br
16 | \fBsha1\fR ?\fB\-log2base \fIlog2base\fR? ?\fB\-copychan \fIcopyChanID\fR? \fB\-chan \fIchanID\fR
17 | .br
18 | or
19 | .br
20 | \fBsha1 \-init\fR (returns descriptor)
21 | .br
22 | \fBsha1 \-update \fIdescriptor\fR ?\fB\-maxbytes \fIn\fR? ?\fB\-copychan \fIchanID\fR? \fB\-chan \fIchanID\fR
23 | .br
24 | \fBsha1\fR ?\fB\-log2base \fIlog2base\fR? \fB\-final \fIdescriptor\fR
25 | .BE
26 | .SH DESCRIPTION
27 | .PP
28 | SHA1 is NIST's Secure Hashing Algorithm (also known as Secure Hashing
29 | Standard) with the minor modification that they proposed on 7/11/94.
30 | .PP
31 | Switches can be in any order.
32 | .PP
33 | Returns a sha1 digest in base 2 ** log2base ascii representation.
34 | log2base defaults to 4, i.e., hex representation.
35 | .PP
36 | .nf
37 | \fBlog2base length chars\fR
38 | 1 160 01 \fI(binary)\fR
39 | 2 80 0..3
40 | 3 54 0...7 \fI(octal)\fR
41 | 4 40 0..9a..f \fI(hex)\fR
42 | 5 32 0..9a..v
43 | 6 27 0..9a..zA..Z_,
44 | .fi
45 | .PP
46 | (The characters in the digest string have been chosen to be usable in
47 | filenames so that the sha1 command can be used, for example, to digest URLs
48 | into shorter strings for filenames in a cache.)
49 | .PP
50 | In the \fB\-string\fR version, returns sha1 digest alone of \fIstring\fR.
51 | .PP
52 | In the \fB\-chan\fR version, returns list of 2 items: length of data in
53 | \fIchanID\fR followed by sha1 digest of all data in \fIchanID\fR.
54 | \fIChanID\fR is identifier returned from "\fBopen\fR" for example. If
55 | \fB\-copychan\fR is supplied, will also copy all data from \fIchanID\fR to
56 | \fIcopychanID\fR.
57 | .PP
58 | In the third form, \fB\-init\fR returns a descriptor, \fB\-update\fR can be
59 | called any number of times with that descriptor and returns the number of
60 | bytes read, and \fB\-final\fR returns the result in the same form as the
61 | standalone \fB\-chan\fR.
62 | '\" Local Variables:
63 | '\" mode: nroff
64 | '\" fill-column: 78
65 | '\" End:
66 |
--------------------------------------------------------------------------------
/README.sha:
--------------------------------------------------------------------------------
1 | sha1 - manipulate sha1 message digests
2 |
3 | SHA1 is NIST's Secure Hashing Algorithm (also known as Secure Hashing
4 | Standard) with the minor modification that they proposed on 7/11/94.
5 |
6 | To make type:
7 |
8 | ./configure
9 | make
10 | make install
11 |
12 | The configure script will deduce $PREFIX from the tcl installation.
13 | The generated Makefile uses the file $PREFIX/lib/tclConfig.sh that was left by
14 | the make of tcl for most of its configuration parameters.
15 |
16 | The Makefile generates pkgIndex.tcl files that are compatible with
17 | tcl7.6. If you are using tcl7.5 then you will need to edit
18 | $PREFIX/lib/pkgIndex.tcl by hand.
19 |
20 | Usage:
21 |
22 | sha1 ?-log2base log2base? -string string
23 |
24 | or
25 |
26 | sha1 ?-log2base log2base? ?-copychan chanID? -chan chanID
27 |
28 | or
29 |
30 | sha1 -init (returns descriptor)
31 | sha1 -update descriptor ?-maxbytes n? ?-copychan chanID? -chan chanID
32 | sha1 ?-log2base log2base? -final descriptor
33 |
34 |
35 | Switches can be in any order.
36 |
37 | Returns a sha1 digest in base 2 ** log2base ascii representation.
38 | log2base defaults to 4, i.e. hex representation.
39 |
40 | log2base length chars
41 | 1 160 01 (binary)
42 | 2 80 0..3
43 | 3 54 0...7 (octal)
44 | 4 40 0..9a..f (hex)
45 | 5 32 0..9a..v
46 | 6 27 0..9a..zA..Z_,
47 |
48 | (The characters in the digest string have been chosen to be usable in
49 | filenames so that the sha1 command can be used, for example,
50 | to digest URLs into shorter strings for filenames in a cache.)
51 |
52 | In the -string version, returns sha1 digest of string.
53 |
54 | In the -chan version, returns list of 2 items: length of data
55 | in chanID followed by sha1 digest of all data in chanID. ChanID is
56 | identifier returned from "open" for example. If -copychan is supplied,
57 | will also copy all data from chanID to copychanID.
58 |
59 | In the third form, -init returns a descriptor, -update can be called
60 | any number of times with that descriptor and returns the number of
61 | bytes read, and -final returns the result in the same form as the
62 | standalone -chan.
63 |
64 | Written by: John Ellson (ellson@lucent.com)
65 | modified by: Dave Dykstra (dwd@bell-labs.com)
66 |
67 | Use at your own risk. No support. No copyright.
68 |
--------------------------------------------------------------------------------
/tea/app_config_options.txt:
--------------------------------------------------------------------------------
1 | [section {Appendix B. Configuration options}]
2 |
3 | The [emph configure] script as generated by Autoconf will support a
4 | number of standard configuration options as well as any that you define
5 | for your extension via the [emph AC_ARG_WITH] and [emph AC_ARG_ENABLE]
6 | macros.
7 | [para]
8 | The table below describes the standard configuration options (most of the
9 | text is copied from B. Welch's book "Practical Tcl and Tk programming", 3rd edition)
10 |
11 | [list_begin bullet]
12 |
13 | [bullet]
14 | --prefix=[emph dir]
15 | [nl]
16 | Defines the root of the installation directory - default: /usr/local.
17 |
18 | [bullet]
19 | --exec-prefix=[emph dir]
20 | [nl]
21 | Defines the root of the installation directory for platform-specific files
22 | - default: the value of "--prefix".
23 |
24 | [bullet]
25 | --enable-gcc/--disable-gcc (default)
26 | [nl]
27 | Use the [emph gcc] compiler instead of the native (enable) or use
28 | the native compiler (disable).
29 |
30 | [bullet]
31 | --enable-shared (default)/--disable-shared
32 | [nl]
33 | Compile and link to get [emph {shared/dynamic}] libraries (enable) or compile and link
34 | to get [emph {archive/static}] libraries (disable).
35 |
36 | [bullet]
37 | --enable-symbols/--disable-symbols (default)
38 | [nl]
39 | Compile and link for debugging (enable) or compile and link without debugging (disable).
40 |
41 | [bullet]
42 | --enable-threads/--disable-threads (default)
43 | [nl]
44 | Turn multithreading support on (enable) or off (disable).
45 |
46 | [bullet]
47 | --with-tcl=[emph dir]
48 | [nl]
49 | Specifies the directory where Tcl was built (especially important if you build against
50 | a number of Tcl versions or for more than one platform)
51 |
52 | [bullet]
53 | --with-tk=[emph dir]
54 | [nl]
55 | Specifies the directory where Tk was built
56 |
57 | [bullet]
58 | --with-tclinclude=[emph dir]
59 | [nl]
60 | Specifies the directory where the Tcl include files can be found (notably: tcl.h)
61 |
62 | [bullet]
63 | --with-tcllib=[emph dir]
64 | [nl]
65 | Specifies the directory where the Tcl libraries can be found (notably: libtclstubs.a)
66 |
67 | [bullet]
68 | --with-x11include=[emph dir]
69 | [nl]
70 | Specifies the directory where the X11 include files (such as X11.h) can be found (especially important
71 | if these are not found in one of the usual places)
72 |
73 | [bullet]
74 | --with-x11lib=[emph dir]
75 | [nl]
76 | Specifies the directory where the X11 libraries (e.g. libX11.so) can be found
77 |
78 | [list_end]
79 |
80 | Note that all of these options come with reasonable defaults, so that you only
81 | have to worry about them when the configure script terminates with some kind of
82 | error.
83 |
--------------------------------------------------------------------------------
/win/targets.vc:
--------------------------------------------------------------------------------
1 | #------------------------------------------------------------- -*- makefile -*-
2 | # targets.vc --
3 | #
4 | # Part of the nmake based build system for Tcl and its extensions.
5 | # This file defines some standard targets for the convenience of extensions
6 | # and can be optionally included by the extension makefile.
7 | # See TIP 477 (https://core.tcl-lang.org/tips/doc/main/tip/477.md) for docs.
8 |
9 | $(PROJECT): setup pkgindex $(PRJLIB)
10 |
11 | !ifdef PRJ_STUBOBJS
12 | $(PROJECT): $(PRJSTUBLIB)
13 | $(PRJSTUBLIB): $(PRJ_STUBOBJS)
14 | $(LIBCMD) $**
15 |
16 | $(PRJ_STUBOBJS):
17 | $(CCSTUBSCMD) %s
18 | !endif # PRJ_STUBOBJS
19 |
20 | !ifdef PRJ_MANIFEST
21 | $(PROJECT): $(PRJLIB).manifest
22 | $(PRJLIB).manifest: $(PRJ_MANIFEST)
23 | @nmakehlp -s << $** >$@
24 | @MACHINE@ $(MACHINE:IX86=X86)
25 | <<
26 | !endif
27 |
28 | !if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk"
29 | $(PRJLIB): $(PRJ_OBJS) $(RESFILE)
30 | !if $(STATIC_BUILD)
31 | $(LIBCMD) $**
32 | !else
33 | $(DLLCMD) $**
34 | $(_VC_MANIFEST_EMBED_DLL)
35 | !endif
36 | -@del $*.exp
37 | !endif
38 |
39 | !if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != ""
40 | $(PRJ_OBJS): $(PRJ_HEADERS)
41 | !endif
42 |
43 | # If parent makefile has defined stub objects, add their installation
44 | # to the default install
45 | !if "$(PRJ_STUBOBJS)" != ""
46 | default-install: default-install-stubs
47 | !endif
48 |
49 | # Unlike the other default targets, these cannot be in rules.vc because
50 | # the executed command depends on existence of macro PRJ_HEADERS_PUBLIC
51 | # that the parent makefile will not define until after including rules-ext.vc
52 | !if "$(PRJ_HEADERS_PUBLIC)" != ""
53 | default-install: default-install-headers
54 | default-install-headers:
55 | @echo Installing headers to '$(INCLUDE_INSTALL_DIR)'
56 | @if not exist "$(INCLUDE_INSTALL_DIR)" $(MKDIR) "$(INCLUDE_INSTALL_DIR)"
57 | @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)"
58 | !endif
59 |
60 | !if "$(DISABLE_STANDARD_TARGETS)" == ""
61 | DISABLE_STANDARD_TARGETS = 0
62 | !endif
63 |
64 | !if "$(DISABLE_TARGET_setup)" == ""
65 | DISABLE_TARGET_setup = 0
66 | !endif
67 | !if "$(DISABLE_TARGET_install)" == ""
68 | DISABLE_TARGET_install = 0
69 | !endif
70 | !if "$(DISABLE_TARGET_clean)" == ""
71 | DISABLE_TARGET_clean = 0
72 | !endif
73 | !if "$(DISABLE_TARGET_test)" == ""
74 | DISABLE_TARGET_test = 0
75 | !endif
76 | !if "$(DISABLE_TARGET_shell)" == ""
77 | DISABLE_TARGET_shell = 0
78 | !endif
79 |
80 | !if !$(DISABLE_STANDARD_TARGETS)
81 | !if !$(DISABLE_TARGET_setup)
82 | setup: default-setup
83 | !endif
84 | !if !$(DISABLE_TARGET_install)
85 | install: default-install
86 | !endif
87 | !if !$(DISABLE_TARGET_clean)
88 | clean: default-clean
89 | realclean: hose
90 | hose: default-hose
91 | distclean: realclean default-distclean
92 | !endif
93 | !if !$(DISABLE_TARGET_test)
94 | test: default-test
95 | !endif
96 | !if !$(DISABLE_TARGET_shell)
97 | shell: default-shell
98 | !endif
99 | !endif # DISABLE_STANDARD_TARGETS
100 |
--------------------------------------------------------------------------------
/tea/stubs.txt:
--------------------------------------------------------------------------------
1 | [section {Chapter 5. TCL STUBS}]
2 |
3 | The highly recommended way of using the Tcl and Tk libraries in a
4 | compiled extension is via [emph stubs]. Stubs allow you to compile and
5 | link an extension and use it with any (later) version of Tcl/Tk. If you
6 | do not, then the libraries can only be used with a very specific version
7 | of Tcl/Tk. This chapter provides some information about what the
8 | advantages and disadvantages are of using stubs.
9 |
10 | [para]
11 | It may seem intimidating at first, but the stubs mechanism in Tcl
12 | (available since version 8.1) is actually very simple - from the point
13 | of view of the programmer:
14 | [list_begin bullet]
15 |
16 | [bullet]
17 | You use the call to Tcl_InitStubs() in the initialisation routine
18 | (see the previous chapter)
19 |
20 | [bullet]
21 | You define a macro USE_TCL_STUBS when compiling the code
22 |
23 | [bullet]
24 | You link against the Tcl and Tk stubs library, instead of the actual
25 | libraries.
26 |
27 | [list_end]
28 |
29 | (Needless to say that most is automatically taken care of by the TEA.)
30 |
31 | [para]
32 | Here is what stubs are all about: rather than using the functions in the
33 | Tcl/Tk libraries directly, you access them via a pointer. The actual
34 | code that is involved is hidden from you via C macros, so you have
35 | nothing to worry about, except for the USE_TCL_STUBS macro and the
36 | proper initialisation. More information can be found in ...
37 |
38 | [para]
39 | The limitations of using stubs are that you can only use the Tcl
40 | functions that are publically available in the stub table (see for
41 | details the header files tcl.h and tk.h). You can not use the private
42 | functions (found in the other header files), but this is a bad idea in
43 | the first place, because the interface to these functions may change
44 | from one release to the next - they are simply not meant for use outside
45 | the Tcl library itself.
46 |
47 | [para]
48 | The advantages of stubs are plenty:
49 |
50 | [list_begin bullet]
51 |
52 | [bullet]
53 | You can compile and link the extension against, say, Tcl 8.3 and use
54 | it in Tcl 8.5. That is: the libraries remain useful.
55 |
56 | [bullet]
57 | It is thus also practical to provide binary versions only (if you want
58 | or need to keep the source code secret)
59 |
60 | [bullet]
61 | Stub-enabled extensions can be used in Tclkit, as this relies heavily
62 | on the stub mechanism.
63 |
64 | [list_end]
65 |
66 | To summarise:
67 | [para]
68 | When you use the TEA, then the only thing you need to take care of in
69 | your code, is that the initialisation routine calls Tcl_InitStubs().
70 |
71 | [para]
72 | Using stubs gives benefits both to you and the users of your extension
73 | that can not be had in another way.
74 |
75 |
76 | [section {Providing your own stubs}]
77 |
78 | A more complicated situation arises when your extension itself defines a
79 | stubs library. This was discussed in some length in Chapter 2. The
80 | advantage is that your functions can be used at the C level too and
81 | would form a veritable extension to the Tcl/Tk API.
82 |
83 | [para]
84 | In the build step this means that besides the ordinary shared object
85 | or DLL also a stubs library must be created. The process is almost
86 | automatic, except that you have to tell which functions are to be made
87 | available in the stubs library (via the .decls file) and you have to
88 | make some provisions in the TEA configuration and make files.
89 |
90 | [para]
91 | If the functions of your extension are to be registered in the Tcl or Tk
92 | library, as is the case with tkimg that provides new formats for the
93 | photo command, then it is necessary or at least highly recommended that
94 | you provide them via the stubs mechanism.
95 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | This is a sample extension showing an implementation of the Tcl Extension
2 | Architecture (TEA). Please see the webpage
3 |
4 | http://www.tcl.tk/doc/tea/
5 |
6 | for more details on TEA. You can also read the enclosed "tea.pdf" document
7 | for instructions on how to adapt this sample extension to your extension.
8 |
9 | This package is a freely available open source package. You can do
10 | virtually anything you like with it, such as modifying it, redistributing
11 | it, and selling it either in whole or in part. See the file
12 | "license.terms" for complete information.
13 |
14 | CONTENTS
15 | ========
16 | The following is a short description of the files you will find in
17 | the sample extension.
18 |
19 | Makefile.in Makefile template. The configure script uses this file to
20 | produce the final Makefile.
21 |
22 | README This file
23 |
24 | README.sha A description of the extension itself.
25 |
26 | aclocal.m4 Generated file. Do not edit. Autoconf uses this as input
27 | when generating the final configure script. See "tcl.m4"
28 | below.
29 |
30 | configure Generated file. Do not edit. This must be regenerated
31 | anytime configure.ac or tclconfig/tcl.m4 changes.
32 |
33 | configure.ac Configure script template. Autoconf uses this file as input
34 | to produce the final configure script.
35 |
36 | pkgIndex.tcl.in Package index template. The configure script will use
37 | this file as input to create pkgIndex.tcl.
38 |
39 | sample.c Core Secure Hash Algorithm code.
40 |
41 | sample.h Header file for functions in the C files.
42 |
43 | sha1.n Unix nroff man page
44 |
45 | tclsample.c Implementation of new Tcl command "sha1".
46 |
47 | tea.pdf PDF file describing the current implementation of the
48 | Tcl Extension Architecture
49 |
50 | tclconfig/ This directory contains various template files that build
51 | the configure script. They should not need modification.
52 |
53 | install-sh Program used for copying binaries and script files
54 | to their install locations.
55 |
56 | tcl.m4 Collection of Tcl autoconf macros. Included by
57 | aclocal.m4 to define SC_* macros.
58 |
59 | UNIX BUILD
60 | ==========
61 |
62 | Building under most UNIX systems is easy, just run the configure script
63 | and then run make. For more information about the build process, see
64 | the tcl/unix/README file in the Tcl src dist. The following minimal
65 | example will install the extension in the /opt/tcl directory.
66 |
67 | $ cd sampleextension
68 | $ ./configure --prefix=/opt/tcl
69 | $ make
70 | $ make install
71 |
72 | WINDOWS BUILD
73 | =============
74 |
75 | The recommended method to build extensions under windows is to use the
76 | Msys + Mingw build process. This provides a Unix-style build while
77 | generating native Windows binaries. Using the Msys + Mingw build tools
78 | means that you can use the same configure script as per the Unix build
79 | to create a Makefile. See the tcl/win/README file for the URL of
80 | the Msys + Mingw download.
81 |
82 | If you have VC++ then you may wish to use the files in the win
83 | subdirectory and build the extension using just VC++. These files have
84 | been designed to be as generic as possible but will require some
85 | additional maintenance by the project developer to synchronise with
86 | the TEA configure.ac and Makefile.in files. Instructions for using the
87 | VC++ makefile are written in the first part of the Makefile.vc
88 | file.
89 |
90 | INSTALLATION
91 | ============
92 |
93 | The installation of a TEA package is structure like so:
94 |
95 | $exec_prefix
96 | / \
97 | lib bin
98 | | |
99 | PACKAGEx.y (dependent .dll files on Windows)
100 | |
101 | pkgIndex.tcl (.so|.dll files)
102 |
103 | The main .so|.dll library file gets installed in the versioned PACKAGE
104 | directory, which is OK on all platforms because it will be directly
105 | referenced with by 'load' in the pkgIndex.tcl file. Dependent DLL files on
106 | Windows must go in the bin directory (or other directory on the user's
107 | PATH) in order for them to be found.
108 |
--------------------------------------------------------------------------------
/win/rules-ext.vc:
--------------------------------------------------------------------------------
1 | # This file should only be included in makefiles for Tcl extensions,
2 | # NOT in the makefile for Tcl itself.
3 |
4 | !ifndef _RULES_EXT_VC
5 |
6 | # We need to run from the directory the parent makefile is located in.
7 | # nmake does not tell us what makefile was used to invoke it so parent
8 | # makefile has to set the MAKEFILEVC macro or we just make a guess and
9 | # warn if we think that is not the case.
10 | !if "$(MAKEFILEVC)" == ""
11 |
12 | !if exist("$(PROJECT).vc")
13 | MAKEFILEVC = $(PROJECT).vc
14 | !elseif exist("makefile.vc")
15 | MAKEFILEVC = makefile.vc
16 | !endif
17 | !endif # "$(MAKEFILEVC)" == ""
18 |
19 | !if !exist("$(MAKEFILEVC)")
20 | MSG = ^
21 | You must run nmake from the directory containing the project makefile.^
22 | If you are doing that and getting this message, set the MAKEFILEVC^
23 | macro to the name of the project makefile.
24 | !message WARNING: $(MSG)
25 | !endif
26 |
27 | !if "$(PROJECT)" == "tcl"
28 | !error The rules-ext.vc file is not intended for Tcl itself.
29 | !endif
30 |
31 | # We extract version numbers using the nmakehlp program. For now use
32 | # the local copy of nmakehlp. Once we locate Tcl, we will use that
33 | # one if it is newer.
34 | !if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
35 | !if [$(CC) -nologo -DNDEBUG "nmakehlp.c" -link -subsystem:console > nul]
36 | !endif
37 | !else
38 | !if [copy x86_64-w64-mingw32-nmakehlp.exe nmakehlp.exe >NUL]
39 | !endif
40 | !endif
41 |
42 | # First locate the Tcl directory that we are working with.
43 | !if "$(TCLDIR)" != ""
44 |
45 | _RULESDIR = $(TCLDIR:/=\)
46 |
47 | !else
48 |
49 | # If an installation path is specified, that is also the Tcl directory.
50 | # Also Tk never builds against an installed Tcl, it needs Tcl sources
51 | !if defined(INSTALLDIR) && "$(PROJECT)" != "tk"
52 | _RULESDIR=$(INSTALLDIR:/=\)
53 | !else
54 | # Locate Tcl sources
55 | !if [echo _RULESDIR = \> nmakehlp.out] \
56 | || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
57 | _RULESDIR = ..\..\tcl
58 | !else
59 | !include nmakehlp.out
60 | !endif
61 |
62 | !endif # defined(INSTALLDIR)....
63 |
64 | !endif # ifndef TCLDIR
65 |
66 | # Now look for the targets.vc file under the Tcl root. Note we check this
67 | # file and not rules.vc because the latter also exists on older systems.
68 | !if exist("$(_RULESDIR)\lib\nmake\targets.vc") # Building against installed Tcl
69 | _RULESDIR = $(_RULESDIR)\lib\nmake
70 | !elseif exist("$(_RULESDIR)\win\targets.vc") # Building against Tcl sources
71 | _RULESDIR = $(_RULESDIR)\win
72 | !else
73 | # If we have not located Tcl's targets file, most likely we are compiling
74 | # against an older version of Tcl and so must use our own support files.
75 | _RULESDIR = .
76 | !endif
77 |
78 | !if "$(_RULESDIR)" != "."
79 | # Potentially using Tcl's support files. If this extension has its own
80 | # nmake support files, need to compare the versions and pick newer.
81 |
82 | !if exist("rules.vc") # The extension has its own copy
83 |
84 | !if [echo TCL_RULES_MAJOR = \> versions.vc] \
85 | && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MAJOR >> versions.vc]
86 | !endif
87 | !if [echo TCL_RULES_MINOR = \>> versions.vc] \
88 | && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MINOR >> versions.vc]
89 | !endif
90 |
91 | !if [echo OUR_RULES_MAJOR = \>> versions.vc] \
92 | && [nmakehlp -V "rules.vc" RULES_VERSION_MAJOR >> versions.vc]
93 | !endif
94 | !if [echo OUR_RULES_MINOR = \>> versions.vc] \
95 | && [nmakehlp -V "rules.vc" RULES_VERSION_MINOR >> versions.vc]
96 | !endif
97 | !include versions.vc
98 | # We have a newer version of the support files, use them
99 | !if ($(TCL_RULES_MAJOR) != $(OUR_RULES_MAJOR)) || ($(TCL_RULES_MINOR) < $(OUR_RULES_MINOR))
100 | _RULESDIR = .
101 | !endif
102 |
103 | !endif # if exist("rules.vc")
104 |
105 | !endif # if $(_RULESDIR) != "."
106 |
107 | # Let rules.vc know what copy of nmakehlp.c to use.
108 | NMAKEHLPC = $(_RULESDIR)\nmakehlp.c
109 |
110 | # Get rid of our internal defines before calling rules.vc
111 | !undef TCL_RULES_MAJOR
112 | !undef TCL_RULES_MINOR
113 | !undef OUR_RULES_MAJOR
114 | !undef OUR_RULES_MINOR
115 |
116 | !if exist("$(_RULESDIR)\rules.vc")
117 | !message *** Using $(_RULESDIR)\rules.vc
118 | !include "$(_RULESDIR)\rules.vc"
119 | !else
120 | !error *** Could not locate rules.vc in $(_RULESDIR)
121 | !endif
122 |
123 | !endif # _RULES_EXT_VC
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | addons:
3 | apt:
4 | sources:
5 | - ubuntu-toolchain-r-test
6 | packages:
7 | - binutils-mingw-w64-i686
8 | - binutils-mingw-w64-x86-64
9 | - gcc-mingw-w64
10 | - gcc-mingw-w64-base
11 | - gcc-mingw-w64-i686
12 | - gcc-mingw-w64-x86-64
13 | - gcc-multilib
14 | - tcl8.6-dev
15 | homebrew:
16 | packages:
17 | - tcl-tk
18 | jobs:
19 | include:
20 | # Testing on Linux GCC
21 | - name: "Linux/GCC/Shared"
22 | os: linux
23 | dist: focal
24 | compiler: gcc
25 | - name: "Linux/GCC/Shared/bionic"
26 | os: linux
27 | dist: bionic
28 | compiler: gcc
29 | - name: "Linux/GCC/Shared/xenial"
30 | os: linux
31 | dist: xenial
32 | compiler: gcc
33 | - name: "Linux/GCC/Debug"
34 | os: linux
35 | dist: focal
36 | compiler: gcc
37 | env:
38 | - CFGOPT="--enable-symbols"
39 | # Newer/Older versions of GCC
40 | - name: "Linux/GCC 10/Shared"
41 | os: linux
42 | dist: focal
43 | compiler: gcc-10
44 | addons:
45 | apt:
46 | packages:
47 | - g++-10
48 | - name: "Linux/GCC 5/Shared"
49 | os: linux
50 | dist: bionic
51 | compiler: gcc-5
52 | addons:
53 | apt:
54 | packages:
55 | - g++-5
56 | # Testing on Linux Clang
57 | - name: "Linux/Clang/Shared"
58 | os: linux
59 | dist: focal
60 | compiler: clang
61 | - name: "Linux/Clang/Debug"
62 | os: linux
63 | dist: focal
64 | compiler: clang
65 | env:
66 | - CFGOPT="--enable-symbols"
67 | # Testing on Mac, various styles
68 | # - name: "macOS/Xcode 12/Shared"
69 | # os: osx
70 | # osx_image: xcode12
71 | # env:
72 | # - CFGOPT="--with-gdbm --with-lmdb --with-tcl=/usr/local/opt/tcl-tk/lib CFLAGS=-I/usr/local/opt/tcl-tk/include"
73 | # - name: "macOS/Xcode 12/Debug"
74 | # os: osx
75 | # osx_image: xcode12
76 | # env:
77 | # - CFGOPT="--with-gdbm --with-lmdb --with-tcl=/usr/local/opt/tcl-tk/lib --enable-symbols CFLAGS=-I/usr/local/opt/tcl-tk/include"
78 | # Older MacOS versions
79 | # - name: "macOS/Xcode 11/Shared"
80 | # os: osx
81 | # osx_image: xcode11.7
82 | # env:
83 | # - CFGOPT="--with-tcl=/usr/local/opt/tcl-tk/lib CFLAGS=-I/usr/local/opt/tcl-tk/include CPPFLAGS=-mmacosx-version-min=10.14"
84 | # - name: "macOS/Xcode 10/Shared"
85 | # os: osx
86 | # osx_image: xcode10.3
87 | # addons:
88 | # homebrew:
89 | # packages:
90 | # - tcl-tk
91 | # update: true
92 | # env:
93 | # - CFGOPT="--with-tcl=/usr/local/opt/tcl-tk/lib CFLAGS=-I/usr/local/opt/tcl-tk/include CPPFLAGS=-mmacosx-version-min=10.14"
94 | # - name: "macOS/Xcode 9/Shared"
95 | # os: osx
96 | # osx_image: xcode9.4
97 | # addons:
98 | # homebrew:
99 | # packages:
100 | # - tcl-tk
101 | # update: true
102 | # env:
103 | # - CFGOPT="--with-tcl=/usr/local/opt/tcl-tk/lib CFLAGS=-I/usr/local/opt/tcl-tk/include CPPFLAGS=-mmacosx-version-min=10.13"
104 | # Test on Windows with MSVC native
105 | # - name: "Windows/MSVC/Shared"
106 | # os: windows
107 | # compiler: cl
108 | # env: &vcenv
109 | # - VCDIR="/C/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Auxiliary/Build"
110 | # before_install: &vcpreinst
111 | # - PATH="$PATH:$VCDIR"
112 | # install: []
113 | # script:
114 | # - cmd.exe //C vcvarsall.bat x64 '&&' nmake '-f' makefile.vc all tktest
115 | # "make dist" only
116 | - name: "Linux: make dist"
117 | os: linux
118 | dist: focal
119 | compiler: gcc
120 | script:
121 | - make dist
122 | before_install:
123 | - |-
124 | case $TRAVIS_OS_NAME in
125 | windows)
126 | choco install -y magicsplat-tcl-tk
127 | ;;
128 | esac
129 | install:
130 | - mkdir "$HOME/install dir"
131 | - mkdir tclconfig
132 | - touch tclconfig/README.txt
133 | - touch tclconfig/tcl.m4
134 | - curl https://core.tcl-lang.org/tclconfig/raw/install-sh?name=f46cea65709582bed664d69a40095db0490968df69c355e30cd8905f0b60a153 >tclconfig/install-sh
135 | - ./configure ${CFGOPT} "--prefix=$HOME/install dir" "--exec-prefix=$HOME/install dir" || (cat config.log && exit 1)
136 | script:
137 | - make || echo "Something wrong, maybe a hickup, let's try again"
138 | - make test >out.txt
139 | - cat out.txt
140 | - grep -q "Failed 0" out.txt
141 | - make install
142 | cache:
143 | directories:
144 | - $HOME/AppData/Local/Temp/chocolatey
145 | - $HOME/AppData/Local/Apps/Tcl86
146 |
--------------------------------------------------------------------------------
/tea/app_makefiles.txt:
--------------------------------------------------------------------------------
1 | [section {Appendix A. Explanation of make files and the make utility}]
2 |
3 | If you are not familiar with the [emph make] program, here is a brief
4 | explanation of it. In some of its features it is very similar to
5 | MicroSoft's Visual Studio or other [emph {integrated development environments}]:
6 | it processes descriptions of how to create a program from its
7 | sources and does so in an efficient way. In fact, many IDE's use the
8 | [emph {make}] utility in some form or other underneath.
9 |
10 | [para]
11 | The main difference between the [emph make] utility and most, "modern"
12 | IDE's is that [emph make] does not itself manage the description, the
13 | so-called [emph {make file}]. This is left to the programmer. Another
14 | difference is that [emph make] can be used for almost any task where
15 | files need to be built
16 | from other files using some program, in other words it is very flexible.
17 |
18 | [para]
19 | [emph {A small example}]
20 | [para]
21 |
22 | So far the introduction to [emph make]. Let us now describe how
23 | [emph make] does the
24 | job it is supposed to do, using the following sample program:
25 |
26 | [para]
27 | The program "sample" is built from two C source files, sample.c and
28 | utils.c. The first source file includes a header file utils.h, which
29 | contains the interface to the functions in utils.c.
30 |
31 | [para]
32 | Now changes to any of these files mean that the whole program has to be
33 | rebuilt. For this small program, we could easily type the command:
34 | [example {
35 | cc -o sample sample.c utils.c
36 | }]
37 |
38 | (or something similar, depending on the compiler you want to use). This
39 | would recompile the entire source and relink the program against all its
40 | parts.
41 |
42 | [para]
43 | Now:
44 |
45 | [list_begin bullet]
46 |
47 | [bullet]
48 | If only utils.c has changed, then it is a waste of time to recompile
49 | sample.c.
50 |
51 | [bullet]
52 | If the header file "utils.h" has changed, recompiling both is required,
53 | as the prototype of a function may have changed or something else that
54 | is vital to the functions in "utils.c". Only this is not clear at all
55 | from the command we just typed: the dependence of the two source files
56 | on this header file is hidden inside the sources!
57 |
58 | [list_end]
59 |
60 | This is what the [emph make] utility would do, when properly instructed:
61 |
62 | [list_begin bullet]
63 |
64 | [bullet]
65 | The file "sample" (our executable program) and others are defined
66 | as "targets": things for the [emph make] utility to examine.
67 |
68 | [bullet]
69 | The file "sample" depends on two "object files" (the results of
70 | a compilation):
71 |
72 | [list_begin bullet]
73 | [bullet]
74 | sample.o
75 | [bullet]
76 | utils.o
77 | [list_end]
78 |
79 | If any of these files is out of date, then the program is out of date.
80 |
81 | [bullet]
82 | So check if these two files are out of date, by checking their
83 | dependencies:
84 |
85 | [list_begin bullet]
86 | [bullet]
87 | sample.o depends on sample.c and utils.h (because sample.c uses
88 | that header file)
89 | [bullet]
90 | in a similar way, utils.o depends on utils.c and utils.h.
91 | By the same reasoning, check these three files.
92 | [list_end]
93 |
94 | [bullet]
95 | These files are source files and header files, we have edited these
96 | files manually, they can not be created from other files. So, this
97 | is the end of that step in the reasoning process.
98 | [bullet]
99 | The object files sample.o and utils.o are out of date if the three
100 | files are newer:
101 |
102 | [list_begin bullet]
103 | [bullet]
104 | sample.o is out of date if sample.c or utils.h is newer than this file.
105 | Then use the rule that belongs to sample.o to rebuild it
106 | [bullet]
107 | utils.o is out of date if utils.c or utils.h is newer than this file.
108 | Again: use the rule that belongs to utils.o to rebuild that.
109 | [list_end]
110 |
111 | [bullet]
112 | Now the two files that our program depends on are up to date.
113 | The program itself clearly is not. So, relink that program.
114 |
115 | [list_end]
116 |
117 | The makefile might look like this:
118 | [example {
119 | sample->:->sample.o utils.o
120 | ->cc -o sample sample.o utils.o
121 |
122 | sample.o->:->sample.c utils.h
123 | ->cc -c sample.c
124 |
125 | utils.o->:->utils.c utils.h
126 | ->cc -c utils.c
127 | }]
128 | (the symbol "->" indicates a tab character - this is essential in makefiles,
129 | as it is used to identify what lines belong together)
130 |
131 | [para]
132 | This is a very simple makefile, in practice programs that are maintained with
133 | makefiles are much larger, you need to take of building the documentation,
134 | libraries, of installing the files at the proper location and so on. To make
135 | things worse: many compilers use different options to specify similar
136 | tasks and operating systems require different libraries (or put the
137 | libraries in different places).
138 |
139 | [para]
140 | To help manage the makefiles, the [emph autoconf] utility was created. This
141 | utility prepares the correct makefile from a given template, using a
142 | complicated but relatively easy to use configuration script.
143 |
--------------------------------------------------------------------------------
/tea/writingdocs.txt:
--------------------------------------------------------------------------------
1 | [section {Chapter 8. DOCUMENTATION}]
2 |
3 | It may seem a heavy burden for many a programmer, but documentation
4 | is necessary, even though one sometimes gets the impression (quite
5 | wrongly of course, but still) that no user ever bothers to read it.
6 |
7 | [para]
8 | Besides proper comments in the code, we need a guide for users to fall
9 | back on. Traditionally for Tcl/Tk this has been in the form of
10 | UNIX-style man pages:
11 |
12 | [list_begin bullet]
13 |
14 | [bullet]
15 | A short introduction to the command
16 |
17 | [bullet]
18 | A list of commands that one can use
19 |
20 | [bullet]
21 | One or more sections with explanations
22 |
23 | [list_end]
24 |
25 | This is a format that works well for more or less experienced users -
26 | they use the man page as a reference manual. On the other hand, new
27 | users may find them a bit awkward, as a lot of background is
28 | usually assumed.
29 |
30 | [para]
31 | For most extensions, it will suffice to use the classical man page
32 | format with perhaps some more explanation of what the extension is all
33 | about and some more examples and elaborated code fragments than usual.
34 |
35 | [para]
36 | To help with writing the documentation, we strongly suggest you use the
37 | so-called [emph doctools] that are now part of the standard Tcl applications.
38 | The basic idea of doctools is simple:
39 |
40 | [list_begin bullet]
41 |
42 | [bullet]
43 | You write the text for the man page using doctools' macros
44 |
45 | [bullet]
46 | These markup macros can be regarded as embedded Tcl commands and
47 | provide the markup system with clues as to how to format the text
48 | (many of the macros represent [emph semantic] clues, instead of mere style
49 | information)
50 |
51 | [bullet]
52 | The doctools application can then process this text and turn it into
53 | any of a number of formats, such as HTML but also nroff and TMML (Tcl
54 | Manual Markup Language).
55 |
56 | [bullet]
57 | This way, one single source suffices to generate all kinds of output
58 | files, suitable for most online documentation systems.
59 |
60 | [list_end]
61 |
62 | Here is a small example of such an input file:
63 | [example {
64 | ......
65 | }]
66 |
67 | This file can be processed by the doctools application, to give an
68 | HTML-file that is rendered like this:
69 |
70 | [example {
71 | /picture/ ??
72 | }]
73 |
74 | [section {Short overview of the macros supported by doctools}]
75 |
76 | [para]
77 | [lb]arg $name[rb]
78 | - argument in a [lb]call[rb] statement
79 | [para]
80 |
81 | [lb]arg_def $type $name $intent[rb]
82 | - description of the argument, what type it is (widget, integer, list,
83 | ...), its name and whether it simply passed to the command (in)
84 | or gets set as well (out or in/out)
85 | [para]
86 |
87 | [lb]bullet[rb]
88 | - start a new item in a bullet list
89 | [para]
90 |
91 | [lb]call $cmd $args[rb]
92 | - define a command (its argument list; the command gets added to the
93 | synopsis)
94 | [para]
95 |
96 | [lb]cmd $name[rb]
97 | - name of the command (first argument for [lb]call[rb])
98 | [para]
99 |
100 | [lb]comment $text[rb]
101 | - add comments to the original, does not show up in the output
102 | [para]
103 |
104 | [lb]copyright $name[rb]
105 | - insert a copyright string at the end of the rendered document
106 | [para]
107 |
108 | [lb]description[rb]
109 | - start the man page section DESCRIPTION (note: this section is required
110 | at the beginning of the document)
111 | [para]
112 |
113 | [lb]emph $text[rb]
114 | - show the given text as emphasized (typically italic)
115 | [para]
116 |
117 | [lb]example $example[rb]
118 | - insert preformatted text that serves as an example for the commands
119 | being discussed
120 | [para]
121 |
122 | [lb]keywords $args[rb]
123 | - add the keywords given in the variable argument list to the end of the
124 | document
125 | [para]
126 |
127 | [lb]list_begin arg[rb]
128 | - start a list of arguments (after a corresponding [lb]call[rb] command)
129 | [para]
130 |
131 | [lb]list_begin bullet[rb]
132 | - start a bullet list
133 | [para]
134 |
135 | [lb]list_begin definitions[rb]
136 | - start a definitions list
137 | [para]
138 |
139 | [lb]list_begin opt[rb]
140 | - start a list of options
141 | [para]
142 |
143 | [lb]list_end[rb]
144 | - end the current list, brackets [lb]list_begin[rb]
145 | [para]
146 |
147 | [lb]manpage_begin $name $section $version[rb]
148 | - indicate the start of the manual page with the name of the
149 | module/package/extension, the section of the manual pages it should go
150 | into (always "n") and the version number
151 | [para]
152 |
153 | [lb]manpage_end[rb]
154 | mandatory end of the man page, brackets the [lb]manpage_begin[rb] command
155 | [para]
156 |
157 | [lb]moddesc $name[rb]
158 | - identify the module
159 | [para]
160 |
161 | [lb]nl[rb]
162 | - put a break in the flowing text. Useable only within lists
163 | [para]
164 |
165 | [lb]opt_def $keyword $type[rb]
166 | - the keyword for an option (without the leading minus sign) and the
167 | expected value type (if any)
168 | [para]
169 |
170 | [lb]para[rb]
171 | - start a new paragraph
172 | [para]
173 |
174 | [lb]require $package $version[rb]
175 | - insert a "package require" command in the synopsis of the man page to
176 | indicate the dependencies
177 | [para]
178 |
179 | [lb]section $title[rb]
180 | - start a new section, the title is traditionally given in capitals
181 | [para]
182 |
183 | [lb]titledesc $title[rb]
184 | - give the man page a proper title
185 |
186 |
187 | [section REFERENCES]
188 |
189 | [list_begin bullet]
190 |
191 | [bullet]
192 | Will Duquette: Guidelines for using namespaces
193 |
194 | [bullet]
195 | Ray Johnson: Tcl/Tk style guide
196 |
197 | [bullet]
198 | Ray Johnson: Engineering manual
199 |
200 | [bullet]
201 | Andreas Kupries: Documentation doctools
202 |
203 | [bullet]
204 | Boris Beizer: Software Testing Techniques
205 |
206 | [bullet]
207 | ??: Managing project with make
208 |
209 | [bullet]
210 | ??: Information on stubs
211 |
212 | [bullet]
213 | Don Porter: Man page on tcltest
214 |
215 | [bullet]
216 | ??: Autoconf documentation
217 |
218 | [list_end]
219 |
--------------------------------------------------------------------------------
/tea/writingtests.txt:
--------------------------------------------------------------------------------
1 | [section {Chapter 7. WRITING AND RUNNING TESTS}]
2 |
3 | As the developer of an extension you are probably in the best
4 | position to identify the kind of things that need to be tested:
5 |
6 | [list_begin bullet]
7 |
8 | [bullet]
9 | The reaction of a command to valid input
10 |
11 | [bullet]
12 | What constitutes invalid input and how your extension deals
13 | with that.
14 |
15 | [list_end]
16 |
17 | It is quite possible to give theoretically sound guidelines for
18 | a complete test suite (complete that is in the sense of some
19 | test criterium, for instance that all code is executed at
20 | least once when all the test cases are run). However, the
21 | same theory also teaches us that each criterium has its
22 | weaknesses and will let through certain types of bugs.
23 | Furthermore, the number of test cases and the management
24 | of the test code becomes unwieldy when your extension achieves
25 | a considerable size. (For more information, the classical
26 | book by Boris Beizer, Software Testing Techniques, can be consulted.
27 | There are many more similar publications.)
28 |
29 | [para]
30 | Let us deal instead with some more practical guidelines. Here are
31 | some minimal requirements:
32 |
33 | [list_begin bullet]
34 |
35 | [bullet]
36 | For all public commands in your extension, there should be at least
37 | one test case. If possible the test case should be small so that
38 | it concentrates on one and only one command, but that may not
39 | always be possible.
40 |
41 | [bullet]
42 | For all public commands at least one or two examples with [emph invalid]
43 | input (if there is any) should be defined. The purpose is to
44 | show that the extension can gracefully deal with such erroneous
45 | calls.
46 | [list_end]
47 |
48 | [para]
49 | If practical, then:
50 |
51 | [list_begin bullet]
52 |
53 | [bullet]
54 | You should define a fairly exhaustive set of
55 | test cases that together deal with all the defined functionality of the extension.
56 |
57 | [bullet]
58 | In a similar fashion all error cases should be included.
59 |
60 | [list_end]
61 |
62 | How we set up the tests? Simple, use the [emph tcltest] package. This package
63 | provides a complete and versatile infrastructure to deal with running
64 | tests and reporting the results (see the quite extensive manual page).
65 |
66 | [para]
67 | Here is a summary:
68 |
69 | [list_begin bullet]
70 |
71 | [bullet]
72 | Define small scripts that should return a known value.
73 |
74 | [bullet]
75 | The scripts are run and the actually returned value is compared
76 | to the expected value.
77 |
78 | [bullet]
79 | If there is a difference, then this is reported and the test fails.
80 |
81 | [bullet]
82 | For more flexibility:
83 |
84 | [list_begin bullet]
85 | [bullet]
86 | You can define the way the two values should be compared
87 | (via glob or regular expression matching or via a user-defined
88 | method, in case of floating-point values for instance)
89 | [bullet]
90 | You can define constraints for the tests - some tests only make
91 | sense on a specific platform for instance
92 | [bullet]
93 | You can prepare files via the special procedures that the tcltest
94 | package provides, so that they can be cleaned up properly.
95 | [list_end]
96 |
97 | [list_end]
98 |
99 | To illustrate this discussion with an example, consider an extension
100 | with a command "isValidXYZFile", this command checks the contents of the
101 | given file (the one argument to this command) and returns 1 if it is
102 | indeed a valid XYZ file (whatever XYZ files are) and 0 if it is not.
103 |
104 | [para]
105 | Test cases for this command could include:
106 |
107 | [list_begin bullet]
108 |
109 | [bullet]
110 | A valid XYZ file
111 |
112 | [bullet]
113 | An arbitrary file (that certainly is not an XYZ file)
114 |
115 | [bullet]
116 | No argument at all
117 |
118 | [bullet]
119 | A non-existent file
120 |
121 | [bullet]
122 | Two or more commands
123 |
124 | [list_end]
125 |
126 | The first two fall in the category "valid input", the others represent
127 | particular invalid input that the command is supposed to gracefully
128 | deal with (recognise that the input is not correct and report an
129 | error).
130 |
131 | [para]
132 | Traditionally, test scripts are contained in files with the extension
133 | ".test". So let us put the following code in a file "xyzfiles.test" to
134 | test our "xyzfiles" extension:
135 | [example {
136 | #
137 | # Initialise the test package (we need only the "test" command)
138 | #
139 | package require tcltest
140 | namespace import ::tcltest::test
141 |
142 | #
143 | # Get our xyzfiles extension
144 | #
145 | package require xyzfiles
146 | namespace import xyzfiles::isValidXYZFile
147 |
148 | #
149 | # Our tests for valid input (sample.xyz is a valid XYZ file
150 | # ships with the extension, sampe2.xyz is an invalid but
151 | # existing file)
152 | #
153 |
154 | test "xyzfiles-1.1" "Valid XYZ file" -body {
155 | isValidXYZFile "sample.xyz"
156 | } -result 1 ;# It is a valid file, so the command returns 1
157 |
158 | test "xyzfiles-1.2" "Not a valid XYZ file" -body {
159 | isValidXYZFile "sample2.xyz"
160 | } -result 0
161 |
162 | #
163 | # Invalid input (the major test number is changed for convenience
164 | # only):
165 | #
166 |
167 | test "xyzfiles-2.1" "No argument" -body {
168 | isValidXYZFile
169 | } -returnCodes error -result "wrong # args: *" -match glob
170 |
171 | # tcltest uses exact matching by default, so we change that for this case
172 |
173 | test "xyzfiles-2.2" "Non-existent file" -body {
174 | isValidXYZFile "non-existent-file.xyz"
175 | } -returnCodes error -result "Non existent file *" -match glob
176 |
177 | test "xyzfiles-2.3" "Too many arguments" -body {
178 | isValidXYZFile 1 2 3 4
179 | } -returnCodes error -result "wrong # args: *" -match glob
180 | }]
181 |
182 | Note that in the last three cases we use the [lb]catch[rb] command to catch
183 | the intended errors and we use the glob matching option to match against
184 | a rough string, rather than an exact string.
185 |
186 | [para]
187 | Testing the arguments is of course much more important in case
188 | of a compiled extension than in case of a Tcl-only procedure, but
189 | if there are subcommands that require different numbers of arguments
190 | it can be a good idea to add tests like the above.
191 |
192 | [para]
193 | These tests can be run by the command:
194 | [example {
195 | > make test
196 | }]
197 | (See the code for "test" target in the make file)
198 |
199 | [para]
200 | It is good style to always run every test in a test suite. If some
201 | tests fail on some platforms, use test constraints to prevent running
202 | of those particular tests. You can also use test constraints to
203 | protect non-test pieces of code in the test file.
204 |
--------------------------------------------------------------------------------
/doc/man.macros:
--------------------------------------------------------------------------------
1 | .\" The -*- nroff -*- definitions below are for supplemental macros used
2 | .\" in Tcl/Tk manual entries.
3 | .\"
4 | .\" .AP type name in/out ?indent?
5 | .\" Start paragraph describing an argument to a library procedure.
6 | .\" type is type of argument (int, etc.), in/out is either "in", "out",
7 | .\" or "in/out" to describe whether procedure reads or modifies arg,
8 | .\" and indent is equivalent to second arg of .IP (shouldn't ever be
9 | .\" needed; use .AS below instead)
10 | .\"
11 | .\" .AS ?type? ?name?
12 | .\" Give maximum sizes of arguments for setting tab stops. Type and
13 | .\" name are examples of largest possible arguments that will be passed
14 | .\" to .AP later. If args are omitted, default tab stops are used.
15 | .\"
16 | .\" .BS
17 | .\" Start box enclosure. From here until next .BE, everything will be
18 | .\" enclosed in one large box.
19 | .\"
20 | .\" .BE
21 | .\" End of box enclosure.
22 | .\"
23 | .\" .CS
24 | .\" Begin code excerpt.
25 | .\"
26 | .\" .CE
27 | .\" End code excerpt.
28 | .\"
29 | .\" .VS ?version? ?br?
30 | .\" Begin vertical sidebar, for use in marking newly-changed parts
31 | .\" of man pages. The first argument is ignored and used for recording
32 | .\" the version when the .VS was added, so that the sidebars can be
33 | .\" found and removed when they reach a certain age. If another argument
34 | .\" is present, then a line break is forced before starting the sidebar.
35 | .\"
36 | .\" .VE
37 | .\" End of vertical sidebar.
38 | .\"
39 | .\" .DS
40 | .\" Begin an indented unfilled display.
41 | .\"
42 | .\" .DE
43 | .\" End of indented unfilled display.
44 | .\"
45 | .\" .SO ?manpage?
46 | .\" Start of list of standard options for a Tk widget. The manpage
47 | .\" argument defines where to look up the standard options; if
48 | .\" omitted, defaults to "options". The options follow on successive
49 | .\" lines, in three columns separated by tabs.
50 | .\"
51 | .\" .SE
52 | .\" End of list of standard options for a Tk widget.
53 | .\"
54 | .\" .OP cmdName dbName dbClass
55 | .\" Start of description of a specific option. cmdName gives the
56 | .\" option's name as specified in the class command, dbName gives
57 | .\" the option's name in the option database, and dbClass gives
58 | .\" the option's class in the option database.
59 | .\"
60 | .\" .UL arg1 arg2
61 | .\" Print arg1 underlined, then print arg2 normally.
62 | .\"
63 | .\" .QW arg1 ?arg2?
64 | .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
65 | .\"
66 | .\" .PQ arg1 ?arg2?
67 | .\" Print an open parenthesis, arg1 in quotes, then arg2 normally
68 | .\" (for trailing punctuation) and then a closing parenthesis.
69 | .\"
70 | .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
71 | .if t .wh -1.3i ^B
72 | .nr ^l \n(.l
73 | .ad b
74 | .\" # Start an argument description
75 | .de AP
76 | .ie !"\\$4"" .TP \\$4
77 | .el \{\
78 | . ie !"\\$2"" .TP \\n()Cu
79 | . el .TP 15
80 | .\}
81 | .ta \\n()Au \\n()Bu
82 | .ie !"\\$3"" \{\
83 | \&\\$1 \\fI\\$2\\fP (\\$3)
84 | .\".b
85 | .\}
86 | .el \{\
87 | .br
88 | .ie !"\\$2"" \{\
89 | \&\\$1 \\fI\\$2\\fP
90 | .\}
91 | .el \{\
92 | \&\\fI\\$1\\fP
93 | .\}
94 | .\}
95 | ..
96 | .\" # define tabbing values for .AP
97 | .de AS
98 | .nr )A 10n
99 | .if !"\\$1"" .nr )A \\w'\\$1'u+3n
100 | .nr )B \\n()Au+15n
101 | .\"
102 | .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
103 | .nr )C \\n()Bu+\\w'(in/out)'u+2n
104 | ..
105 | .AS Tcl_Interp Tcl_CreateInterp in/out
106 | .\" # BS - start boxed text
107 | .\" # ^y = starting y location
108 | .\" # ^b = 1
109 | .de BS
110 | .br
111 | .mk ^y
112 | .nr ^b 1u
113 | .if n .nf
114 | .if n .ti 0
115 | .if n \l'\\n(.lu\(ul'
116 | .if n .fi
117 | ..
118 | .\" # BE - end boxed text (draw box now)
119 | .de BE
120 | .nf
121 | .ti 0
122 | .mk ^t
123 | .ie n \l'\\n(^lu\(ul'
124 | .el \{\
125 | .\" Draw four-sided box normally, but don't draw top of
126 | .\" box if the box started on an earlier page.
127 | .ie !\\n(^b-1 \{\
128 | \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
129 | .\}
130 | .el \}\
131 | \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
132 | .\}
133 | .\}
134 | .fi
135 | .br
136 | .nr ^b 0
137 | ..
138 | .\" # VS - start vertical sidebar
139 | .\" # ^Y = starting y location
140 | .\" # ^v = 1 (for troff; for nroff this doesn't matter)
141 | .de VS
142 | .if !"\\$2"" .br
143 | .mk ^Y
144 | .ie n 'mc \s12\(br\s0
145 | .el .nr ^v 1u
146 | ..
147 | .\" # VE - end of vertical sidebar
148 | .de VE
149 | .ie n 'mc
150 | .el \{\
151 | .ev 2
152 | .nf
153 | .ti 0
154 | .mk ^t
155 | \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
156 | .sp -1
157 | .fi
158 | .ev
159 | .\}
160 | .nr ^v 0
161 | ..
162 | .\" # Special macro to handle page bottom: finish off current
163 | .\" # box/sidebar if in box/sidebar mode, then invoked standard
164 | .\" # page bottom macro.
165 | .de ^B
166 | .ev 2
167 | 'ti 0
168 | 'nf
169 | .mk ^t
170 | .if \\n(^b \{\
171 | .\" Draw three-sided box if this is the box's first page,
172 | .\" draw two sides but no top otherwise.
173 | .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
174 | .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
175 | .\}
176 | .if \\n(^v \{\
177 | .nr ^x \\n(^tu+1v-\\n(^Yu
178 | \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
179 | .\}
180 | .bp
181 | 'fi
182 | .ev
183 | .if \\n(^b \{\
184 | .mk ^y
185 | .nr ^b 2
186 | .\}
187 | .if \\n(^v \{\
188 | .mk ^Y
189 | .\}
190 | ..
191 | .\" # DS - begin display
192 | .de DS
193 | .RS
194 | .nf
195 | .sp
196 | ..
197 | .\" # DE - end display
198 | .de DE
199 | .fi
200 | .RE
201 | .sp
202 | ..
203 | .\" # SO - start of list of standard options
204 | .de SO
205 | 'ie '\\$1'' .ds So \\fBoptions\\fR
206 | 'el .ds So \\fB\\$1\\fR
207 | .SH "STANDARD OPTIONS"
208 | .LP
209 | .nf
210 | .ta 5.5c 11c
211 | .ft B
212 | ..
213 | .\" # SE - end of list of standard options
214 | .de SE
215 | .fi
216 | .ft R
217 | .LP
218 | See the \\*(So manual entry for details on the standard options.
219 | ..
220 | .\" # OP - start of full description for a single option
221 | .de OP
222 | .LP
223 | .nf
224 | .ta 4c
225 | Command-Line Name: \\fB\\$1\\fR
226 | Database Name: \\fB\\$2\\fR
227 | Database Class: \\fB\\$3\\fR
228 | .fi
229 | .IP
230 | ..
231 | .\" # CS - begin code excerpt
232 | .de CS
233 | .RS
234 | .nf
235 | .ta .25i .5i .75i 1i
236 | ..
237 | .\" # CE - end code excerpt
238 | .de CE
239 | .fi
240 | .RE
241 | ..
242 | .\" # UL - underline word
243 | .de UL
244 | \\$1\l'|0\(ul'\\$2
245 | ..
246 | .\" # QW - apply quotation marks to word
247 | .de QW
248 | .ie '\\*(lq'"' ``\\$1''\\$2
249 | .\"" fix emacs highlighting
250 | .el \\*(lq\\$1\\*(rq\\$2
251 | ..
252 | .\" # PQ - apply parens and quotation marks to word
253 | .de PQ
254 | .ie '\\*(lq'"' (``\\$1''\\$2)\\$3
255 | .\"" fix emacs highlighting
256 | .el (\\*(lq\\$1\\*(rq\\$2)\\$3
257 | ..
258 | .\" # QR - quoted range
259 | .de QR
260 | .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
261 | .\"" fix emacs highlighting
262 | .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
263 | ..
264 | .\" # MT - "empty" string
265 | .de MT
266 | .QW ""
267 | ..
268 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | #!/bin/bash -norc
2 | dnl This file is an input file used by the GNU "autoconf" program to
3 | dnl generate the file "configure", which is run during Tcl installation
4 | dnl to configure the system for the local environment.
5 |
6 | #-----------------------------------------------------------------------
7 | # Sample configure.ac for Tcl Extensions. The only places you should
8 | # need to modify this file are marked by the string __CHANGE__
9 | #-----------------------------------------------------------------------
10 |
11 | #-----------------------------------------------------------------------
12 | # __CHANGE__
13 | # Set your package name and version numbers here.
14 | #
15 | # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
16 | # set as provided. These will also be added as -D defs in your Makefile
17 | # so you can encode the package version directly into the source files.
18 | # This will also define a special symbol for Windows (BUILD_
19 | # so that we create the export library with the dll.
20 | #-----------------------------------------------------------------------
21 |
22 | AC_INIT([sample],[0.6])
23 |
24 | #--------------------------------------------------------------------
25 | # Call TEA_INIT as the first TEA_ macro to set up initial vars.
26 | # This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
27 | # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
28 | #--------------------------------------------------------------------
29 |
30 | TEA_INIT()
31 |
32 | AC_CONFIG_AUX_DIR(tclconfig)
33 |
34 | #--------------------------------------------------------------------
35 | # Load the tclConfig.sh file
36 | #--------------------------------------------------------------------
37 |
38 | TEA_PATH_TCLCONFIG
39 | TEA_LOAD_TCLCONFIG
40 |
41 | #--------------------------------------------------------------------
42 | # Load the tkConfig.sh file if necessary (Tk extension)
43 | #--------------------------------------------------------------------
44 |
45 | #TEA_PATH_TKCONFIG
46 | #TEA_LOAD_TKCONFIG
47 |
48 | #-----------------------------------------------------------------------
49 | # Handle the --prefix=... option by defaulting to what Tcl gave.
50 | # Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER.
51 | #-----------------------------------------------------------------------
52 |
53 | TEA_PREFIX
54 |
55 | #-----------------------------------------------------------------------
56 | # Standard compiler checks.
57 | # This sets up CC by using the CC env var, or looks for gcc otherwise.
58 | # This also calls AC_PROG_CC and a few others to create the basic setup
59 | # necessary to compile executables.
60 | #-----------------------------------------------------------------------
61 |
62 | TEA_SETUP_COMPILER
63 |
64 | #-----------------------------------------------------------------------
65 | # __CHANGE__
66 | # Specify the C source files to compile in TEA_ADD_SOURCES,
67 | # public headers that need to be installed in TEA_ADD_HEADERS,
68 | # stub library C source files to compile in TEA_ADD_STUB_SOURCES,
69 | # and runtime Tcl library files in TEA_ADD_TCL_SOURCES.
70 | # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS
71 | # and PKG_TCL_SOURCES.
72 | #-----------------------------------------------------------------------
73 |
74 | TEA_ADD_SOURCES([sample.c tclsample.c])
75 | TEA_ADD_HEADERS([])
76 | TEA_ADD_INCLUDES([])
77 | TEA_ADD_LIBS([])
78 | TEA_ADD_CFLAGS([])
79 | TEA_ADD_STUB_SOURCES([])
80 | TEA_ADD_TCL_SOURCES([])
81 |
82 | #--------------------------------------------------------------------
83 | # __CHANGE__
84 | #
85 | # You can add more files to clean if your extension creates any extra
86 | # files by extending CLEANFILES.
87 | # Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
88 | # and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
89 | #
90 | # A few miscellaneous platform-specific items:
91 | # TEA_ADD_* any platform specific compiler/build info here.
92 | #--------------------------------------------------------------------
93 |
94 | #CLEANFILES="$CLEANFILES pkgIndex.tcl"
95 | if test "${TEA_PLATFORM}" = "windows" ; then
96 | # Ensure no empty if clauses
97 | :
98 | #TEA_ADD_SOURCES([win/winFile.c])
99 | #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"])
100 | else
101 | # Ensure no empty else clauses
102 | :
103 | #TEA_ADD_SOURCES([unix/unixFile.c])
104 | #TEA_ADD_LIBS([-lsuperfly])
105 | fi
106 |
107 | #--------------------------------------------------------------------
108 | # __CHANGE__
109 | # Choose which headers you need. Extension authors should try very
110 | # hard to only rely on the Tcl public header files. Internal headers
111 | # contain private data structures and are subject to change without
112 | # notice.
113 | # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
114 | #--------------------------------------------------------------------
115 |
116 | TEA_PUBLIC_TCL_HEADERS
117 | #TEA_PRIVATE_TCL_HEADERS
118 |
119 | #TEA_PUBLIC_TK_HEADERS
120 | #TEA_PRIVATE_TK_HEADERS
121 | #TEA_PATH_X
122 |
123 | #--------------------------------------------------------------------
124 | # Check whether --enable-threads or --disable-threads was given.
125 | # This auto-enables if Tcl was compiled threaded.
126 | #--------------------------------------------------------------------
127 |
128 | TEA_ENABLE_THREADS
129 |
130 | #--------------------------------------------------------------------
131 | # The statement below defines a collection of symbols related to
132 | # building as a shared library instead of a static library.
133 | #--------------------------------------------------------------------
134 |
135 | TEA_ENABLE_SHARED
136 |
137 | #--------------------------------------------------------------------
138 | # This macro figures out what flags to use with the compiler/linker
139 | # when building shared/static debug/optimized objects. This information
140 | # can be taken from the tclConfig.sh file, but this figures it all out.
141 | #--------------------------------------------------------------------
142 |
143 | TEA_CONFIG_CFLAGS
144 |
145 | #--------------------------------------------------------------------
146 | # Set the default compiler switches based on the --enable-symbols option.
147 | #--------------------------------------------------------------------
148 |
149 | TEA_ENABLE_SYMBOLS
150 |
151 | #--------------------------------------------------------------------
152 | # This macro generates a line to use when building a library. It
153 | # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
154 | # and TEA_LOAD_TCLCONFIG macros above.
155 | #--------------------------------------------------------------------
156 |
157 | TEA_MAKE_LIB
158 |
159 | #--------------------------------------------------------------------
160 | # Determine the name of the tclsh and/or wish executables in the
161 | # Tcl and Tk build directories or the location they were installed
162 | # into. These paths are used to support running test cases only,
163 | # the Makefile should not be making use of these paths to generate
164 | # a pkgIndex.tcl file or anything else at extension build time.
165 | #--------------------------------------------------------------------
166 |
167 | TEA_PROG_TCLSH
168 | #TEA_PROG_WISH
169 |
170 | #--------------------------------------------------------------------
171 | # Setup a *Config.sh.in configuration file.
172 | #--------------------------------------------------------------------
173 |
174 | #TEA_EXPORT_CONFIG([sample])
175 | #AC_SUBST(SAMPLE_VAR)
176 |
177 | #--------------------------------------------------------------------
178 | # Specify files to substitute AC variables in. You may alternatively
179 | # have a special pkgIndex.tcl.in or other files which require
180 | # substituting the AC variables in. Include these here.
181 | #--------------------------------------------------------------------
182 |
183 | AC_CONFIG_FILES([Makefile pkgIndex.tcl])
184 | #AC_CONFIG_FILES([sampleConfig.sh])
185 |
186 | #--------------------------------------------------------------------
187 | # Finally, substitute all of the various values into the files
188 | # specified with AC_CONFIG_FILES.
189 | #--------------------------------------------------------------------
190 |
191 | AC_OUTPUT
192 |
--------------------------------------------------------------------------------
/tea/packages.txt:
--------------------------------------------------------------------------------
1 | [section {Chapter 4. TCL PACKAGES}]
2 |
3 | NOTE: needs an update!!
4 | [para]
5 |
6 | The [emph package] mechanism, by which an extension is made available
7 | to a Tcl application is both simple and daunting, simple if you can stick to
8 | the user side, daunting if you need to understand how it actually
9 | works. In this chapter we give an overview of what the average
10 | programmer needs to know about it and nothing more. (The man pages
11 | on the [emph package] command are quite extensive and they document some
12 | of the inner workings too.)
13 |
14 |
15 | [section {The user side}]
16 |
17 | For the programmer who merely uses a particular package, there are two
18 | things he/she needs to know:
19 |
20 | [list_begin bullet]
21 |
22 | [bullet]
23 | the [emph {package require}] command
24 |
25 | [bullet]
26 | the auto_path variable
27 |
28 | [list_end]
29 |
30 | The programmer who needs, say, the Tktable extension, uses the
31 | following command:
32 | [example {
33 | package require Tktable
34 | }]
35 |
36 | (mostly without a version number, sometimes with a version number)
37 |
38 | [para]
39 | This instructs Tcl to go look for files "pkgIndex.tcl" in the
40 | directories listed in the [emph auto_path] variable and any of their
41 | subdirectories. Usually an installed package will be found in the
42 | standard place for extensions (packages): the lib directory under the
43 | Tcl installation directory. If not, the programmer can extend the
44 | auto_path variable with the directory that does contain the required
45 | package.
46 |
47 |
48 | [section {The package side}]
49 |
50 | If you are creating a package, then you need to know a bit more:
51 | - the [emph {package provide}] command for Tcl-based extensions/packages
52 | - the Tcl_PkgProvide() function for C-based extensions/packages
53 |
54 | [para]
55 | Here are small examples of both:
56 |
57 | [para]
58 | From the msgcat extension:
59 | [example {
60 | # msgcat.tcl --
61 | #
62 | # This file defines various procedures which implement a
63 | # message catalog facility for Tcl programs. It should be
64 | # loaded with the command "package require msgcat".
65 | #
66 | # Copyright (c) 1998-2000 by Ajuba Solutions.
67 | # Copyright (c) 1998 by Mark Harrison.
68 | #
69 | # See the file "license.terms" for information on usage and redistribution
70 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
71 |
72 | package require Tcl 8.2
73 | # When the version number changes, be sure to update the pkgIndex.tcl file,
74 | # and the installation directory in the Makefiles.
75 | package provide msgcat 1.3
76 |
77 | namespace eval msgcat {
78 | ...
79 | }
80 | }]
81 |
82 | The corresponding pkgIndex.tcl file looks like this:
83 | [example {
84 | if {![package vsatisfies [package provide Tcl] 8.2]} {return}
85 | package ifneeded msgcat 1.3 [list source [file join $dir msgcat.tcl]]
86 | }]
87 |
88 | Note the variable "$dir" in the second statement: this variable is set
89 | by the package mechanism when it is looking for the required package.
90 |
91 | [para]
92 | From the example extension (Sample):
93 | [example {
94 | /*
95 | *----------------------------------------------------------------------
96 | *
97 | * Sample_Init --
98 | *
99 | * Initialize the new package. The string "Sample" in the
100 | * function name must match the PACKAGE declaration at the top of
101 | * configure.ac.
102 | *
103 | * Results:
104 | * A standard Tcl result
105 | *
106 | * Side effects:
107 | * The Sample package is created.
108 | * One new command "sha1" is added to the Tcl interpreter.
109 | *
110 | *----------------------------------------------------------------------
111 | */
112 |
113 | int
114 | Sample_Init(Tcl_Interp *interp)
115 | {
116 | if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) {
117 | return TCL_ERROR;
118 | }
119 | if (Tcl_PkgRequire(interp, "Tcl", "8.6-", 0) == NULL) {
120 | return TCL_ERROR;
121 | }
122 | if (Tcl_PkgProvide(interp, "sample", VERSION) != TCL_OK) {
123 | return TCL_ERROR;
124 | }
125 | Tcl_CreateObjCommand(interp, "sha1", Sha1, NULL, NULL);
126 |
127 | ...
128 | }
129 | }]
130 | As this extension is built via the TEA facilities, a pkgIndex.tcl
131 | file is provided for automatically. Instead of simply sourcing a
132 | Tcl script, it will load the shared object or DLL that was built from
133 | the C sources, roughly like:
134 | [example {
135 | package ifneeded sample 1.0 [list load [file join $dir libsample.so]]
136 | }]
137 | or:
138 | [example {
139 | package ifneeded sample 1.0 [list load [file join $dir sample.dll]]
140 | }]
141 | The TEA will create the pkgIndex.tcl file automatically via the
142 | pkg_mkIndex command.
143 |
144 |
145 | [section {Details on version numbers}]
146 |
147 | The package command defines a number of administrative subcommands, like
148 | [emph {package vsatisfies}] that deal with version numbers and so on.
149 | In most cases, all you need to do as an extension writer is to use the
150 | well-known two-part version numbering.
151 |
152 | [para]
153 | It is, however, important to be consistent with the version numbers:
154 |
155 | [list_begin bullet]
156 |
157 | [bullet]
158 | Throughout the extension, the same version number must be used
159 |
160 | [bullet]
161 | New versions get a higher minor number and if there are major changes
162 | or incompatibilities with older versions, the major number should
163 | change.
164 |
165 | [bullet]
166 | This holds not only for the code itself, but also for the
167 | documentation and test cases.
168 |
169 | [list_end]
170 |
171 | For this reason, the TEA defines a C macro, VERSION, that holds the
172 | version string (you can see how it is used in the code for the sample
173 | extension). This string is built up of the major version and a
174 | combination of the minor version and the patchlevel. From the file
175 | "configure.ac" (see Chapter 6) we have:
176 | [example {
177 | #--------------------------------------------------------------------
178 | # __CHANGE__
179 | # Set your package name and version numbers here. The NODOT_VERSION is
180 | # required for constructing the library name on systems that don't like
181 | # dots in library names (Windows). The VERSION variable is used on the
182 | # other systems.
183 | #--------------------------------------------------------------------
184 |
185 | PACKAGE=sample
186 |
187 | MAJOR_VERSION=0
188 | MINOR_VERSION=6
189 | PATCHLEVEL=
190 |
191 | VERSION=${MAJOR_VERSION}.${MINOR_VERSION}${PATCHLEVEL}
192 | NODOT_VERSION=${MAJOR_VERSION}${MINOR_VERSION}
193 | }]
194 |
195 | So, the above would result in a macro VERSION with the value 0.6
196 | [para]
197 | The version number is also used to construct a distinguishing name for
198 | the library, like: libsample0.6.so or sample06.dll.
199 | This way there is much less chance of a conflict between versions.
200 |
201 |
202 | [section {Subtleties with package names}]
203 |
204 | There are a few things you must be aware of when choosing a name for
205 | the extension:
206 | [list_begin bullet]
207 |
208 | [bullet]
209 | package names should not end in a digit and should not contain
210 | special characters. Otherwise the script that generates the index file
211 | will be confused.
212 |
213 | [bullet]
214 | package names must be unique within an installation. Before you decide
215 | on some name, check that there is no other (popular) extension of that
216 | name (or something very similar).
217 |
218 | [list_end]
219 |
220 |
221 | [section {Subtleties at the C side}]
222 |
223 | Things are a bit more intertwined on the C side. As the command that
224 | will be used to load a binary extension is:
225 | [example {
226 | load filename
227 | }]
228 | Tcl will have to deduce from the filename alone what the name is of the
229 | initialisation routine. The precise rules are explained in the manual
230 | page for the load command, but here are a few examples:
231 | [example {
232 | Filename Package name Initial procedure
233 | foo.dll foo Foo_Init
234 | libfoo1.2.so fOo Foo_Init
235 | }]
236 | So, in the index file you might see:
237 | [example {
238 | package ifneeded foo 1.2 [list load [file join $dir libfoo1.2.so]]
239 | }]
240 | A second issue is that for the extension to useful in a [emph safe]
241 | interpreter, you need to define an initialisation routine with a name
242 | like "Foo_SafeInit" (and possibly define the commands in another, safer,
243 | way).
244 |
245 | [para]
246 | The third issue that we would like to bring under your attention is the
247 | fact that under Windows you must explicitly indicate that a function in
248 | a DLL is to made visible (exported) to the outside world. Without this
249 | instruction the initialisation routine can not be loaded and therefore
250 | loading the extension fails.
251 |
252 | [para]
253 | The sample extension contains this fragment of code (sample.h) to take
254 | care of this (in general, the initialisation routine is the only one
255 | that needs to be exported - all others should be defined as [emph static] to
256 | reduce the chance of naming conflicts):
257 | [example {
258 | /*
259 | * Windows needs to know which symbols to export.
260 | */
261 |
262 | #ifdef BUILD_sample
263 | #undef TCL_STORAGE_CLASS
264 | #define TCL_STORAGE_CLASS DLLEXPORT
265 | #endif /* BUILD_sample */
266 |
267 | ...
268 |
269 | /*
270 | * Only the _Init function is exported.
271 | */
272 |
273 | EXTERN int Sample_Init (Tcl_Interp * interp);
274 | }]
275 |
--------------------------------------------------------------------------------
/generic/sample.c:
--------------------------------------------------------------------------------
1 | /*
2 | * sample.c --
3 | *
4 | * This file implements a secure hashing algorithm
5 | *
6 | * Copyright (c) 1999 Scriptics Corporation.
7 | *
8 | * See the file "license.terms" for information on usage and redistribution
9 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 | *
11 | */
12 |
13 | /*
14 | * SHA-1 in C
15 | * By Steve Reid
16 | * 100% Public Domain
17 | *
18 | * Test Vectors (from FIPS PUB 180-1)
19 | * "abc"
20 | * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
21 | * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
22 | * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
23 | * A million repetitions of "a"
24 | * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
25 | */
26 |
27 | /*
28 | * If byte order known, #define LITTLE_ENDIAN or BIG_ENDIAN to be faster
29 | */
30 |
31 | /*
32 | * Copy data before messing with it.
33 | * #define SHA1HANDSOFF
34 | */
35 |
36 | #include
37 | #include
38 | #include
39 | #include "sample.h"
40 |
41 | #define Rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
42 |
43 | /*
44 | * Blk0() and Blk() perform the initial expand.
45 | * I got the idea of expanding during the round function from SSLeay
46 | */
47 |
48 | #ifdef LITTLE_ENDIAN
49 | #define Blk0(i) (block->l[i] = (Rol(block->l[i],24)&0xFF00FF00) \
50 | |(Rol(block->l[i],8)&0x00FF00FF))
51 | #else
52 | #ifdef BIG_ENDIAN
53 | #define Blk0(i) block->l[i]
54 | #else
55 |
56 | /*
57 | * for unknown byte order, to work with either
58 | * results in no change on big endian machines
59 | * added by Dave Dykstra, 4/16/97
60 | */
61 |
62 | #define Blk0(i) (p = (unsigned char *) (&block->l[i]), \
63 | block->l[i] = (*p << 24) \
64 | + (*(p+1) << 16) + (*(p+2) << 8) + *(p+3))
65 | #endif
66 | #endif
67 | #define Blk(i) (block->l[i&15] = Rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
68 | ^block->l[(i+2)&15]^block->l[i&15],1))
69 |
70 | /*
71 | * (R0+R1), R2, R3, R4 are the different operations used in SHA1
72 | */
73 |
74 | #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+Blk0(i)+0x5A827999+Rol(v,5);w=Rol(w,30);
75 | #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+Blk(i)+0x5A827999+Rol(v,5);w=Rol(w,30);
76 | #define R2(v,w,x,y,z,i) z+=(w^x^y)+Blk(i)+0x6ED9EBA1+Rol(v,5);w=Rol(w,30);
77 | #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+Blk(i)+0x8F1BBCDC+Rol(v,5);w=Rol(w,30);
78 | #define R4(v,w,x,y,z,i) z+=(w^x^y)+Blk(i)+0xCA62C1D6+Rol(v,5);w=Rol(w,30);
79 |
80 | /*
81 | *----------------------------------------------------------------------
82 | *
83 | * SHA1Transform
84 | *
85 | * Hash a single 512-bit block. This is the core of the algorithm.
86 | *
87 | * Results:
88 | * None.
89 | *
90 | * Side effects:
91 | * Contents of state pointer are changed.
92 | *
93 | *----------------------------------------------------------------------
94 | */
95 |
96 | void
97 | SHA1Transform(
98 | sha_uint32_t state[5], /* State variable */
99 | unsigned char buffer[64]) /* Modified buffer */
100 | {
101 | #if (!defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN))
102 | unsigned char *p;
103 | #endif
104 | sha_uint32_t a, b, c, d, e;
105 | typedef union {
106 | unsigned char c[64];
107 | sha_uint32_t l[16];
108 | } CHAR64LONG16;
109 | CHAR64LONG16* block;
110 |
111 | #ifdef SHA1HANDSOFF
112 | static unsigned char workspace[64];
113 | block = (CHAR64LONG16*)workspace;
114 | memcpy(block, buffer, 64);
115 | #else
116 | block = (CHAR64LONG16*)buffer;
117 | #endif
118 |
119 | assert(sizeof(block->c) == sizeof(block->l));
120 |
121 | /*
122 | * Copy context->state[] to working vars
123 | */
124 |
125 | a = state[0];
126 | b = state[1];
127 | c = state[2];
128 | d = state[3];
129 | e = state[4];
130 |
131 | /*
132 | * 4 rounds of 20 operations each. Loop unrolled.
133 | */
134 |
135 | R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
136 | R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
137 | R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
138 | R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
139 | R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
140 | R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
141 | R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
142 | R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
143 | R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
144 | R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
145 | R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
146 | R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
147 | R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
148 | R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
149 | R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
150 | R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
151 | R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
152 | R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
153 | R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
154 | R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
155 |
156 | /*
157 | * Add the working vars back into context.state[]
158 | */
159 |
160 | state[0] += a;
161 | state[1] += b;
162 | state[2] += c;
163 | state[3] += d;
164 | state[4] += e;
165 |
166 | /*
167 | * Wipe variables
168 | */
169 |
170 | a = b = c = d = e = 0;
171 |
172 | return;
173 | }
174 |
175 | /*
176 | *----------------------------------------------------------------------
177 | *
178 | * SHA1Init --
179 | *
180 | * Initialize new context
181 | *
182 | * Results:
183 | * None.
184 | *
185 | * Side effects:
186 | * Contents of context pointer are changed.
187 | *
188 | *----------------------------------------------------------------------
189 | */
190 |
191 | void SHA1Init(
192 | SHA1_CTX* context) /* Context to initialize */
193 | {
194 | /*
195 | * SHA1 initialization constants
196 | */
197 |
198 | context->state[0] = 0x67452301;
199 | context->state[1] = 0xEFCDAB89;
200 | context->state[2] = 0x98BADCFE;
201 | context->state[3] = 0x10325476;
202 | context->state[4] = 0xC3D2E1F0;
203 | context->count[0] = context->count[1] = 0;
204 |
205 | return;
206 | }
207 |
208 | /*
209 | *----------------------------------------------------------------------
210 | *
211 | * SHA1Update
212 | *
213 | * Updates a context.
214 | *
215 | * Results:
216 | * None.
217 | *
218 | * Side effects:
219 | * Contents of context pointer are changed.
220 | *
221 | *----------------------------------------------------------------------
222 | */
223 |
224 | void
225 | SHA1Update(
226 | SHA1_CTX* context, /* Context to update */
227 | unsigned char* data, /* Data used for update */
228 | Tcl_Size len) /* Length of data */
229 | {
230 | Tcl_Size i, j;
231 |
232 | j = (context->count[0] >> 3) & 63;
233 | if ((context->count[0] += len << 3) < (len << 3)) {
234 | context->count[1]++;
235 | }
236 | context->count[1] += (len >> 29);
237 | if ((j + len) > 63) {
238 | memcpy(&context->buffer[j], data, (i = 64-j));
239 | SHA1Transform(context->state, context->buffer);
240 | for ( ; i + 63 < len; i += 64) {
241 | #ifdef CANWRITEDATA
242 | SHA1Transform(context->state, &data[i]);
243 | #else
244 |
245 | /*
246 | * else case added by Dave Dykstra 4/22/97
247 | */
248 |
249 | memcpy(&context->buffer[0], &data[i], 64);
250 | SHA1Transform(context->state, context->buffer);
251 | #endif
252 | }
253 | j = 0;
254 | } else {
255 | i = 0;
256 | }
257 |
258 | memcpy(&context->buffer[j], &data[i], len - i);
259 |
260 | return;
261 | }
262 |
263 | /*
264 | *----------------------------------------------------------------------
265 | *
266 | * SHA1Final
267 | *
268 | * Add padding and return the message digest.
269 | *
270 | * Results:
271 | * None.
272 | *
273 | * Side effects:
274 | * Contents of context pointer are changed.
275 | *
276 | *----------------------------------------------------------------------
277 | */
278 |
279 | void SHA1Final(
280 | SHA1_CTX* context, /* Context to pad */
281 | unsigned char digest[20]) /* Returned message digest */
282 | {
283 | sha_uint32_t i, j;
284 | unsigned char finalcount[8];
285 |
286 | for (i = 0; i < 8; i++) {
287 | /*
288 | * This statement is independent of the endianness
289 | */
290 |
291 | finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
292 | >> ((3-(i & 3)) * 8) ) & 255);
293 | }
294 | SHA1Update(context, (unsigned char *)"\200", 1);
295 | while ((context->count[0] & 504) != 448) {
296 | SHA1Update(context, (unsigned char *)"\0", 1);
297 | }
298 |
299 | /*
300 | * Should cause a SHA1Transform()
301 | */
302 |
303 | SHA1Update(context, finalcount, 8);
304 | for (i = 0; i < 20; i++) {
305 | digest[i] = (unsigned char)
306 | ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
307 | }
308 |
309 | /*
310 | * Wipe variables
311 | */
312 |
313 | i = j = 0;
314 | memset(context, 0, sizeof(SHA1_CTX));
315 | memset(&finalcount, 0, 8);
316 |
317 | /*
318 | * Make SHA1Transform overwrite it's own static vars.
319 | */
320 |
321 | #ifdef SHA1HANDSOFF
322 | SHA1Transform(context->state, context->buffer);
323 | #endif
324 |
325 | return;
326 | }
327 |
--------------------------------------------------------------------------------
/generic/tclsample.c:
--------------------------------------------------------------------------------
1 | /*
2 | * tclsample.c --
3 | *
4 | * This file implements a Tcl interface to the secure hashing
5 | * algorithm functions in sha1.c
6 | *
7 | * Copyright (c) 1999 Scriptics Corporation.
8 | * Copyright (c) 2003 ActiveState Corporation.
9 | *
10 | * See the file "license.terms" for information on usage and redistribution
11 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 | *
13 | */
14 |
15 | /*
16 | * Modified from tclmd5.c by Dave Dykstra, dwd@bell-labs.com, 4/22/97
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include "sample.h"
24 | #include "sampleUuid.h"
25 |
26 | #define TCL_READ_CHUNK_SIZE 4096
27 |
28 | static const unsigned char itoa64f[] =
29 | "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_,";
30 |
31 | static int numcontexts = 0;
32 | typedef struct {
33 | SHA1_CTX ctx;
34 | Tcl_Size totalRead;
35 | } sha1CmdContext;
36 | static sha1CmdContext *sha1CmdContexts = NULL;
37 |
38 |
39 | static int Sha1_Cmd(void *clientData, Tcl_Interp *interp,
40 | int objc, Tcl_Obj *const objv[]);
41 |
42 | #define DIGESTSIZE 20
43 |
44 | /*
45 | *----------------------------------------------------------------------
46 | *
47 | * Sha1 --
48 | *
49 | * Implements the new Tcl "sha1" command.
50 | *
51 | * Results:
52 | * A standard Tcl result
53 | *
54 | * Side effects:
55 | * None.
56 | *
57 | *----------------------------------------------------------------------
58 | */
59 |
60 | static int
61 | Sha1_Cmd(
62 | void *dummy, /* Not used. */
63 | Tcl_Interp *interp, /* Current interpreter */
64 | int objc, /* Number of arguments */
65 | Tcl_Obj *const objv[] /* Argument strings */
66 | )
67 | {
68 | /*
69 | * The default base is hex
70 | */
71 |
72 | int log2base = 4;
73 | int a;
74 | Tcl_Obj *stringObj = NULL;
75 | Tcl_Channel chan = NULL;
76 | Tcl_Channel copychan = NULL;
77 | int mode;
78 | int contextnum = 0;
79 | #define sha1Context (sha1CmdContexts[contextnum].ctx)
80 | char *bufPtr;
81 | Tcl_WideInt maxbytes = 0;
82 | int doinit = 1;
83 | int dofinal = 1;
84 | Tcl_Obj *descriptorObj = NULL;
85 | Tcl_Size totalRead = 0, n;
86 | int i, j, mask, bits, offset;
87 | (void)dummy;
88 |
89 | /*
90 | * For binary representation + null char
91 | */
92 |
93 | char buf[129];
94 | unsigned char digest[DIGESTSIZE];
95 |
96 | static const char *const options[] = {
97 | "-chan", "-copychan", "-final", "-init", "-log2base", "-maxbytes",
98 | "-string", "-update", NULL
99 | };
100 | enum ShaOpts {
101 | SHAOPT_CHAN, SHAOPT_COPY, SHAOPT_FINAL, SHAOPT_INIT, SHAOPT_LOG,
102 | SHAOPT_MAXB, SHAOPT_STRING, SHAOPT_UPDATE
103 | };
104 |
105 | for (a = 1; a < objc; a++) {
106 | int index;
107 |
108 | if (Tcl_GetIndexFromObjStruct(interp, objv[a], options, sizeof(char *),
109 | "option", 0, &index) != TCL_OK) {
110 | return TCL_ERROR;
111 | }
112 | /*
113 | * Everything except -init takes an argument...
114 | */
115 | if ((index != SHAOPT_INIT) && (++a >= objc)) {
116 | goto wrongArgs;
117 | }
118 | switch ((enum ShaOpts) index) {
119 | case SHAOPT_INIT:
120 | for (contextnum = 1; contextnum < numcontexts; contextnum++) {
121 | if (sha1CmdContexts[contextnum].totalRead == -1) {
122 | break;
123 | }
124 | }
125 | if (contextnum == numcontexts) {
126 | /*
127 | * Allocate a new context.
128 | */
129 |
130 | numcontexts++;
131 | sha1CmdContexts = (sha1CmdContext *)ckrealloc((void *)sha1CmdContexts,
132 | numcontexts * sizeof(sha1CmdContext));
133 | }
134 | sha1CmdContexts[contextnum].totalRead = 0;
135 | SHA1Init(&sha1Context);
136 | snprintf(buf, sizeof(buf), "sha1%d", contextnum);
137 | Tcl_AppendResult(interp, buf, (char *)NULL);
138 | return TCL_OK;
139 | case SHAOPT_CHAN:
140 | chan = Tcl_GetChannel(interp, Tcl_GetString(objv[a]), &mode);
141 | if (chan == NULL) {
142 | return TCL_ERROR;
143 | }
144 | if ((mode & TCL_READABLE) == 0) {
145 | Tcl_AppendResult(interp, "chan \"", Tcl_GetString(objv[a]),
146 | "\" wasn't opened for reading", (char *)NULL);
147 | return TCL_ERROR;
148 | }
149 | continue;
150 | case SHAOPT_COPY:
151 | copychan = Tcl_GetChannel(interp, Tcl_GetString(objv[a]), &mode);
152 | if (copychan == NULL) {
153 | return TCL_ERROR;
154 | }
155 | if ((mode & TCL_WRITABLE) == 0) {
156 | Tcl_AppendResult(interp, "copychan \"", Tcl_GetString(objv[a]),
157 | "\" wasn't opened for writing", (char *)NULL);
158 | return TCL_ERROR;
159 | }
160 | continue;
161 | case SHAOPT_FINAL:
162 | descriptorObj = objv[a];
163 | doinit = 0;
164 | continue;
165 | case SHAOPT_LOG:
166 | if (Tcl_GetIntFromObj(interp, objv[a], &log2base) != TCL_OK) {
167 | return TCL_ERROR;
168 | } else if ((log2base < 1) || (log2base > 6)) {
169 | Tcl_AppendResult(interp, "parameter to -log2base \"",
170 | Tcl_GetString(objv[a]),
171 | "\" must be integer in range 1...6", (char *)NULL);
172 | return TCL_ERROR;
173 | }
174 | continue;
175 | case SHAOPT_MAXB:
176 | if (Tcl_GetWideIntFromObj(interp, objv[a], &maxbytes) != TCL_OK) {
177 | return TCL_ERROR;
178 | }
179 | continue;
180 | case SHAOPT_STRING:
181 | stringObj = objv[a];
182 | continue;
183 | case SHAOPT_UPDATE:
184 | descriptorObj = objv[a];
185 | doinit = 0;
186 | dofinal = 0;
187 | continue;
188 | }
189 | }
190 |
191 | if (descriptorObj != NULL) {
192 | if ((sscanf(Tcl_GetString(descriptorObj), "sha1%d",
193 | &contextnum) != 1) || (contextnum >= numcontexts) ||
194 | (sha1CmdContexts[contextnum].totalRead == -1)) {
195 | Tcl_AppendResult(interp, "invalid sha1 descriptor \"",
196 | Tcl_GetString(descriptorObj), "\"", (char *)NULL);
197 | return TCL_ERROR;
198 | }
199 | }
200 |
201 | if (doinit) {
202 | SHA1Init(&sha1Context);
203 | }
204 |
205 | if (stringObj != NULL) {
206 | char *string;
207 | if (chan != NULL) {
208 | goto wrongArgs;
209 | }
210 | string = Tcl_GetStringFromObj(stringObj, &totalRead);
211 | SHA1Update(&sha1Context, (unsigned char *) string, totalRead);
212 | } else if (chan != NULL) {
213 | bufPtr = (char *)ckalloc(TCL_READ_CHUNK_SIZE);
214 | totalRead = 0;
215 | while ((n = Tcl_Read(chan, bufPtr,
216 | maxbytes == 0
217 | ? TCL_READ_CHUNK_SIZE
218 | : (TCL_READ_CHUNK_SIZE < maxbytes
219 | ? TCL_READ_CHUNK_SIZE
220 | : maxbytes))) != 0) {
221 | if (n == -1) {
222 | ckfree(bufPtr);
223 | Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": ",
224 | Tcl_GetChannelName(chan), Tcl_PosixError(interp),
225 | (char *)NULL);
226 | return TCL_ERROR;
227 | }
228 |
229 | totalRead += n;
230 |
231 | SHA1Update(&sha1Context, (unsigned char *)bufPtr, n);
232 |
233 | if (copychan != NULL) {
234 | n = Tcl_Write(copychan, bufPtr, n);
235 | if (n == -1) {
236 | ckfree(bufPtr);
237 | Tcl_AppendResult(interp, Tcl_GetString(objv[0]), ": ",
238 | Tcl_GetChannelName(copychan),
239 | Tcl_PosixError(interp), (char *)NULL);
240 | return TCL_ERROR;
241 | }
242 | }
243 |
244 | if ((maxbytes > 0) && (maxbytes <= n)) {
245 | break;
246 | }
247 | maxbytes -= n;
248 | }
249 | ckfree(bufPtr);
250 | } else if (descriptorObj == NULL) {
251 | goto wrongArgs;
252 | }
253 |
254 | if (!dofinal) {
255 | sha1CmdContexts[contextnum].totalRead += totalRead;
256 | Tcl_SetObjResult(interp, Tcl_NewWideIntObj(totalRead));
257 | return TCL_OK;
258 | }
259 |
260 | if (stringObj == NULL) {
261 | totalRead += sha1CmdContexts[contextnum].totalRead;
262 | Tcl_SetObjResult(interp, Tcl_NewWideIntObj(totalRead));
263 | }
264 |
265 | SHA1Final(&sha1Context, digest);
266 |
267 | /*
268 | * Take the 20 byte array and print it in the requested base
269 | * e.g. log2base=1 => binary, log2base=4 => hex
270 | */
271 |
272 | n = log2base;
273 | i = j = bits = 0;
274 |
275 | /*
276 | * if 160 bits doesn't divide exactly by n then the first character of
277 | * the output represents the residual bits. e.g for n=6 (base 64) the
278 | * first character can only take the values 0..f
279 | */
280 |
281 | offset = (DIGESTSIZE * 8) % n;
282 | if (offset > 0) {
283 | offset = n - offset;
284 | }
285 | mask = (2 << (n-1)) - 1;
286 | while (1) {
287 | bits <<= n;
288 | if (offset <= n) {
289 | if (i == DIGESTSIZE) {
290 | break;
291 | }
292 | bits += (digest[i++] << (n - offset));
293 | offset += 8;
294 | }
295 | offset -= n;
296 | buf[j++] = itoa64f[(bits>>8)&mask];
297 | }
298 | buf[j++] = itoa64f[(bits>>8)&mask];
299 | buf[j++] = '\0';
300 | Tcl_AppendResult(interp, buf, (char *)NULL);
301 | if (contextnum > 0) {
302 | sha1CmdContexts[contextnum].totalRead = -1;
303 | }
304 | return TCL_OK;
305 |
306 | wrongArgs:
307 | Tcl_AppendResult(interp, "wrong # args: should be either:\n",
308 | " ",
309 | Tcl_GetString(objv[0]),
310 | " ?-log2base log2base? -string string\n",
311 | " or\n",
312 | " ",
313 | Tcl_GetString(objv[0]),
314 | " ?-log2base log2base? ?-copychan chanID? -chan chanID\n",
315 | " or\n",
316 | " ",
317 | Tcl_GetString(objv[0]),
318 | " -init (returns descriptor)\n",
319 | " ",
320 | Tcl_GetString(objv[0]),
321 | " -update descriptor ?-maxbytes n? ?-copychan chanID? -chan chanID\n",
322 | " (any number of -update calls, returns number of bytes read)\n",
323 | " ",
324 | Tcl_GetString(objv[0]),
325 | " ?-log2base log2base? -final descriptor\n",
326 | " The default log2base is 4 (hex)",
327 | (char *)NULL);
328 | return TCL_ERROR;
329 | }
330 |
331 | /*
332 | *----------------------------------------------------------------------
333 | *
334 | * Sample_Init --
335 | *
336 | * Initialize the new package. The string "Sample" in the
337 | * function name must match the PACKAGE declaration at the top of
338 | * configure.ac.
339 | *
340 | * Results:
341 | * A standard Tcl result
342 | *
343 | * Side effects:
344 | * The Sample package is created.
345 | * One new command "sha1" is added to the Tcl interpreter.
346 | *
347 | *----------------------------------------------------------------------
348 | */
349 |
350 | #ifndef STRINGIFY
351 | # define STRINGIFY(x) STRINGIFY1(x)
352 | # define STRINGIFY1(x) #x
353 | #endif
354 |
355 | #ifdef __cplusplus
356 | extern "C" {
357 | #endif /* __cplusplus */
358 | DLLEXPORT int
359 | Sample_Init(
360 | Tcl_Interp* interp) /* Tcl interpreter */
361 | {
362 | Tcl_CmdInfo info;
363 |
364 | /*
365 | * Support any TCL version from 8.5.0 to 9.x.x.
366 | * The upper bound "10" is exclusive
367 | */
368 | if (Tcl_InitStubs(interp, "8.5-10", 0) == NULL) {
369 | return TCL_ERROR;
370 | }
371 |
372 | if (Tcl_GetCommandInfo(interp, "::tcl::build-info", &info)) {
373 | Tcl_CreateObjCommand(interp, "::sample::build-info",
374 | info.objProc, (void *)(
375 | PACKAGE_VERSION "+" STRINGIFY(SAMPLE_VERSION_UUID)
376 | #if defined(__clang__) && defined(__clang_major__)
377 | ".clang-" STRINGIFY(__clang_major__)
378 | #if __clang_minor__ < 10
379 | "0"
380 | #endif
381 | STRINGIFY(__clang_minor__)
382 | #endif
383 | #if defined(__cplusplus) && !defined(__OBJC__)
384 | ".cplusplus"
385 | #endif
386 | #ifndef NDEBUG
387 | ".debug"
388 | #endif
389 | #if !defined(__clang__) && !defined(__INTEL_COMPILER) && defined(__GNUC__)
390 | ".gcc-" STRINGIFY(__GNUC__)
391 | #if __GNUC_MINOR__ < 10
392 | "0"
393 | #endif
394 | STRINGIFY(__GNUC_MINOR__)
395 | #endif
396 | #ifdef __INTEL_COMPILER
397 | ".icc-" STRINGIFY(__INTEL_COMPILER)
398 | #endif
399 | #ifdef TCL_MEM_DEBUG
400 | ".memdebug"
401 | #endif
402 | #if defined(_MSC_VER)
403 | ".msvc-" STRINGIFY(_MSC_VER)
404 | #endif
405 | #ifdef USE_NMAKE
406 | ".nmake"
407 | #endif
408 | #ifndef TCL_CFG_OPTIMIZED
409 | ".no-optimize"
410 | #endif
411 | #ifdef __OBJC__
412 | ".objective-c"
413 | #if defined(__cplusplus)
414 | "plusplus"
415 | #endif
416 | #endif
417 | #ifdef TCL_CFG_PROFILED
418 | ".profile"
419 | #endif
420 | #ifdef PURIFY
421 | ".purify"
422 | #endif
423 | #ifdef STATIC_BUILD
424 | ".static"
425 | #endif
426 | ), NULL);
427 | }
428 |
429 | /* Provide the current package */
430 |
431 | if (Tcl_PkgProvideEx(interp, PACKAGE_NAME, PACKAGE_VERSION, NULL) != TCL_OK) {
432 | return TCL_ERROR;
433 | }
434 | Tcl_CreateObjCommand(interp, "sha1", (Tcl_ObjCmdProc *)Sha1_Cmd,
435 | NULL, NULL);
436 |
437 | numcontexts = 1;
438 | sha1CmdContexts = (sha1CmdContext *)ckalloc(sizeof(sha1CmdContext));
439 | sha1CmdContexts[0].totalRead = 0;
440 |
441 | return TCL_OK;
442 | }
443 | #ifdef __cplusplus
444 | }
445 | #endif /* __cplusplus */
446 |
--------------------------------------------------------------------------------
/tea/makefiles.txt:
--------------------------------------------------------------------------------
1 | [section {Chapter 6. CONFIGURE AND MAKE FILES}]
2 |
3 | A large part of TEA is devoted to making the actual build process as
4 | smoothly as possible, that is, people who install your extension
5 | should not need to know anything of the build process, except for a few
6 | simple commands, found and explained in the INSTALL file.
7 |
8 | [para]
9 | For you as an extension writer, things are a bit more involved, but
10 | again TEA has the task to make the preparation of the build process for
11 | your specific extension as smooth and painless as possible.
12 | Nevertheless, you will have to do something:
13 |
14 | [list_begin bullet]
15 |
16 | [bullet]
17 | Prepare at least two template files, configure.ac and Makefile.in,
18 | that contain information about what sources your extension is made of,
19 | under what name your extension will be known and so on.
20 |
21 | [bullet]
22 | Create a [emph {shell script}] (*), called [emph configure], via the Autoconf
23 | program.
24 |
25 | [bullet]
26 | Bundle your extension into a single file that can be delivered to
27 | others.
28 |
29 | [list_end]
30 |
31 | This chapter will guide you through this process. First it will gloss
32 | over the Autoconf program and its purpose. Then it will describe in
33 | detail what the average extension writer has to do.
34 |
35 | [para]
36 | [emph Note:]
37 | [para]
38 | If you are not familiar with [emph {make files}], read the expose in
39 | appendix A first. It will help appreciate the steps you will have to
40 | take.
41 |
42 | [para]
43 | [emph Note:]
44 | [para]
45 | TEA version 3 assumes that you have Autoconf version 2.50 or later.
46 | Autoconf is only necessary when you build the configure script, it is
47 | not required by the users of your extension (see the section
48 | "Required software")
49 |
50 | [para]
51 | (*) For Windows programmers: a shell script can be regarded as a
52 | sophisticated DOS batch file. It has the same purpose, but because UNIX
53 | shell languages (there are several) are more powerful than DOS batch
54 | commands, you can do a lot more with them.
55 |
56 |
57 | [section {The purpose of Autoconf}]
58 |
59 | The GNU program Autoconf, which is one of a suite of programs, is meant
60 | to create a configuration script, which then takes care of everything.
61 | To do this, it reads a file called configure.ac (or configure.in in
62 | older versions) and processes the macros it finds in there. These
63 | macros have been developed to take care of all the nasty little details
64 | that can bother a programmer. (If you familiarise yourself with the
65 | Autoconf tool, you will be able to create new macros. This is actually
66 | one of the great advantages of Autoconf.)
67 |
68 | [para]
69 | While Autoconf takes a template file "configure.ac", TEA provides you
70 | with a template for this template. All you need to do is:
71 |
72 | [list_begin bullet]
73 |
74 | [bullet]
75 | replace the name of the sample extension (exampleA) by the name
76 | of your extension
77 |
78 | [bullet]
79 | replace the names of the source files in the sample extension by
80 | those of your source files
81 |
82 | [bullet]
83 | adjust version numbers and some other details
84 |
85 | [bullet]
86 | run the Autoconf program
87 |
88 | [list_end]
89 |
90 | The resulting script, called [emph configure], will check for a lot of
91 | things:
92 |
93 | [list_begin bullet]
94 |
95 | [bullet]
96 | where the Tcl libraries and header files are (it may need some help,
97 | though, to find the right directory)
98 |
99 | [bullet]
100 | what compiler and linker options to use
101 |
102 | [bullet]
103 | what file extensions are used on that particular platform
104 |
105 | [bullet]
106 | what external libraries are required
107 |
108 | [bullet]
109 | etc.
110 |
111 | [list_end]
112 |
113 | All of these things are substituted into the template for the make file
114 | (Makefile.in) so that the user can run the make utility to create the
115 | library or program. For instance, in the template you may see:
116 | [example {
117 | CFLAGS_DEBUG = @CFLAGS_DEBUG@
118 | }]
119 | The first is a variable in the make file that is used to set the flags
120 | for a debug version of your extension. The configure script
121 | replaces the string "@CFLAGS_DEBUG@" by whatever is appropriate for that
122 | platform, often "-g -c". This is accomplished by a command
123 | AC_SUBST([lb]CFLAGS_DEBUG[rb]) somewhere in the configure.ac file (or
124 | the macros it uses).
125 |
126 |
127 | [section {The macros used by TEA}]
128 |
129 | The template files that come with TEA are very well documented,
130 | but still some explanation is required, if you are not familiar with
131 | Autoconf (see the example below).
132 |
133 | [para]
134 | [emph Note:]
135 | [para]
136 | The order of the macros is important, as the wrong order can make the
137 | resulting configure script useless (in Autoconf all variables are
138 | global and sometimes the value of a variable causes erroneous
139 | macro processing).
140 |
141 | [example {
142 | Example
143 | }]
144 |
145 | [list_begin bullet]
146 |
147 | [bullet]
148 | The very first macro is AC_INIT(), this has two arguments, the name of
149 | the extension and its version number:
150 |
151 | [list_begin bullet]
152 | [bullet]
153 | the major and minor version numbers of this release
154 | [bullet]
155 | the patchlevel (if any)
156 | [list_end]
157 |
158 | These numbers will be used to identify the resulting files uniquely.
159 | Because of pecularities between platforms, two "version" variables are
160 | created, one with dots and one without.
161 |
162 | [bullet]
163 | The next steps are to initialise the TEA macro library, via
164 | TEA_INIT and to set the directory with auxiliary scripts, tclconfig,
165 | via the macro AC_AUX_CONFIG_DIR.
166 |
167 | [bullet]
168 | Depending on whether your extension uses only Tcl or Tk as well, you
169 | will have to use:
170 |
171 | [list_begin bullet]
172 | [bullet]
173 | TEA_PATH_TCLCONFIG and TEA_LOAD_TCLCONFIG
174 | [bullet]
175 | TEA_PATH_TKCONFIG and TEA_LOAD_TKCONFIG
176 | [list_end]
177 | [nl]
178 | These macros locate the tclConfig.sh and tkConfig.sh files that hold
179 | information about how Tcl/Tk itself was built on this platform (or how
180 | the binary distribution was built).
181 |
182 | [bullet]
183 | TEA_PREFIX is used to set the directory that all files will be
184 | installed under, later, after building the extensions.
185 |
186 | [bullet]
187 | TEA_SETUP_COMPILER identifies the C compiler to be used and the flags
188 | or options needed in general.
189 |
190 | [bullet]
191 | After the call to this macro, we get a small section with information
192 | that is specific to your extension:
193 |
194 | [list_begin bullet]
195 | [bullet]
196 | TEA_ADD_SOURCES should be used to register the source files of your
197 | extension - the listed files will be compiled.
198 |
199 | [bullet]
200 | TEA_ADD_HEADERS is used to register the public header files (so
201 | these header files will be available for other extensions after
202 | installation).
203 |
204 | [bullet]
205 | TEA_ADD_INCLUDES lists possible additional directories to look for
206 | include files.
207 |
208 | [bullet]
209 | TEA_ADD_TCL_SOURCES registers the Tcl scripts that form part of your
210 | extension.
211 | [list_end]
212 |
213 | [nl]
214 | Two macros that are much more specific are:
215 |
216 | [list_begin bullet]
217 | [bullet]
218 | TEA_ADD_CFLAGS gives you the opportunity to add specfic compiler
219 | flags (but note that these can depend on the platform!)
220 | [bullet]
221 | TEA_ADD_STUB_SOURCES lists all the source files that together will
222 | make up the stubs library (if your extension makes one of its own).
223 | [list_end]
224 | [nl]
225 | [bullet]
226 | After this part we need to choose which header files we need:
227 |
228 | [list_begin bullet]
229 | [bullet]
230 | TEA_PUBLIC_TCL_HEADERS and TEA_PUBLIC_TK_HEADERS control the use of
231 | the [emph public] header files.
232 | [bullet]
233 | TEA_PRIVATE_TCL_HEADERS and TEA_PRIVATE_TK_HEADERS control the use
234 | of the [emph private] header files.
235 | [list_end]
236 |
237 | [nl]
238 | Caution: using the private header files is "dangerous" - they may
239 | change without regard for compatibility. In principle extensions
240 | should never rely on these, but in rare cases it might be unavoidable.
241 |
242 | [bullet]
243 | If your extension uses Tk, then the TEA_PATH_X macro is responsible
244 | for finding the system's graphical libraries (on UNIX-like systems)
245 |
246 | [bullet]
247 | Now comes the one place where some platform-dependent code is
248 | required:
249 |
250 | [list_begin bullet]
251 | [bullet]
252 | On Windows, an extension using Tk will need extra libraries and any
253 | extension will need to remove some intermediate files produced by
254 | the MS Visual C/C++ compiler.
255 | [nl]
256 | Also, the macro BUILD_package needs to be set for Windows (see the
257 | Chapter on Design)
258 | [bullet]
259 | There may be some intermediate files that are specific to the
260 | extension that need to be cleaned up.
261 | [list_end]
262 |
263 | [nl]
264 | This is best set via code like in the sample extension.
265 |
266 | [bullet]
267 | The remainder of the configuration file is straightforward:
268 | Several extra checks and finally the macro that tells the configure
269 | script what files to produce: AC_OUTPUT().
270 |
271 | [bullet]
272 | The rest of the file contains a number of macro calls, each of which
273 | is clearly documented. Use them or comment them as is necessary for
274 | your extension.
275 |
276 | [bullet]
277 | The last line, AC_OUTPUT(), lists all the files that need to be
278 | created by the configure script.
279 |
280 | [list_end]
281 |
282 | You can use a number of other macros in your configure.ac file:
283 |
284 | [list_begin bullet]
285 |
286 | [bullet]
287 | AC_DEFINE(variable,value,?description?):
288 | [nl]
289 | Add a C compiler macro "variable" with the given value to the list of
290 | compiler options, something like:
291 | [example {
292 | cc -Dvariable=value
293 | }]
294 |
295 | [bullet]
296 | AC_SUBST(variable,?value?):
297 | [nl]
298 | Substitute the given shell variable into the output files (when
299 | AC_OUTPUT is invoked)
300 |
301 | [bullet]
302 | AC_ARG_WITH(suffix,description,action):
303 | [nl]
304 | Check the command-line arguments of the configure script, such as:
305 | [example {
306 | --with-tcl=
307 | }]
308 | If the argument is present, the action will be carried out.
309 |
310 | [bullet]
311 | AC_ARG_ENABLE(suffix,description,action_on,action_off):
312 | [nl]
313 | Check the command-line arguments of the configure script, such as:
314 | [example {
315 | --enable-threads
316 | }]
317 | If the argument is present as "enabled", the action "on" will be
318 | carried out, otherwise the action "off" will be carried out.
319 |
320 | [bullet]
321 | AC_CHECK_HEADER(headerfile,action_if_found,action_not_found,):
322 | [nl]
323 | Check for the presence of a particular header file and if found, run
324 | the first action, otherwise the second action.
325 |
326 | [bullet]
327 | AC_CHECK_LIB(libfile,function,action_if_found,action_not_found,other_libs):
328 | [nl]
329 | Similar for libraries that should contain a particular function.
330 |
331 | [bullet]
332 | TEA_ADD_LIBS(list-of-names):
333 | [nl]
334 | Add one or more libraries to the link command. Note: the
335 | platform-dependent names are expected. See the TEA_LIB_SPEC macro.
336 |
337 | [bullet]
338 | TEA_LIB_SPEC(basename,extra_dir):
339 | [nl]
340 | Find the exact name of the library given via its basename (e.g.
341 | libinet.a would have the base name "inet" and user32.lib would
342 | have the base name "user32"). The extra directory is used first,
343 | then a bunch of standard directories. The resulting variable
344 | basename_LIB_SPEC can be used with the TEA_ADD_LIBS macro.
345 |
346 | [bullet]
347 | TEA_PATH_CONFIG(pkg)
348 | [nl]
349 | Look for a particular pkgConfig.sh file, which is part of some
350 | extension "pkg".
351 |
352 | [bullet]
353 | TEA_LOAD_CONFIG
354 | [nl]
355 | Load that particular pkgConfig.sh file.
356 |
357 | [list_end]
358 |
359 |
360 | [section {The Makefile.in template}]
361 |
362 | If you study the (well-documented) make file template that comes with
363 | the sample extension, Makefile.in, you will notice that there is very
364 | little that you need to adapt. In fact, there are only two sections that
365 | require your attention:
366 |
367 | [list_begin bullet]
368 |
369 | [bullet]
370 | The section at the top for new variables that you may have defined via
371 | the [emph AC_SUBST] macro. This section - if needed - should contain one
372 | line for each new variable like:
373 |
374 | [example {
375 | SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@
376 | }]
377 | This defines a new variable "SAMPLE_NEW_VAR" in the make file which
378 | receives the value of the variable by the same name in the configure
379 | script.
380 |
381 | [nl]
382 | [emph Note:]
383 | For the sake of simplicity, always use the same names! There is no need
384 | to get creative at this point - it will only make things more difficult.
385 |
386 | [bullet]
387 | The section containing the user-definable targets. This section may look
388 | intimidating to someone not familiar with UNIX shells or make files,
389 | but in fact, most of the code found there is completely generic.
390 | [nl]
391 | The exceptions are the targets dealing with the documentation (doc and
392 | install-doc) and with the distribution of the code as a single archive
393 | (tar-file, zip-file or whatever).
394 | [nl]
395 | The reason these targets may need to be adjusted to your needs are:
396 |
397 | [list_begin bullet]
398 |
399 | [bullet]
400 | You use a different system of documentation
401 |
402 | [bullet]
403 | You require more files from different locations to be included
404 | (residing in other directories for instance).
405 | [list_end]
406 |
407 | As it is very difficult to make these tasks generic, this remains an
408 | issue for you as an extension programmer.
409 |
410 | [list_end]
411 |
412 | [section {Making the distribution}]
413 |
414 | Once you have created the configure script, you as the author of the
415 | extension can use to create a bundled file with all the source and
416 | other files for distribution:
417 |
418 | [list_begin bullet]
419 |
420 | [bullet]
421 | Run the configure script
422 | [bullet]
423 | Run the resulting make file:
424 | [example {
425 | make dist
426 | }]
427 | [list_end]
428 |
429 | If you want other files to be generated as part of the distribution,
430 | for instance, the INSTALL file must be adjusted to include the name
431 | and purpose of your extension, then you can do so by defining a
432 | variable specific for that file and define it in the configure script:
433 |
434 | [list_begin bullet]
435 |
436 | [bullet]
437 | Define a file INSTALL.in which has a line "@MY_EXTENSION_TEXT@"
438 | in it.
439 |
440 | [bullet]
441 | Define a variable MY_EXTENSION_TEXT in the configure.ac file:
442 | [example {
443 | AC_DEFINE([MY_EXTENSION_TEXT])
444 | MY_EXTENSION_TEXT="Whatever text you want inserted"
445 | AC_SUBST([MY_EXTENSION_TEXT])
446 | }]
447 |
448 | [bullet]
449 | Add the name of the file, [emph {without the ".in" extension}], to the
450 | AC_OUTPUT macro:
451 | [example {
452 | AC_OUTPUT([Makefile INSTALL])
453 | }]
454 |
455 | [list_end]
456 |
457 |
458 | [section {Required software}]
459 |
460 | To create a working configure script via Autoconf, you will need to have
461 | Autoconf 2.50 or better. Autoconf is only needed if you are developing
462 | an extension. The users of your extension only need the configure script
463 | and the make file template.
464 | [para]
465 | Once the configure script is created, you can run it without any
466 | additional software on a UNIX/Linux/*BSD/MacOSX system, as these systems
467 | almost always have the UNIX shells and the make utility.
468 | [para]
469 | For Windows systems, you will need to have such tools as Cygwin or
470 | MingW/MSYS - both ports of the UNIX tools to Windows.
471 | [para]
472 | See the [sectref References] section for the websites where you can get
473 | this software.
474 |
475 |
476 | [section {Making the extension}]
477 | The steps taken by any user who uses the distributed source files are:
478 |
479 | [list_begin bullet]
480 |
481 | [bullet]
482 | run the configure script to tell it where to find, for instance,
483 | the Tcl/Tk header files or what C compiler to use
484 |
485 | [bullet]
486 | this script uses the file Makefile.in as a template to create
487 | the file Makefile.
488 |
489 | [bullet]
490 | when the [emph configure] script is finished, the programmer can run [emph make]
491 | to create the libraries, the programs and the documentation, ready
492 | for installation.
493 |
494 | [bullet]
495 | so, when [emph make] is done and all has been successful, the next steps
496 | can be run: run the tests and install the program(s).
497 |
498 | [list_end]
499 |
500 | The various steps are handled via special keywords in the makefile,
501 | targets that are not connected to a specific file - they are always
502 | considered out of date.
503 |
504 | [para]
505 | So, the above procedure is carried out by running the following
506 | commands on UNIX/Linux (> is the command prompt):
507 | [example {
508 | > ./configure
509 | > make
510 | > make test
511 | > make install
512 | }]
513 | (assuming all steps are successful).
514 |
515 | [para]
516 | If you want to restart (some compilation error had to solved),
517 | you would run:
518 | [example {
519 | > make clean
520 | }]
521 | to throw away most intermediate files, or:
522 | [example {
523 | > make distclean
524 | }]
525 | to start from a really clean slate.
526 |
527 | [para]
528 | TODO: how to use mingw/msys to accomplish this on Windows
529 | [para]
530 | TODO: what about Windows project files?
531 |
532 |
--------------------------------------------------------------------------------
/Makefile.in:
--------------------------------------------------------------------------------
1 | # Makefile.in --
2 | #
3 | # This file is a Makefile for Sample TEA Extension. If it has the name
4 | # "Makefile.in" then it is a template for a Makefile; to generate the
5 | # actual Makefile, run "./configure", which is a configuration script
6 | # generated by the "autoconf" program (constructs like "@foo@" will get
7 | # replaced in the actual Makefile.
8 | #
9 | # Copyright (c) 1999 Scriptics Corporation.
10 | # Copyright (c) 2002-2005 ActiveState Corporation.
11 | #
12 | # See the file "license.terms" for information on usage and redistribution
13 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 |
15 | #========================================================================
16 | # Add additional lines to handle any additional AC_SUBST cases that
17 | # have been added in a customized configure script.
18 | #========================================================================
19 |
20 | #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@
21 |
22 | #========================================================================
23 | # Nothing of the variables below this line should need to be changed.
24 | # Please check the TARGETS section below to make sure the make targets
25 | # are correct.
26 | #========================================================================
27 |
28 | #========================================================================
29 | # The names of the source files is defined in the configure script.
30 | # The object files are used for linking into the final library.
31 | # This will be used when a dist target is added to the Makefile.
32 | # It is not important to specify the directory, as long as it is the
33 | # $(srcdir) or in the generic, win or unix subdirectory.
34 | #========================================================================
35 |
36 | PKG_SOURCES = @PKG_SOURCES@
37 | PKG_OBJECTS = @PKG_OBJECTS@
38 |
39 | PKG_STUB_SOURCES = @PKG_STUB_SOURCES@
40 | PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@
41 |
42 | #========================================================================
43 | # PKG_TCL_SOURCES identifies Tcl runtime files that are associated with
44 | # this package that need to be installed, if any.
45 | #========================================================================
46 |
47 | PKG_TCL_SOURCES = @PKG_TCL_SOURCES@
48 |
49 | #========================================================================
50 | # This is a list of public header files to be installed, if any.
51 | #========================================================================
52 |
53 | PKG_HEADERS = @PKG_HEADERS@
54 |
55 | #========================================================================
56 | # "PKG_LIB_FILE" refers to the library (dynamic or static as per
57 | # configuration options) composed of the named objects.
58 | #========================================================================
59 |
60 | PKG_LIB_FILE = @PKG_LIB_FILE@
61 | PKG_LIB_FILE8 = @PKG_LIB_FILE8@
62 | PKG_LIB_FILE9 = @PKG_LIB_FILE9@
63 | PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@
64 |
65 | lib_BINARIES = $(PKG_LIB_FILE)
66 | BINARIES = $(lib_BINARIES)
67 |
68 | SHELL = @SHELL@
69 |
70 | srcdir = @srcdir@
71 | prefix = @prefix@
72 | exec_prefix = @exec_prefix@
73 |
74 | bindir = @bindir@
75 | libdir = @libdir@
76 | includedir = @includedir@
77 | datarootdir = @datarootdir@
78 | runstatedir = @runstatedir@
79 | datadir = @datadir@
80 | mandir = @mandir@
81 |
82 | DESTDIR =
83 |
84 | PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION)
85 | pkgdatadir = $(datadir)/$(PKG_DIR)
86 | pkglibdir = $(libdir)/$(PKG_DIR)
87 | pkgincludedir = $(includedir)/$(PKG_DIR)
88 |
89 | top_builddir = @abs_top_builddir@
90 |
91 | INSTALL_OPTIONS =
92 | INSTALL = @INSTALL@ $(INSTALL_OPTIONS)
93 | INSTALL_DATA_DIR = @INSTALL_DATA_DIR@
94 | INSTALL_DATA = @INSTALL_DATA@
95 | INSTALL_PROGRAM = @INSTALL_PROGRAM@
96 | INSTALL_SCRIPT = @INSTALL_SCRIPT@
97 | INSTALL_LIBRARY = @INSTALL_LIBRARY@
98 |
99 | PACKAGE_NAME = @PACKAGE_NAME@
100 | PACKAGE_VERSION = @PACKAGE_VERSION@
101 | CC = @CC@
102 | CCLD = @CCLD@
103 | CFLAGS_DEFAULT = @CFLAGS_DEFAULT@
104 | CFLAGS_WARNING = @CFLAGS_WARNING@
105 | EXEEXT = @EXEEXT@
106 | MAKE_LIB = @MAKE_LIB@
107 | MAKE_STUB_LIB = @MAKE_STUB_LIB@
108 | OBJEXT = @OBJEXT@
109 | RANLIB = @RANLIB@
110 | RANLIB_STUB = @RANLIB_STUB@
111 | SHLIB_CFLAGS = @SHLIB_CFLAGS@
112 | SHLIB_LD = @SHLIB_LD@
113 | SHLIB_LD_LIBS = @SHLIB_LD_LIBS@
114 | STLIB_LD = @STLIB_LD@
115 | #TCL_DEFS = @TCL_DEFS@
116 | TCL_BIN_DIR = @TCL_BIN_DIR@
117 | TCL_SRC_DIR = @TCL_SRC_DIR@
118 | #TK_BIN_DIR = @TK_BIN_DIR@
119 | #TK_SRC_DIR = @TK_SRC_DIR@
120 |
121 | # Not used, but retained for reference of what libs Tcl required
122 | #TCL_LIBS = @TCL_LIBS@
123 |
124 | #========================================================================
125 | # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our
126 | # package without installing. The other environment variables allow us
127 | # to test against an uninstalled Tcl. Add special env vars that you
128 | # require for testing here (like TCLX_LIBRARY).
129 | #========================================================================
130 |
131 | EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR)
132 | #EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR)
133 | TCLLIBPATH = $(top_builddir)
134 | TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library`
135 | PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
136 | PATH="$(EXTRA_PATH):$(PATH)" \
137 | TCLLIBPATH="$(TCLLIBPATH)"
138 |
139 | TCLSH_PROG = @TCLSH_PROG@
140 | TCLSH = $(TCLSH_ENV) $(PKG_ENV) $(TCLSH_PROG)
141 |
142 | #WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library`
143 | #WISH_PROG = @WISH_PROG@
144 | #WISH = $(TCLSH_ENV) $(WISH_ENV) $(PKG_ENV) $(WISH_PROG)
145 |
146 | SHARED_BUILD = @SHARED_BUILD@
147 |
148 | INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ -I.
149 | #INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@
150 |
151 | PKG_CFLAGS = @PKG_CFLAGS@
152 |
153 | # TCL_DEFS is not strictly need here, but if you remove it, then you
154 | # must make sure that configure.ac checks for the necessary components
155 | # that your library may use. TCL_DEFS can actually be a problem if
156 | # you do not compile with a similar machine setup as the Tcl core was
157 | # compiled with.
158 | #DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS)
159 | DEFS = @DEFS@ $(PKG_CFLAGS)
160 |
161 | # Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile
162 | CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl
163 | CLEANFILES = @CLEANFILES@
164 |
165 | CPPFLAGS = @CPPFLAGS@
166 | LIBS = @PKG_LIBS@ @LIBS@
167 | AR = @AR@
168 | CFLAGS = @CFLAGS@
169 | LDFLAGS = @LDFLAGS@
170 | LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
171 | COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) \
172 | $(CFLAGS)
173 |
174 | GDB = gdb
175 | VALGRIND = valgrind
176 | VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \
177 | --leak-check=yes --show-reachable=yes -v
178 |
179 | .SUFFIXES: .c .$(OBJEXT)
180 |
181 | #========================================================================
182 | # Start of user-definable TARGETS section
183 | #========================================================================
184 |
185 | #========================================================================
186 | # TEA TARGETS. Please note that the "libraries:" target refers to platform
187 | # independent files, and the "binaries:" target includes executable programs and
188 | # platform-dependent libraries. Modify these targets so that they install
189 | # the various pieces of your package. The make and install rules
190 | # for the BINARIES that you specified above have already been done.
191 | #========================================================================
192 |
193 | all: binaries libraries doc
194 |
195 | #========================================================================
196 | # The binaries target builds executable programs, Windows .dll's, unix
197 | # shared/static libraries, and any other platform-dependent files.
198 | # The list of targets to build for "binaries:" is specified at the top
199 | # of the Makefile, in the "BINARIES" variable.
200 | #========================================================================
201 |
202 | binaries: $(BINARIES)
203 |
204 | libraries:
205 |
206 | #========================================================================
207 | # Your doc target should differentiate from doc builds (by the developer)
208 | # and doc installs (see install-doc), which just install the docs on the
209 | # end user machine when building from source.
210 | #========================================================================
211 |
212 | doc:
213 | @echo "If you have documentation to create, place the commands to"
214 | @echo "build the docs in the 'doc:' target. For example:"
215 | @echo " xml2nroff sample.xml > sample.n"
216 | @echo " xml2html sample.xml > sample.html"
217 |
218 | install: all install-binaries install-libraries install-doc
219 |
220 | install-binaries: binaries install-lib-binaries install-bin-binaries
221 |
222 | #========================================================================
223 | # This rule installs platform-independent files, such as header files.
224 | # The list=...; for p in $$list handles the empty list case x-platform.
225 | #========================================================================
226 |
227 | install-libraries: libraries
228 | @$(INSTALL_DATA_DIR) "$(DESTDIR)$(includedir)"
229 | @echo "Installing header files in $(DESTDIR)$(includedir)"
230 | @list='$(PKG_HEADERS)'; for i in $$list; do \
231 | echo "Installing $(srcdir)/$$i" ; \
232 | $(INSTALL_DATA) $(srcdir)/$$i "$(DESTDIR)$(includedir)" ; \
233 | done;
234 |
235 | #========================================================================
236 | # Install documentation. Unix manpages should go in the $(mandir)
237 | # directory.
238 | #========================================================================
239 |
240 | install-doc: doc
241 | @$(INSTALL_DATA_DIR) "$(DESTDIR)$(mandir)/mann"
242 | @echo "Installing documentation in $(DESTDIR)$(mandir)"
243 | @list='$(srcdir)/doc/*.n'; for i in $$list; do \
244 | echo "Installing $$i"; \
245 | $(INSTALL_DATA) $$i "$(DESTDIR)$(mandir)/mann" ; \
246 | done
247 |
248 | test: binaries libraries
249 | $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \
250 | -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \
251 | [list load `@CYGPATH@ $(PKG_LIB_FILE)` [string totitle $(PACKAGE_NAME)]]"
252 |
253 | shell: binaries libraries
254 | @$(TCLSH) $(SCRIPT)
255 |
256 | gdb:
257 | $(TCLSH_ENV) $(PKG_ENV) $(GDB) $(TCLSH_PROG) $(SCRIPT)
258 |
259 | gdb-test: binaries libraries
260 | $(TCLSH_ENV) $(PKG_ENV) $(GDB) \
261 | --args $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` \
262 | $(TESTFLAGS) -singleproc 1 \
263 | -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \
264 | [list load `@CYGPATH@ $(PKG_LIB_FILE)` [string totitle $(PACKAGE_NAME)]]"
265 |
266 | valgrind: binaries libraries
267 | $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) \
268 | `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS)
269 |
270 | valgrindshell: binaries libraries
271 | $(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT)
272 |
273 | depend:
274 |
275 | #========================================================================
276 | # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable
277 | # mentioned above. That will ensure that this target is built when you
278 | # run "make binaries".
279 | #
280 | # The $(PKG_OBJECTS) objects are created and linked into the final
281 | # library. In most cases these object files will correspond to the
282 | # source files above.
283 | #========================================================================
284 |
285 | $(PKG_LIB_FILE): $(PKG_OBJECTS)
286 | -rm -f $(PKG_LIB_FILE)
287 | ${MAKE_LIB}
288 | $(RANLIB) $(PKG_LIB_FILE)
289 |
290 | $(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS)
291 | -rm -f $(PKG_STUB_LIB_FILE)
292 | ${MAKE_STUB_LIB}
293 | $(RANLIB_STUB) $(PKG_STUB_LIB_FILE)
294 |
295 | #========================================================================
296 | # We need to enumerate the list of .c to .o lines here.
297 | #
298 | # In the following lines, $(srcdir) refers to the toplevel directory
299 | # containing your extension. If your sources are in a subdirectory,
300 | # you will have to modify the paths to reflect this:
301 | #
302 | # sample.$(OBJEXT): $(srcdir)/generic/sample.c
303 | # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@
304 | #
305 | # Setting the VPATH variable to a list of paths will cause the makefile
306 | # to look into these paths when resolving .c to .obj dependencies.
307 | # As necessary, add $(srcdir):$(srcdir)/compat:....
308 | #========================================================================
309 |
310 | VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macosx
311 |
312 | .c.@OBJEXT@:
313 | $(COMPILE) -c `@CYGPATH@ $<` -o $@
314 |
315 | tclsample.@OBJEXT@: sampleUuid.h
316 |
317 | $(srcdir)/manifest.uuid:
318 | printf "git-" >$(srcdir)/manifest.uuid
319 | (cd $(srcdir); git rev-parse HEAD >>$(srcdir)/manifest.uuid || \
320 | (printf "svn-r" >$(srcdir)/manifest.uuid ; \
321 | svn info --show-item last-changed-revision >>$(srcdir)/manifest.uuid) || \
322 | printf "unknown" >$(srcdir)/manifest.uuid)
323 |
324 | sampleUuid.h: $(srcdir)/manifest.uuid
325 | echo "#define SAMPLE_VERSION_UUID \\" >$@
326 | cat $(srcdir)/manifest.uuid >>$@
327 | echo "" >>$@
328 |
329 | #========================================================================
330 | # Distribution creation
331 | # You may need to tweak this target to make it work correctly.
332 | #========================================================================
333 |
334 | #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar
335 | COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR)
336 | DIST_ROOT = /tmp/dist
337 | DIST_DIR = $(DIST_ROOT)/$(PKG_DIR)
338 |
339 | DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644
340 | DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755
341 |
342 | dist-clean:
343 | rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.*
344 |
345 | dist: dist-clean $(srcdir)/manifest.uuid
346 | $(INSTALL_DATA_DIR) $(DIST_DIR)
347 |
348 | # TEA files
349 | $(DIST_INSTALL_DATA) $(srcdir)/Makefile.in \
350 | $(srcdir)/aclocal.m4 $(srcdir)/configure.ac \
351 | $(DIST_DIR)/
352 | $(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/
353 |
354 | $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig
355 | $(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \
356 | $(srcdir)/manifest.uuid \
357 | $(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \
358 | $(DIST_DIR)/tclconfig/
359 |
360 | # Extension files
361 | $(DIST_INSTALL_DATA) \
362 | $(srcdir)/ChangeLog \
363 | $(srcdir)/README.sha \
364 | $(srcdir)/license.terms \
365 | $(srcdir)/README \
366 | $(srcdir)/pkgIndex.tcl.in \
367 | $(DIST_DIR)/
368 |
369 | list='demos doc generic library macosx tests unix win'; \
370 | for p in $$list; do \
371 | if test -d $(srcdir)/$$p ; then \
372 | $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \
373 | $(DIST_INSTALL_DATA) $(srcdir)/$$p/* $(DIST_DIR)/$$p/; \
374 | fi; \
375 | done
376 |
377 | (cd $(DIST_ROOT); $(COMPRESS);)
378 |
379 | #========================================================================
380 | # End of user-definable section
381 | #========================================================================
382 |
383 | #========================================================================
384 | # Don't modify the file to clean here. Instead, set the "CLEANFILES"
385 | # variable in configure.ac
386 | #========================================================================
387 |
388 | clean:
389 | -test -z "$(BINARIES)" || rm -f $(BINARIES)
390 | -rm -f *.$(OBJEXT) core *.core
391 | -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
392 |
393 | distclean: clean
394 | -rm -f *.tab.c
395 | -rm -f $(CONFIG_CLEAN_FILES)
396 | -rm -f config.cache config.log config.status
397 |
398 | #========================================================================
399 | # Install binary object libraries. On Windows this includes both .dll and
400 | # .lib files. Because the .lib files are not explicitly listed anywhere,
401 | # we need to deduce their existence from the .dll file of the same name.
402 | # Library files go into the lib directory.
403 | # In addition, this will generate the pkgIndex.tcl
404 | # file in the install location (assuming it can find a usable tclsh shell)
405 | #
406 | # You should not have to modify this target.
407 | #========================================================================
408 |
409 | install-lib-binaries: binaries
410 | @$(INSTALL_DATA_DIR) "$(DESTDIR)$(pkglibdir)"
411 | @list='$(lib_BINARIES)'; for p in $$list; do \
412 | if test -f $$p; then \
413 | echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
414 | $(INSTALL_LIBRARY) $$p "$(DESTDIR)$(pkglibdir)/$$p"; \
415 | ext=`echo $$p|sed -e "s/.*\.//"`; \
416 | if test "x$$ext" = "xdll"; then \
417 | lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \
418 | if test -f $$lib; then \
419 | echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \
420 | $(INSTALL_DATA) $$lib "$(DESTDIR)$(pkglibdir)/$$lib"; \
421 | fi; \
422 | fi; \
423 | fi; \
424 | done
425 | @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
426 | if test -f $(srcdir)/$$p; then \
427 | destp=`basename $$p`; \
428 | echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \
429 | $(INSTALL_DATA) $(srcdir)/$$p "$(DESTDIR)$(pkglibdir)/$$destp"; \
430 | fi; \
431 | done
432 | @if test "x$(SHARED_BUILD)" = "x1"; then \
433 | echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \
434 | $(INSTALL_DATA) pkgIndex.tcl "$(DESTDIR)$(pkglibdir)"; \
435 | fi
436 |
437 | #========================================================================
438 | # Install binary executables (e.g. .exe files and dependent .dll files)
439 | # This is for files that must go in the bin directory (located next to
440 | # wish and tclsh), like dependent .dll files on Windows.
441 | #
442 | # You should not have to modify this target, except to define bin_BINARIES
443 | # above if necessary.
444 | #========================================================================
445 |
446 | install-bin-binaries: binaries
447 | @$(INSTALL_DATA_DIR) "$(DESTDIR)$(bindir)"
448 | @list='$(bin_BINARIES)'; for p in $$list; do \
449 | if test -f $$p; then \
450 | echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \
451 | $(INSTALL_PROGRAM) $$p "$(DESTDIR)$(bindir)/$$p"; \
452 | fi; \
453 | done
454 |
455 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
456 | cd $(top_builddir) \
457 | && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
458 |
459 | uninstall-binaries:
460 | list='$(lib_BINARIES)'; for p in $$list; do \
461 | rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
462 | done
463 | list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
464 | p=`basename $$p`; \
465 | rm -f "$(DESTDIR)$(pkglibdir)/$$p"; \
466 | done
467 | list='$(bin_BINARIES)'; for p in $$list; do \
468 | rm -f "$(DESTDIR)$(bindir)/$$p"; \
469 | done
470 |
471 | .PHONY: all binaries clean depend distclean doc install libraries test
472 | .PHONY: gdb gdb-test valgrind valgrindshell
473 |
474 | # Tell versions [3.59,3.63) of GNU make to not export all variables.
475 | # Otherwise a system limit (for SysV at least) may be exceeded.
476 | .NOEXPORT:
477 |
--------------------------------------------------------------------------------
/tea/design.txt:
--------------------------------------------------------------------------------
1 | [section {Chapter 2. DESIGN AND CODING}]
2 |
3 | [section {Tcl extensions}]
4 | [para]
5 |
6 | In this document a [emph {Tcl extension}] is simply a collection of Tcl
7 | commands that can be distributed separately: an extension can be used
8 | in any application that wants to use the functionality it offers.
9 |
10 | [para]
11 |
12 | Well-known examples of extensions are:
13 | [list_begin bullet]
14 | [bullet]
15 | [emph msgcat]: translate text in an application that is to be shown to
16 | the user into the language that the user prefers. It is a collection
17 | of Tcl scripts that is shipped with Tcl itself.
18 |
19 | [bullet]
20 | [emph tktable]: a sophisticated widget to display and manipulate tabular
21 | data. In contrast to [emph msgcat], it is a [emph compiled] extension,
22 | consisting of both Tcl scripts and a loadable library of C functions.
23 |
24 | [bullet]
25 | [emph snack]: play and record sound from within a Tcl application. This
26 | extension relies on the presence of specific hardware and software (the computer
27 | must have audio capabilities). Such an extension is more complicated
28 | to maintain than either of the two others - you need to be aware of the
29 | typical libraries that are available on the various platforms and of
30 | the typical hardware that people use.
31 |
32 | [bullet]
33 | [emph tkimg]: manipulate images and image files with the support of a
34 | number of external libraries.
35 |
36 | [list_end]
37 |
38 | [para]
39 | Each of the four extensions we described exemplifies a category of
40 | extensions:
41 |
42 | [list_begin bullet]
43 |
44 | [bullet]
45 | Tcl-only extensions
46 |
47 | [bullet]
48 | Extensions built from Tcl and C code, but which are more or less
49 | independent of the operating system
50 |
51 | [bullet]
52 | Extensions built from Tcl and C code that do need to take care of the
53 | particular operating system
54 |
55 | [bullet]
56 | Extensions built from Tcl and C code that export new compiled
57 | functions (not commands!) to the Tcl interpreter. This adds an extra
58 | complication to the build process (see also the chapter on the stubs
59 | mechanism).
60 |
61 | [list_end]
62 |
63 | [emph Note:]
64 | [para]
65 | We have talked about C code, not because it is the only possibility, but
66 | because it is the most commonly used compiled language to extend Tcl. It
67 | is very well possible to use C++ or Fortran to build libraries that can
68 | be used from Tcl scripts. However, we will not go into these matters,
69 | they are beyond the scope of this document.
70 |
71 | [para]
72 | [emph Note:]
73 | [para]
74 | It is somewhat confusing that we use the words packages, extensions and
75 | modules to mean the same thing: Tcl commands or procedures that can be
76 | added to an application from some generally useable collection. The words
77 | each indicate a slightly different viewpoint:
78 |
79 | [list_begin bullet]
80 | [bullet]
81 | [emph package] refers to the mechanism by which a programmer loads the
82 | commands into his or her application: the commands are treated as a
83 | single collection.
84 |
85 | [bullet]
86 | [emph module] is often used to refer to a smaller collection inside a
87 | collection that is otherwise known as a whole, such as the
88 | Tcllib collection. Such large collections can be very heterogeneous,
89 | mixing network facilities with text processing facilities for
90 | instance.
91 |
92 | [bullet]
93 | [emph extension] is mostly used when a collection of commands is built
94 | from C sources, rather than Tcl scripts only, and it refers to both
95 | the source code and the actual compiled library or libraries.
96 |
97 | [list_end]
98 |
99 | Actually, all these terms can be used interchangeably and rather than
100 | invent a new word to replace them all, we will simply use all three
101 | terms, depending on the context.
102 |
103 | [para]
104 | Let us examine each of the above types of extensions in more detail in
105 | the next few sections.
106 |
107 | [section {Tcl-only extensions}]
108 |
109 | If you have a collection of Tcl scripts that you would like to distribute
110 | as a whole to others, then the situation is easy:
111 |
112 | [list_begin bullet]
113 | [bullet]
114 | Provide proper documentation, so that people can understand the extension
115 | without having to understand the code.
116 |
117 | [bullet]
118 | Provide the code as a package (more on the [emph package] mechanism in Chapter ..)
119 |
120 | [bullet]
121 | Wrap it in a zip-file or a tar-ball and put it on the Internet.
122 |
123 | [list_end]
124 |
125 | Well, things are a bit more complex than that. Let us have a look again at
126 | the [emph msgcat] extension as it is present in any or all Tcl installations:
127 |
128 | [list_begin bullet]
129 |
130 | [bullet]
131 | It lives in a directory of its own under the lib/tcl8.x directory
132 |
133 | [bullet]
134 | The file "pkgIndex.tcl" is used by the [emph {package require}] command to
135 | identify the presence of the package or extension and how to get it
136 | into the application (*).
137 |
138 | [bullet]
139 | Because it is used in Tk, you will find a few message catalogue files
140 | in the lib/tk8.x/msgs directory to translate text that appears in
141 | the wish window to the user's language.
142 |
143 | [list_end]
144 |
145 | (*) Note the uppercase "i" in this name: under Windows file names may be
146 | case-insensitive, this is not so under UNIX/Linux and many other
147 | operating systems. So, please take note of the precise spelling of
148 | file names.
149 |
150 | [para]
151 | Here is an excerpt of the directory that holds the extension itself (we
152 | used Tcl8.6 for this):
153 | [example {
154 | lib/
155 | tcl8.6/
156 | msgcat1.3/
157 | msgcat.tcl
158 | pkgIndex.tcl
159 | }]
160 | In the source distribution, we can also find the file "msgcat.test"
161 | (containing the test cases) in the directory "tests" and the
162 | documentation in the file "msgcat.man".
163 |
164 | [para]
165 | The number "1.3" at the end of the directory name is no coincidence: it
166 | is the version number of the [emph msgcat] package. This way you can keep
167 | various versions of a package around.
168 |
169 | [para]
170 | In Tcllib, such a collection of files is found more commonly
171 | together, like for the CRC module:
172 | [example {
173 | tcllib/
174 | modules/
175 | crc/
176 | ChangeLog file containing short descriptions of
177 | changes over time
178 | cksum.man the documentation file
179 | cksum.tcl the actual Tcl script that implements
180 | the cksum command
181 | cksum.test the test cases
182 | ... (other related sources)
183 | }]
184 |
185 | There is no "pkgIndex.tcl" script, as this is created by the
186 | installation procedure for Tcllib as a whole.
187 |
188 |
189 |
190 | [section {Extensions that are platform-independent}]
191 |
192 | A well-known extension like Tktable has to be built for all platforms
193 | that Tcl supports. Tktable itself does not have (much) code that differs
194 | from platform to platform. Yet, as the directory structure shows, it
195 | does have directories specific for the major platform categories,
196 | [emph {in the same way as do Tcl and Tk themselves}]:
197 | [example {
198 | tktable/
199 | demos/ directory with demonstration scripts
200 | doc/ documentation
201 | generic/ the platform-independent sources
202 | library/ supporting scripts (in this case: key
203 | bindings and such)
204 | mac/ mac-specific sources (here: the
205 | project-file for building on Mac)
206 | tclconfig/ scripts that are used while building
207 | the extension
208 | tests/ test scripts
209 | unix/ unix-specific sources (here: nothing???)
210 | win/ Windows-specific sources (here: the
211 | project-file for building on Windows)
212 | ChangeLog description of changes
213 | Makefile.in TEA-template for the makefile
214 | aclocal.m4 "include" file required by Autoconf
215 | configure configure script generated by Autoconf
216 | configure.ac TEA-template for the configure script
217 | ... (others files, not related to the building
218 | process itself)
219 | }]
220 |
221 | In this overview you will see some files related to the TEA, most
222 | notably, [emph Makefile.in] and [emph configure.ac]. These will be described in
223 | great detail in Chapter 7 (fortunately the details have become less and
224 | less painful with the further development of TEA).
225 |
226 | [para]
227 | The most important thing is that this extension uses the [emph same]
228 | directory structure as Tcl/Tk itself. This may not always seem necessary
229 | (for instance, a Windows-specific extension might do without the unix
230 | and mac directories), but by keeping this same structure, you make it
231 | easier for others to manoeuvre through the source directory: they know
232 | what to expect.
233 |
234 | [section {Platform-dependent extensions}]
235 |
236 | Extensions that depend on the particular platform may need to deal with
237 | various OS aspects:
238 |
239 | [list_begin bullet]
240 |
241 | [bullet]
242 | They may require specific OS libraries
243 |
244 | [bullet]
245 | They may have extensive source code that is platform-dependent
246 |
247 | [bullet]
248 | They may have to deal with deficiencies of the platform, such as
249 | broken implementations of some standard library function (functions
250 | like strtod() are notorious in this respect)
251 |
252 | [list_end]
253 |
254 | The directory structure described in the previous section is
255 | quite useable in this case too. The platform-dependencies are expressed
256 | in the mac, unix and win directories containing one or more source files
257 | (not just project or make files), but also in the configure.ac and
258 | Makefile.in files containing extra code to find the relevant
259 | OS libraries or checks for deficiencies.
260 |
261 | [section {Extensions exporting their own functions}]
262 |
263 | Complications arise when extensions need to export their own
264 | (compiled) functions, to provide their functionality. Again, this is not
265 | so much a matter of the directory structure, as it is a problem for
266 | building the extension.
267 |
268 | [para]
269 | In [emph tkimg] this is necessary because the photo command must have
270 | access to the functions that [emph tkimg] supplies. To do this in a way
271 | that does not tie [emph tkimg] to a particular version of Tcl/Tk, the
272 | stubs mechanism (see Chapter 5) is needed.
273 |
274 | [para]
275 | A simpler extension that provides its own stubs library is the backport
276 | of the dictionary data structure that is new in Tcl 8.5 to Tcl 4.x
277 | (done by Pascal Scheffers, ). The stubs
278 | library allows other extensions to use the functionality this [emph dict]
279 | extension provides, in much the same way as you can use the general Tcl
280 | API. We will discuss the implications in the next section and in the
281 | chapter on Tcl stubs.
282 |
283 | [section {Coding a C extension}]
284 |
285 | Now that we have covered the directory structure an extension should
286 | use, let us have a quick look at the C source code itself. (This is not
287 | a tutorial about how to use the Tcl/Tk API to build new
288 | compiled extensions. We simpy give some very basic information.)
289 |
290 | [para]
291 | A C extension, like the example that comes with TEA, contains an
292 | (exported) function with a specific name: Package_Init(), where
293 | "Package" is to be replaced by the name of the package (the first letter
294 | is capitalised, the rest is in lower-case). Here is the skeleton code
295 | for such a function:
296 |
297 | [example {
298 | int
299 | Package_Init(Tcl_Interp *interp)
300 | {
301 | /* Initialise the stubs library - see chapter 5
302 | */
303 | if (Tcl_InitStubs(interp, "8.6-", 0) == NULL) {
304 | return TCL_ERROR;
305 | }
306 |
307 | /* Require some version of Tcl, at least 8.0
308 | */
309 | if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
310 | return TCL_ERROR;
311 | }
312 |
313 | /* Make the package known
314 | */
315 | if (Tcl_PkgProvide(interp, "Package", VERSION) != TCL_OK) {
316 | return TCL_ERROR;
317 | }
318 |
319 | /* Create all the commands:
320 | Tcl command "cmd1" is implemented by the function Cmd1,
321 | etc.
322 | */
323 | Tcl_CreateObjCommand(interp, "cmd1", Cmd1, NULL, NULL);
324 | ... other commands ...
325 |
326 | return TCL_OK;
327 | }
328 | }]
329 |
330 | The functions that actually implement the Tcl commands are usually
331 | static functions, so that there is no name clash with other libraries.
332 |
333 | [para]
334 | The structure of the functions can be anything you like, but it is usual
335 | to:
336 |
337 | [list_begin bullet]
338 |
339 | [bullet]
340 | first check if the correct number of arguments is used
341 |
342 | [bullet]
343 | then dispatch on the first argument, in case subcommands are used
344 |
345 | [list_end]
346 |
347 | [example {
348 | (Code example)
349 | }]
350 |
351 | [para]
352 | The functions that your extension implements for public use should be
353 | properly prototyped via a header file - this is a matter of C coding
354 | style, but it also gives other people the opportunity to use your
355 | extension in their C extension.
356 |
357 | [para]
358 | The header file for an extension also contains the magic for
359 | building it on various platforms. To explain this magic and what you
360 | should be aware of, have a look at the header file of the sample
361 | extension:
362 |
363 | [example {
364 | /*
365 | * examplea.h --
366 | *
367 | * This header file contains the function declarations needed for
368 | * all of the source files in this package.
369 | *
370 | * Copyright (c) 1998-1999 Scriptics Corporation.
371 | *
372 | * See the file "license.terms" for information on usage and redistribution
373 | * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
374 | *
375 | */
376 |
377 | #ifndef _EXAMPLEA
378 | #define _EXAMPLEA
379 |
380 | #include
381 |
382 | /*
383 | * Windows needs to know which symbols to export.
384 | */
385 |
386 | #ifdef BUILD_examplea
387 | #undef TCL_STORAGE_CLASS
388 | #define TCL_STORAGE_CLASS DLLEXPORT
389 | #endif /* BUILD_examplea */
390 |
391 | typedef struct {
392 | unsigned long state[5];
393 | unsigned long count[2];
394 | unsigned char buffer[64];
395 | } SHA1_CTX;
396 |
397 | void SHA1Init (SHA1_CTX* context);
398 | void SHA1Update (SHA1_CTX* context, unsigned char* data,
399 | size_t len);
400 | void SHA1Final (SHA1_CTX* context, unsigned char digest[20]);
401 |
402 | /*
403 | * Only the _Init function is exported.
404 | */
405 |
406 | EXTERN int Examplea_Init (Tcl_Interp * interp);
407 |
408 | #endif /* _EXAMPLEA */
409 | }]
410 |
411 | Explanation:
412 |
413 | [list_begin bullet]
414 |
415 | [bullet]
416 | The header file starts with a standard information block, describing
417 | the extension it belongs to.
418 |
419 | [bullet]
420 | The actual declarations are "bracketed" by an #ifndef/#endif pair to
421 | avoid multiple inclusions.
422 |
423 | [bullet]
424 | It includes the public Tcl header for access to the Tcl API,
425 | [emph {but not the private header file}] (see the recommendations section).
426 |
427 | [bullet]
428 | There is a piece of magic involving Windows builds: the macro
429 | BUILD_examplea controls this. This is a macro that is defined via the
430 | [emph configure] file - more about this in Chapter 7. Note: this is
431 | boiler-plate stuff, only the name of the macro needs to be adjusted.
432 |
433 | [bullet]
434 | Most of what follows is specific to the extension:
435 |
436 | [list_begin bullet]
437 | [bullet]
438 | The definition of the structure that this extension uses
439 | [bullet]
440 | The prototypes for the public functions in the SHA1 library
441 | (the example extension is a wrapper for that library)
442 | [bullet]
443 | The last few lines concern the initialisation procedure, here
444 | again some magic, controlled by the EXTERN macro.
445 | [list_end]
446 |
447 | [list_end]
448 |
449 | If the extension provides its own [emph {stubs library}], then:
450 | [list_begin bullet]
451 |
452 | [bullet]
453 | add the following code fragments to the header file for your extension:
454 |
455 | [example {
456 | EXTERN const char * Examplea_InitStubs
457 | (Tcl_Interp *interp,
458 | const char *version, int exact);
459 |
460 | #ifndef USE_TCL_STUBS
461 |
462 | /*
463 | * When not using stubs, make it a macro.
464 | */
465 |
466 | #define Examplea_InitStubs(interp, version, exact) \\
467 | Tcl_PkgRequire(interp, "examplea", version, exact)
468 |
469 | #endif /* USE_TCL_STUBS */
470 |
471 | /*
472 | * Include the public function declarations that are accessible via
473 | * the stubs table.
474 | */
475 |
476 | #include "exampleaDecls.h"}]
477 |
478 | [bullet]
479 | prepare a declarations file (examplea.dict) that contains the
480 | definitions of all functions available via the stubs library.
481 | Here is a fragment of the dict extension:
482 |
483 | [example {
484 | # dict.decls --
485 | #
486 | # This file contains the declarations for all supported public
487 | # functions that are exported by the Dict Tcl library via the
488 | # stubs table.
489 | # This file is used to generate the dictDecls.h and dictStub.c files.
490 | #
491 | #
492 | # Copyright (c) 1998-1999 by Scriptics Corporation.
493 | # Copyright (c) 2001, 2002 by Kevin B. Kenny. All rights reserved.
494 | # See the file "license.terms" for information on usage and redistribution
495 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
496 | #
497 | # Branched from:
498 | # RCS: @(#) Id: tcl.decls,v 1.103 2004/03/17 18:14:12 das Exp
499 | # for the dict backport.
500 |
501 | library dict
502 |
503 | # Define the dict interface, no sub interfaces.
504 |
505 | interface dict
506 | #hooks {}
507 |
508 | # Declare each of the functions in the public dict interface. Note that
509 | # the an index should never be reused for a different function in order
510 | # to preserve backwards compatibility.
511 |
512 | # DICTIONARIES - TIP#111
513 | declare 0 generic {
514 | int Tcl_DictObjPut(Tcl_Interp *interp, Tcl_Obj *dictPtr,
515 | Tcl_Obj *keyPtr, Tcl_Obj *valuePtr)
516 | }
517 | declare 1 generic {
518 | int Tcl_DictObjGet(Tcl_Interp *interp, Tcl_Obj *dictPtr,
519 | Tcl_Obj *keyPtr, Tcl_Obj **valuePtrPtr)
520 | }
521 | }]
522 |
523 | This file (yes, simply Tcl code) is processed by the tools/genStubs.tcl
524 | script to produce the "exampleaDecls.h" header file and the code for
525 | the stubs library. (Most of this is taken care of automatically -
526 | just make sure that the above steps are properly taken).
527 |
528 | [list_end]
529 |
530 | [section {Some recommendations}]
531 |
532 | We conclude this chapter with the following general recommendations:
533 |
534 | [list_begin bullet]
535 |
536 | [bullet]
537 | Use the Tcl_Obj interface, instead of the older string
538 | interface, as it is easier to work with and especially because
539 | it results in faster command processing.
540 |
541 | [bullet]
542 | If your use options, use key-value pairs, like in the Tk
543 | widgets:
544 | [example {
545 | $w configure -foreground black
546 | }]
547 |
548 | The reason is that this gives you much more freedom (options are known
549 | to expand over time, often you want to explicitly negate an option and
550 | inventing new keywords is more troublesome than just a new value.
551 |
552 | [bullet]
553 | Use only the public API of Tcl/Tk or any other extension.
554 | Otherwise your extension becomes tied to one particular version of
555 | Tcl/Tk, forbidding use in Tclkit for instance. What is more, if these
556 | internals change, you will have to change your extension as well.
557 | The public API is very unlikely to change, and if it changes, then
558 | backward compatibility is almost guaranteed (like with the string
559 | interface that still exists).
560 |
561 | [list_end]
562 |
563 | [para]
564 | [emph TODO:]
565 | Refer to TIP #55 and to Tcllib
566 | Describe a preferred directory structure (based on TIP #55)
567 | What about namespaces?
568 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
1 | 2015-08-28 Jan Nijtmans
2 |
3 | * configure: Rfe [00189c4afc]: Allow semi-static UCRT build on
4 | * win/makefile.vc Windows with VC 14.0
5 | * win/rules.vc
6 |
7 | 2013-07-04 Jan Nijtmans
8 |
9 | * configure: Regenerated to use latest TEA tcl.m4.
10 | * Makefile.in: Make test-suite runnable from installed directory.
11 |
12 | 2013-07-02 Jan Nijtmans
13 |
14 | * configure: Regenerated to use latest TEA tcl.m4.
15 | * Makefile.in: Use $(INSTALL_DATA_DIR) in stead of mkdir.
16 | * .fossil-settings/*: Versioned settings for fossil.
17 |
18 | 2012-08-17 Jan Nijtmans
19 |
20 | * win/nmakehlp.c: Add "-V" option, in order to be able
21 | to detect partial version numbers.
22 |
23 | 2012-08-12 Jan Nijtmans
24 |
25 | * configure: Regenerated to use latest TEA tcl.m4.
26 | * win/rules.vc: Remove some unused code, always set
27 | USE_THREAD_ALLOC in combination with TCL_THREADS
28 |
29 | 2010-08-03 Stuart Cassoff
30 |
31 | * ChangeLog: Zap trailing whitespace.
32 | * README.sha: No functional change.
33 | * win/nmakehlp.c:
34 | * Makefile.in: DON'T use gnu tar; use normal tar.
35 |
36 | 2010-08-02 Stuart Cassoff
37 |
38 | * README.sha: Zap trailing whitespace.
39 | * doc/sha1.n: No functional change.
40 | * generic/sample.c:
41 | * generic/tclsample.c:
42 | * license.terms:
43 | * win/makefile.vc:
44 | * ChangeLog: Fix wrong date in previous ChangeLog entry.
45 |
46 | 2010-08-01 Stuart Cassoff
47 |
48 | * Makefile.in: Tidy: Whitespace, formatting, spelling.
49 | * configure.in: No functional change.
50 |
51 | 2012-08-01 Jan Nijtmans
52 |
53 | * win/makefile.vc: Sync with latest Tcl 8.6 updates
54 | * win/rules.vc:
55 | * win/pkg.vc:
56 |
57 | 2012-02-27 Jan Nijtmans
58 |
59 | * configure: Regenerated to use latest TEA tcl.m4.
60 | * : Purge RCS keywords.
61 |
62 | 2010-12-15 Stuart Cassoff
63 |
64 | * configure.in: Upgrade to newer install-sh and use it.
65 | * Makefile.in:
66 | * configure: Regenerated to use latest TEA tcl.m4.
67 |
68 | 2010-12-14 Stuart Cassoff
69 |
70 | * configure: Regenerated to use latest TEA tcl.m4.
71 | Better building on OpenBSD.
72 |
73 | 2010-12-14 Stuart Cassoff
74 |
75 | * Makefile.in: Make .SUFFIXES work for more (BSD) make programs.
76 |
77 | 2010-12-14 Jan Nijtmans
78 |
79 | * configure: Regenerated to use latest TEA tcl.m4.
80 | This adds cross-compile support to UNIX and Win, and
81 | support for building 64-bit executables with mingw-w64
82 | build tools.
83 |
84 | 2010-09-14 Jeff Hobbs
85 |
86 | * Makefile.in (valgrind): add valgrind sample targets
87 |
88 | 2010-08-16 Jeff Hobbs
89 |
90 | * Makefile.in (PKG_CFLAGS): remove -DBUILD_sample as that is
91 | auto-defined in TEA 3.9
92 | * configure, configure.in: update TEA 3.9
93 |
94 | 2010-08-12 Jeff Hobbs
95 |
96 | * configure: update TEA 3.8
97 | * Makefile.in (VPATH): add macosx.
98 |
99 | 2010-08-11 Jeff Hobbs
100 |
101 | * configure, configure.in: TEA 3.8 update, just include tcl.m4,
102 | modify TEA_INIT version and run autoconf 2.59
103 |
104 | 2010-04-30 Donal K. Fellows
105 |
106 | * doc/sha1.n: [Bug 2994714]: Updated documentation formatting to more
107 | closely follow Tcl's best practice guidelines in many aspects.
108 |
109 | 2010-04-29 Jan Nijtmans
110 |
111 | * doc/sha1.n [Enh 2788534]: add package require to doc
112 |
113 | 2010-04-23 Jan Nijtmans
114 |
115 | * configure: Regenerated to use latest TEA tcl.m4.
116 | * [Bug 2782806]: sample package's test cases fail
117 | Always define BUILD_sample, even on UNIX.
118 |
119 | 2010-02-19 Stuart Cassoff
120 |
121 | * tcl.m4: Correct compiler/linker flags for threaded builds on OpenBSD.
122 | * configure: Regenerated to use latest TEA tcl.m4.
123 |
124 | 2010-01-19 Jan Nijtmans
125 |
126 | * configure: Regenerated to use latest TEA tcl.m4.
127 |
128 | 2009-04-27 Jeff Hobbs
129 |
130 | * tcl.m4 (TEA_CONFIG_CFLAGS): harden the check to add _r to CC on AIX
131 | with threads.
132 |
133 | 2009-03-26 Jan Nijtmans
134 |
135 | * configure: Regenerated to use latest TEA tcl.m4.
136 |
137 | 2009-03-20 Andreas Kupries
138 |
139 | * configure: Regenerated to get my latest updates to tcl.m4 (See
140 | tclconfig/ChangeLog).
141 |
142 | NOTE: This pulled in an unexpected set of changes regarding
143 | SHLIB_VERSION and SHARED_LIB_SUFFIX, indicating that configure was not
144 | regenerated since some older change to tcl.m4.
145 |
146 | 2009-03-18 Stuart Cassoff
147 |
148 | * Makefile.in: [Bug 2429444]: Removed offending 'rm -f' line.
149 |
150 | 2009-03-11 Joe English
151 |
152 | * pkgIndex.tcl.in: [Bug 1960628]: use @PACKAGE_NAME@ instead of
153 | "Tclsha1".
154 |
155 | 2008-12-20 Daniel Steffen
156 |
157 | * Makefile.in: use INSTALL_LIBRARY instead of INSTALL_PROGRAM to
158 | install libraries, avoids breakage from tcl's install-strip when built
159 | as a bundled package.
160 |
161 | 2008-06-18 Pat Thoyts
162 |
163 | * win/makefile.vc: Updated win build files. Added new option to
164 | * win/rules.vc: nmakehlp to qualify a path name for use in setting
165 | * win/nmakehlp.c: up paths for test.
166 |
167 | 2007-10-23 Jeff Hobbs
168 |
169 | *** Tagged tea-3-branch to start TEA 4 development on HEAD ***
170 |
171 | * Makefile.in: separate PKG_ENV parts from TCLSH/WISH_ENV parts to
172 | better allow 8.4 and 8.5 core variant testing.
173 |
174 | 2007-05-11 Pat Thoyts
175 |
176 | * win/nmakehlp.c: Added support for simple substitution of an
177 | * win/makefile.vc: input file. This permits us to make use of
178 | pkgIndex.tcl.in style files without resorting to use of the tclsh
179 | we are building against -- when compiling for a foreign target (eg
180 | AMD64 from a ix86 host) we may not be able to run the
181 | tclsh. nmakehlp however must always be a native executable.
182 |
183 | 2007-05-03 Pat Thoyts
184 |
185 | * win/makefile.vc: Round of updating to synch up with the Tcl
186 | * win/rules.vc: core version of this build system.
187 | * win/nmakehlp.c:
188 | * win/sample.rc: Added sample resource file.
189 |
190 | 2007-02-09 Jeff Hobbs
191 |
192 | * Makefile.in, configure.in (CLEANFILES): correct cleanup handling
193 | of pkgIndex.tcl and clarify when it should be in CLEANFILES,
194 | CONFIG_CLEAN_FILES and/or BINARIES. [Bug 1655088]
195 | * configure: Updated with TEA 3.6 changes
196 |
197 | 2006-11-26 Daniel Steffen
198 |
199 | * Makefile.in: add datarootdir for autoconf-2.60.
200 |
201 | * configure: autoconf-2.59 for TEA updates.
202 |
203 | 2006-09-24 Pat Thoyts
204 |
205 | * win/nmakehlp.c: Updated for building extensions with msvc8,
206 | * win/makefile.vc: support for varying compiler options for
207 | * win/rules.vc: msvc6,7,8.
208 |
209 | 2006-01-23 Jeff Hobbs
210 |
211 | * configure.in, configure: update to TEA 3.5
212 |
213 | 2006-01-10 Daniel Steffen
214 |
215 | * generic/sample.c:
216 | * generic/tclsample.c: fix gcc4 warnings.
217 |
218 | * configure: autoconf-2.59 for TEA updates.
219 |
220 | 2005-12-01 Daniel Steffen
221 |
222 | * configure: autoconf-2.59 for TEA updates.
223 |
224 | 2005-11-29 Jeff Hobbs
225 |
226 | * configure, configure.in: update to TEA 3.4 (darwin-64, Win-64
227 | build improvements). [Bug 1369597]
228 |
229 | * pkgIndex.tcl.in: specify $PACKAGE_NAME to load
230 |
231 | 2005-11-27 Daniel Steffen
232 |
233 | * configure: autoconf-2.59 for TEA updates.
234 |
235 | 2005-09-13 Jeff Hobbs
236 |
237 | * configure, configure.in: using TEA 3.3 that has threads enabled
238 | by default.
239 |
240 | * Makefile.in: remove unnecessary private dir info
241 |
242 | 2005-07-26 Mo DeJong
243 |
244 | * Makefile.in: Remove SYSTEM_TCLSH and revert
245 | back to just using TCLSH_PROG and WISH_PROG.
246 | Remove use of SYSTEM_TCLSH at build time since
247 | this is no longer supported.
248 | * configure: Regen.
249 | * configure.in: Don't invoke TEA_BUILD_TCLSH or
250 | TEA_BUILD_WISH since these were removed from
251 | tcl.m4. This fixes up support for a build
252 | or installed version of Tcl.
253 |
254 | 2005-07-24 Mo DeJong
255 |
256 | * README: Add info about mingw and mention
257 | pkgIndex.tcl.in.
258 | * configure: Regen.
259 | * configure.in: Emit a pkgIndex.tcl in the
260 | build directory. This makes it possible to
261 | build and install sampleextension without
262 | having to run anything in a tclsh shell.
263 | A build process that depends on running
264 | the software being built will not work
265 | when cross compiling.
266 | * pkgIndex.tcl.in: Add template.
267 |
268 | 2005-07-24 Mo DeJong
269 |
270 | * Makefile.in: Subst TCLSH_PROG from PATH
271 | as SYSTEM_TCLSH and subst BUILD_TCLSH and
272 | BUILD_WISH. Use SYSTEM_TCLSH for the
273 | pkgIndex.tcl generation target.
274 | * configure: Regen.
275 | * configure.in: Invoke new TEA_BUILD_TCLSH
276 | and TEA_BUILD_WISH macros defined in tcl.m4.
277 | [Tcl bug 1160114]
278 | [Tcl patch 1244153]
279 |
280 | 2005-06-23 Daniel Steffen
281 |
282 | * Makefile.in: added commented out variable definitions for building
283 | extensions using Tk, to document exactly what needs to be added for Tk.
284 | Commented out obsolete makefile variables TCL_DEFS and TCL_LIBS.
285 |
286 | * configure: autoconf-2.59 for TEA updates.
287 |
288 | 2005-06-18 Daniel Steffen
289 |
290 | * configure: autoconf-2.59 for TEA updates.
291 |
292 | 2005-06-04 Daniel Steffen
293 |
294 | * configure: autoconf-2.59 for TEA updates.
295 |
296 | 2005-04-25 Daniel Steffen
297 |
298 | * Makefile.in: split out TCLLIBPATH from TCLSH_ENV to allow
299 | customization and overriding, add PKG_LIB_FILE dependency to
300 | pkgIndex.tcl target.
301 | * configure.in: added AC_DEFINE* descriptions to allow
302 | use with autoheader.
303 | * configure: autoconf-2.59.
304 |
305 | 2005-03-25 Jeff Hobbs
306 |
307 | * Makefile.in: add binaries dep to install-lib-binaries and
308 | install-bin-binaries. (steffen)
309 |
310 | 2005-03-24 Don Porter
311 |
312 | * Makefile.in: Corrected the `make dist` target.
313 | * configure: TEA updates.
314 |
315 | 2005-03-18 Jeff Hobbs
316 |
317 | * configure: regen with later tcl.m4.
318 | * Makefile.in: use @AR@ instead of hard-coded 'ar' to fix AIX
319 | 64-bit static build.
320 |
321 | 2005-02-08 Jeff Hobbs
322 |
323 | * configure: update for minor tcl.m4 changes. This is the first
324 | checkin that uses autoconf-2.59 (previously used 2.57).
325 |
326 | 2005-02-07 Jeff Hobbs
327 |
328 | * Makefile.in: SHLIB_LD_FLAGS no longer exported
329 |
330 | 2005-02-01 Jeff Hobbs
331 |
332 | * configure, configure.in: update for TEA 3.2.
333 |
334 | * Makefile.in: add comments about doc target. [RFE #681117]
335 |
336 | 2005-01-24 Jeff Hobbs
337 |
338 | * Makefile.in, tclconfig/tcl.m4: update to TEA 3.1, better CFLAGS
339 | * configure, configure.in: handling, evc4 and msys support.
340 |
341 | 2004-12-29 Joe English
342 |
343 | * tclconfig/tcl.m4: Do not use ${DBGX} suffix when building
344 | shared libraries [patch #1081595, TIP #34]
345 |
346 | 2004-12-02 Donal K. Fellows
347 |
348 | * generic/tclsample.c (Sha1_Cmd): Rewrote to use the Tcl_Obj API
349 | for arguments instead of the old string API. [FRQ #1076907]
350 |
351 | 2004-07-16 Jeff Hobbs
352 |
353 | * configure.in, configure, Makefile.in: Reorder configure.in for
354 | better 64-bit build configuration, replacing EXTRA_CFLAGS with
355 | CFLAGS. [Bug #874058]
356 | (install-doc, install-libraries): guard against null globs
357 |
358 | 2004-07-05 Pat Thoyts
359 |
360 | * win/rules.vc: Modified the nmake build system to support
361 | * win/makefile.vc: an specific installation directory not in the
362 | tcl install tree. eg: a site-lib directory. Some general fixups
363 | too, get the tests working again, update the version, and use the
364 | new PACKAGE_VERSION macro.
365 |
366 | 2004-07-04 Pat Thoyts
367 |
368 | * tests/all.tcl: Added a compatability function to permit running
369 | tests on tcl 8.2.
370 |
371 | 2003-12-10 Jeff Hobbs
372 |
373 | * Makefile.in: added TEA_ADD_LIBS, TEA_ADD_INCLUDES and
374 | * configure: TEA_ADD_CFLAGS to configurable parameters with
375 | * configure.in: PKG_* equivs in the Makefile. This allows the
376 | * tclconfig/tcl.m4: user to worry less about actual magic VAR names.
377 | Corrected Makefile.in to note that TEA_ADD_TCL_SOURCES requires
378 | exact file names.
379 |
380 | 2003-12-09 Jeff Hobbs
381 |
382 | * Makefile.in: added stub lib support even though sample doesn't
383 | yet create a stub library.
384 |
385 | * configure, tclconfig/tcl.m4: updated OpenBSD support based on
386 | [Patch #775246] (cassoff)
387 |
388 | 2003-12-08 Jeff Hobbs
389 |
390 | * generic/sample.c:
391 | * generic/sample.h: updated for 64-bit correctness
392 |
393 | 2003-12-05 Jeff Hobbs
394 |
395 | * configure:
396 | * configure.in:
397 | * Makefile.in (VPATH): readd $(srcdir) to front of VPATH as the
398 | first part of VPATH can get chopped off.
399 | Change .c.$(OBJEXT) rule to .c.@OBJEXT@ to support more makes.
400 | * tclconfig/tcl.m4: add TEA_ADD_STUB_SOURCES to support libstub
401 | generation and TEA_ADD_TCL_SOURCES to replace RUNTIME_SOURCES as
402 | the way the user specifies library files.
403 |
404 | 2003-12-03 Jeff Hobbs
405 |
406 | * configure: Update of TEA spec to (hopefully) simplify
407 | * configure.in: some aspects of TEA by making use of more
408 | * Makefile.in: AC 2.5x features. Use PACKAGE_NAME (instead
409 | * generic/tclsample.c: of PACKAGE) and PACKAGE_VERSION (instead of
410 | * tclconfig/tcl.m4: VERSION) arguments to AC_INIT as the TEA
411 | package name and version.
412 | Provide a version argument to TEA_INIT - starting with 3.0.
413 | Drop all use of interior shell substs that older makefiles didn't
414 | like. Use PKG_* naming convention instead.
415 | Move specification of source files and public headers into
416 | configure.in with TEA_ADD_SOURCES and TEA_ADD_HEADERS. These will
417 | be munged during ./configure into the right obj file names (no
418 | $(SOURCES:.c=.obj) needed).
419 | There is almost nothing that should be touched in Makefile.in now
420 | for the developer. May want to add a TEA_ADD_TCL_SOURCES for the
421 | RUNTIME_SOURCES that remains.
422 | Use SHLID_LD_FLAGS (instead of SHLID_LDFLAGS) as Tcl does.
423 | Only specify the user requested LDFLAGS/CFLAGS in the Makefile,
424 | don't mention the _OPTIMIZE/_DEBUG variants.
425 |
426 | * generic/sample.h: remove outdated ANSI_ARGS usage
427 |
428 | 2003-11-26 Jeff Hobbs
429 |
430 | **** tagged sampleextension-0-4 ****
431 |
432 | 2003-10-06 Jeff Hobbs
433 |
434 | * configure: regened with autoconf 2.5x tcl.m4
435 |
436 | * Makefile.in (CFLAGS_WARNING): added to base makefile
437 |
438 | 2003-10-01 Pat Thoyts
439 |
440 | * tea.pdf: Set to binary so it downloads properly under Win32
441 |
442 | * win/rules.vc: Fixed nmakehlp to find the correct Tcl or Tk
443 | * win/nmakehlp.c: version from the tcl.h header file. This will
444 | * win/makefile.vc then pick up the right libraries.
445 |
446 | 2003-07-02 Pat Thoyts
447 |
448 | * README: Added notes for the win/ build files.
449 |
450 | * win/Makefile.vc: Patch #762878 applied to provide a sample VC++
451 | * win/rules.vc: build system. This is NOT TEA but is a useful
452 | * win/nmakehlp.c: alternative for win32 developers.
453 |
454 | 2003-04-04 Andreas Kupries
455 |
456 | * configure.in:
457 | * tclconfig/tcl.m4: Updated to newest tcl.m4, regenerated
458 | configure's.
459 |
460 | 2003-02-25 Mo DeJong
461 |
462 | * README: Add generic unix build instructions
463 | and suggest the msys + mingw build process
464 | described in tcl/win/README.
465 | * README.cygwin: Remove Cygwin specific info since
466 | this is now covered in the README file.
467 | [Tc Patch 679416]
468 |
469 | 2002-10-15 Jeff Hobbs
470 |
471 | * configure:
472 | * configure.in: move the CFLAGS definition into TEA_ENABLE_SHARED
473 | and make it pick up the env CFLAGS at configure time.
474 |
475 | 2002-07-11 Jeff Hobbs
476 |
477 | * Makefile.in: make TCL_DEFS come first in DEFS to that our DEFS
478 | would redefine the Tcl ones.
479 |
480 | * generic/tclsample.c: renamed Sha1 to Sha1_Cmd to better follow
481 | convention
482 |
483 | 2002-04-22 Jeff Hobbs
484 |
485 | * configure: regen'ed
486 | * configure.in (CLEANFILES): added pkgIndex.tcl
487 |
488 | * README.cygwin: improved notes on using cygwin.
489 |
490 | 2002-04-03 Jeff Hobbs
491 |
492 | * Makefile.in: improved use of DESTDIR in install targets.
493 | Removed need for installdirs target.
494 | Broke TCLSH_PROG into TCLSH_ENV and TCLSH_PROG with TCLSH var and
495 | added comments about TCLSH_ENV.
496 | Added default shell and gdb targets.
497 | Added comments about using RUNTIME_SOURCES var.
498 |
499 | * README.cygwin: updated notes about using mingw gcc as a compiler.
500 |
501 | * configure:
502 | * configure.in: updated to new TEA base that: prefixes all macros
503 | with TEA_* instead of SC_*; adds TEA_PREFIX, which defaults the
504 | prefix and exec_prefix values to what Tcl used; adds
505 | TEA_SETUP_COMPILER, which handles basic compiler / support program
506 | checks and simplifies the configure.in.
507 |
508 | 2002-04-01 Jeff Hobbs
509 |
510 | * Makefile.in (install-lib-binaries): ensure that binary files are
511 | installed with executable bit set (use INSTALL_PROGRAM)
512 |
513 | 2002-03-29 Jeff Hobbs
514 |
515 | * configure: regen'ed from changed tclconfig/tcl.m4
516 |
517 | * generic/tclsample.c: added #include for strlen /
518 | strcmp declarations.
519 |
520 | 2002-03-28 Jeff Hobbs
521 |
522 | * Makefile.in: moved setting TCLLIBPATH to the test target because
523 | that is where it is needed, added a little doc about it.
524 |
525 | * configure:
526 | * configure.in: BUILD_${PACKAGE} had to be static BUILD_sample in
527 | AC_DEFINE because autoconf wasn't substituting ${PACKAGE}.
528 |
529 | * tests/all.tcl: added message about starting pwd
530 |
531 | 2002-03-27 Jeff Hobbs
532 |
533 | * Makefile.in (TCLSH_PROG): moved and updated env var definitions
534 | to have tclsh work from build dir. Removed TCL_EXTRA_CFLAGS,
535 | TCL_LD_FLAGS, TCL_SHLIB_LD_LIBS, TCL_DBGX, TCL_STUB_LIB_FILE,
536 | TCL_STUB_LIB_SPEC as they aren't needed (configure acquires all
537 | that info for us). TCL_LIBS is also not needed, but left in as a
538 | reference to the libs Tcl used.
539 |
540 | * configure: regen based on updated tclconfig/tcl.m4
541 | * configure.in: moved the SHLIB_LD_LIBS magic into
542 | tclconfig/tcl.m4 and noted where users can modify (SHLIB_LD_)LIBS.
543 |
544 | 2002-03-20 Jeff Hobbs
545 |
546 | * Makefile.in (install-binaries): corrected if shell error
547 | [Bug #532557] (virden)
548 |
549 | 2002-03-19 Jeff Hobbs
550 |
551 | * README:
552 | * mkIndex.tcl.in (removed): removed the need for this script by
553 | simplifying the default install structure to use pkglibdir for the
554 | main dynamic library file generated.
555 |
556 | * configure:
557 | * configure.in: use double eval on the ${PACKAGE}_LIB_FILE to
558 | substitute the ${DBGX} variable.
559 | Remove output of the mkIndex.tcl script.
560 |
561 | * Makefile.in: added pkgIndex.tcl to binaries dependencies.
562 | Removed use of mkIndex.tcl script. Simple pkgIndex.tcl target
563 | added and install-lib-binaries modified to use pkglibdir instead
564 | of bindir and libdir directories.
565 |
566 | 2002-03-12 Jeff Hobbs
567 |
568 | * configure: regenerated
569 | * configure.in: removed pulling (UN)SHARED_LIB_SUFFIX from
570 | tclConfig.sh as these are defined by SC_CONFIG_CFLAGS.
571 |
572 | * Makefile.in (TCLSH_PROG): added a viable TCL_LIBRARY for when
573 | the TCLSH_PROG is a built, but not installed, executable.
574 | (install-binaries, test, LIB_FILE): use $($(PACKAGE)_LIB_FILE)
575 | instead of directly referencing package name to reduce number of
576 | lines that need changing.
577 | (dist): removed install of no longer existent tclconfig/config.*
578 |
579 | 2002-03-11 Jeff Hobbs
580 |
581 | * Makefile.in:
582 | * doc/sha1.n: moved from sha1.n
583 | * generic/sample.c: moved from sample.c
584 | * generic/sample.h: moved from sample.h
585 | * generic/tclsample.c: moved from tclsample.c
586 |
587 | 2002-03-06 Jeff Hobbs
588 |
589 | * Makefile.in: add EXTRA_SOURCES, WIN_SOURCES, UNIX_SOURCES
590 | example lines, remove $(sample_LIB_FILE)_OBJECTS problematic
591 | macro, move lib_BINARIES and BINARIES as they don't need editing.
592 | Replace $(mkinstalldirs) with "mkdir -p", added $(srcdir)/unix to
593 | VPATH, removed inclusion of tclconfig/installFile.tcl and
594 | tclconfig/mkinstalldirs in dist: target.
595 |
596 | * aclocal.m4: added comments
597 |
598 | 2002-03-05 Jeff Hobbs
599 |
600 | * Makefile.in: removed unused @vars@. Cleaned up targets. Added
601 | dist and dist-clean generic targets. Improved use of OBJEXT.
602 |
603 | * configure.in: bumped package to 0.3, cleaned up macro usage.
604 |
605 | * README:
606 | * README.cygwin:
607 | * aclocal.m4:
608 | * configure (new):
609 | * install-sh, mkinstalldirs, tcl.m4 (removed): complete revamp to
610 | use the tclconfig updated TEA module
611 |
612 | * exampleA.c, sample.c:
613 | * exampleA.h, sample.h:
614 | * tclexampleA.c, tclsample.c: s/exampleA/sample/g
615 |
616 | 2001-05-21 Jeff Hobbs
617 |
618 | * tcl.m4: 419812
619 |
620 | 2000-06-26 Mike Thomas
621 |
622 | * Makefile.in: Changed TCLTESTARGS to TESTFLAGS in test: target.
623 |
624 | 2000-02-03 Mike Thomas
625 |
626 | * tests/: Added tests subdirectory with sample test files
627 | * Makefile.in: Added test target to Makefile.
628 | * configure.in: Added hooks for when we later move some of the config
629 | files to a subdirectory.
630 |
631 | 2000-02-02 Mike Thomas
632 |
633 | * configure.in:
634 | * Makefile.in: Applied patch from Andreas Kupries to fix install
635 | problems when building static libraries.
636 |
637 | 2000-01-24 Mike Thomas
638 |
639 | * tcl.m4: Look for CYGWIN_98 and CYGWIN_95 environments, not just
640 | CYGWIN_NT. Also search for executables with the $EXEEXT extension
641 | in SC_PROG_TCLSH and SC_PROG_WISH so that we don't pick up MS VS
642 | junk files.
643 | * configure.in: Changes to support building on Win 95/98 using
644 | the cygwin environment.
645 |
--------------------------------------------------------------------------------
/win/nmakehlp.c:
--------------------------------------------------------------------------------
1 | /*
2 | * ----------------------------------------------------------------------------
3 | * nmakehlp.c --
4 | *
5 | * This is used to fix limitations within nmake and the environment.
6 | *
7 | * Copyright (c) 2002 David Gravereaux.
8 | * Copyright (c) 2006 Pat Thoyts
9 | *
10 | * See the file "license.terms" for information on usage and redistribution of
11 | * this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 | * ----------------------------------------------------------------------------
13 | */
14 |
15 | #define _CRT_SECURE_NO_DEPRECATE
16 | #include
17 | #ifdef _MSC_VER
18 | #pragma comment (lib, "user32.lib")
19 | #pragma comment (lib, "kernel32.lib")
20 | #endif
21 | #include
22 |
23 | /*
24 | * This library is required for x64 builds with _some_ versions of MSVC
25 | */
26 | #if defined(_M_IA64) || defined(_M_AMD64)
27 | #if _MSC_VER >= 1400 && _MSC_VER < 1500
28 | #pragma comment(lib, "bufferoverflowU")
29 | #endif
30 | #endif
31 |
32 | /* ISO hack for dumb VC++ */
33 | #if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1900
34 | #define snprintf _snprintf
35 | #endif
36 |
37 |
38 | /* protos */
39 |
40 | static int CheckForCompilerFeature(const char *option);
41 | static int CheckForLinkerFeature(char **options, int count);
42 | static int IsIn(const char *string, const char *substring);
43 | static int SubstituteFile(const char *substs, const char *filename);
44 | static int QualifyPath(const char *path);
45 | static int LocateDependency(const char *keyfile);
46 | static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
47 | static DWORD WINAPI ReadFromPipe(LPVOID args);
48 |
49 | /* globals */
50 |
51 | #define CHUNK 25
52 | #define STATICBUFFERSIZE 1000
53 | typedef struct {
54 | HANDLE pipe;
55 | char buffer[STATICBUFFERSIZE];
56 | } pipeinfo;
57 |
58 | pipeinfo Out = {INVALID_HANDLE_VALUE, ""};
59 | pipeinfo Err = {INVALID_HANDLE_VALUE, ""};
60 |
61 | /*
62 | * exitcodes: 0 == no, 1 == yes, 2 == error
63 | */
64 |
65 | int
66 | main(
67 | int argc,
68 | char *argv[])
69 | {
70 | char msg[300];
71 | DWORD dwWritten;
72 | int chars;
73 | const char *s;
74 |
75 | /*
76 | * Make sure children (cl.exe and link.exe) are kept quiet.
77 | */
78 |
79 | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
80 |
81 | /*
82 | * Make sure the compiler and linker aren't effected by the outside world.
83 | */
84 |
85 | SetEnvironmentVariable("CL", "");
86 | SetEnvironmentVariable("LINK", "");
87 |
88 | if (argc > 1 && *argv[1] == '-') {
89 | switch (*(argv[1]+1)) {
90 | case 'c':
91 | if (argc != 3) {
92 | chars = snprintf(msg, sizeof(msg) - 1,
93 | "usage: %s -c \n"
94 | "Tests for whether cl.exe supports an option\n"
95 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
96 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
97 | &dwWritten, NULL);
98 | return 2;
99 | }
100 | return CheckForCompilerFeature(argv[2]);
101 | case 'l':
102 | if (argc < 3) {
103 | chars = snprintf(msg, sizeof(msg) - 1,
104 | "usage: %s -l ? ...?\n"
105 | "Tests for whether link.exe supports an option\n"
106 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
107 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
108 | &dwWritten, NULL);
109 | return 2;
110 | }
111 | return CheckForLinkerFeature(&argv[2], argc-2);
112 | case 'f':
113 | if (argc == 2) {
114 | chars = snprintf(msg, sizeof(msg) - 1,
115 | "usage: %s -f \n"
116 | "Find a substring within another\n"
117 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
118 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
119 | &dwWritten, NULL);
120 | return 2;
121 | } else if (argc == 3) {
122 | /*
123 | * If the string is blank, there is no match.
124 | */
125 |
126 | return 0;
127 | } else {
128 | return IsIn(argv[2], argv[3]);
129 | }
130 | case 's':
131 | if (argc == 2) {
132 | chars = snprintf(msg, sizeof(msg) - 1,
133 | "usage: %s -s \n"
134 | "Perform a set of string map type substutitions on a file\n"
135 | "exitcodes: 0\n",
136 | argv[0]);
137 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
138 | &dwWritten, NULL);
139 | return 2;
140 | }
141 | return SubstituteFile(argv[2], argv[3]);
142 | case 'V':
143 | if (argc != 4) {
144 | chars = snprintf(msg, sizeof(msg) - 1,
145 | "usage: %s -V filename matchstring\n"
146 | "Extract a version from a file:\n"
147 | "eg: pkgIndex.tcl \"package ifneeded http\"",
148 | argv[0]);
149 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
150 | &dwWritten, NULL);
151 | return 0;
152 | }
153 | s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
154 | if (s && *s) {
155 | printf("%s\n", s);
156 | return 0;
157 | } else
158 | return 1; /* Version not found. Return non-0 exit code */
159 |
160 | case 'Q':
161 | if (argc != 3) {
162 | chars = snprintf(msg, sizeof(msg) - 1,
163 | "usage: %s -Q path\n"
164 | "Emit the fully qualified path\n"
165 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
166 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
167 | &dwWritten, NULL);
168 | return 2;
169 | }
170 | return QualifyPath(argv[2]);
171 |
172 | case 'L':
173 | if (argc != 3) {
174 | chars = snprintf(msg, sizeof(msg) - 1,
175 | "usage: %s -L keypath\n"
176 | "Emit the fully qualified path of directory containing keypath\n"
177 | "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
178 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
179 | &dwWritten, NULL);
180 | return 2;
181 | }
182 | return LocateDependency(argv[2]);
183 | }
184 | }
185 | chars = snprintf(msg, sizeof(msg) - 1,
186 | "usage: %s -c|-f|-l|-Q|-s|-V ...\n"
187 | "This is a little helper app to equalize shell differences between WinNT and\n"
188 | "Win9x and get nmake.exe to accomplish its job.\n",
189 | argv[0]);
190 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
191 | return 2;
192 | }
193 |
194 | static int
195 | CheckForCompilerFeature(
196 | const char *option)
197 | {
198 | STARTUPINFO si;
199 | PROCESS_INFORMATION pi;
200 | SECURITY_ATTRIBUTES sa;
201 | DWORD threadID;
202 | char msg[300];
203 | BOOL ok;
204 | HANDLE hProcess, h, pipeThreads[2];
205 | char cmdline[100];
206 |
207 | hProcess = GetCurrentProcess();
208 |
209 | memset(&pi, 0, sizeof(PROCESS_INFORMATION));
210 | memset(&si, 0, sizeof(STARTUPINFO));
211 | si.cb = sizeof(STARTUPINFO);
212 | si.dwFlags = STARTF_USESTDHANDLES;
213 | si.hStdInput = INVALID_HANDLE_VALUE;
214 |
215 | memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
216 | sa.nLength = sizeof(SECURITY_ATTRIBUTES);
217 | sa.lpSecurityDescriptor = NULL;
218 | sa.bInheritHandle = FALSE;
219 |
220 | /*
221 | * Create a non-inheritable pipe.
222 | */
223 |
224 | CreatePipe(&Out.pipe, &h, &sa, 0);
225 |
226 | /*
227 | * Dupe the write side, make it inheritable, and close the original.
228 | */
229 |
230 | DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
231 | DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
232 |
233 | /*
234 | * Same as above, but for the error side.
235 | */
236 |
237 | CreatePipe(&Err.pipe, &h, &sa, 0);
238 | DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
239 | DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
240 |
241 | /*
242 | * Base command line.
243 | */
244 |
245 | lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");
246 |
247 | /*
248 | * Append our option for testing
249 | */
250 |
251 | lstrcat(cmdline, option);
252 |
253 | /*
254 | * Filename to compile, which exists, but is nothing and empty.
255 | */
256 |
257 | lstrcat(cmdline, " .\\nul");
258 |
259 | ok = CreateProcess(
260 | NULL, /* Module name. */
261 | cmdline, /* Command line. */
262 | NULL, /* Process handle not inheritable. */
263 | NULL, /* Thread handle not inheritable. */
264 | TRUE, /* yes, inherit handles. */
265 | DETACHED_PROCESS, /* No console for you. */
266 | NULL, /* Use parent's environment block. */
267 | NULL, /* Use parent's starting directory. */
268 | &si, /* Pointer to STARTUPINFO structure. */
269 | &pi); /* Pointer to PROCESS_INFORMATION structure. */
270 |
271 | if (!ok) {
272 | DWORD err = GetLastError();
273 | int chars = snprintf(msg, sizeof(msg) - 1,
274 | "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
275 |
276 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
277 | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
278 | (300-chars), 0);
279 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
280 | return 2;
281 | }
282 |
283 | /*
284 | * Close our references to the write handles that have now been inherited.
285 | */
286 |
287 | CloseHandle(si.hStdOutput);
288 | CloseHandle(si.hStdError);
289 |
290 | WaitForInputIdle(pi.hProcess, 5000);
291 | CloseHandle(pi.hThread);
292 |
293 | /*
294 | * Start the pipe reader threads.
295 | */
296 |
297 | pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
298 | pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
299 |
300 | /*
301 | * Block waiting for the process to end.
302 | */
303 |
304 | WaitForSingleObject(pi.hProcess, INFINITE);
305 | CloseHandle(pi.hProcess);
306 |
307 | /*
308 | * Wait for our pipe to get done reading, should it be a little slow.
309 | */
310 |
311 | WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
312 | CloseHandle(pipeThreads[0]);
313 | CloseHandle(pipeThreads[1]);
314 |
315 | /*
316 | * Look for the commandline warning code in both streams.
317 | * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
318 | */
319 |
320 | return !(strstr(Out.buffer, "D4002") != NULL
321 | || strstr(Err.buffer, "D4002") != NULL
322 | || strstr(Out.buffer, "D9002") != NULL
323 | || strstr(Err.buffer, "D9002") != NULL
324 | || strstr(Out.buffer, "D2021") != NULL
325 | || strstr(Err.buffer, "D2021") != NULL);
326 | }
327 |
328 | static int
329 | CheckForLinkerFeature(
330 | char **options,
331 | int count)
332 | {
333 | STARTUPINFO si;
334 | PROCESS_INFORMATION pi;
335 | SECURITY_ATTRIBUTES sa;
336 | DWORD threadID;
337 | char msg[300];
338 | BOOL ok;
339 | HANDLE hProcess, h, pipeThreads[2];
340 | int i;
341 | char cmdline[255];
342 |
343 | hProcess = GetCurrentProcess();
344 |
345 | memset(&pi, 0, sizeof(PROCESS_INFORMATION));
346 | memset(&si, 0, sizeof(STARTUPINFO));
347 | si.cb = sizeof(STARTUPINFO);
348 | si.dwFlags = STARTF_USESTDHANDLES;
349 | si.hStdInput = INVALID_HANDLE_VALUE;
350 |
351 | memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
352 | sa.nLength = sizeof(SECURITY_ATTRIBUTES);
353 | sa.lpSecurityDescriptor = NULL;
354 | sa.bInheritHandle = TRUE;
355 |
356 | /*
357 | * Create a non-inheritible pipe.
358 | */
359 |
360 | CreatePipe(&Out.pipe, &h, &sa, 0);
361 |
362 | /*
363 | * Dupe the write side, make it inheritable, and close the original.
364 | */
365 |
366 | DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
367 | DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
368 |
369 | /*
370 | * Same as above, but for the error side.
371 | */
372 |
373 | CreatePipe(&Err.pipe, &h, &sa, 0);
374 | DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
375 | DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
376 |
377 | /*
378 | * Base command line.
379 | */
380 |
381 | lstrcpy(cmdline, "link.exe -nologo ");
382 |
383 | /*
384 | * Append our option for testing.
385 | */
386 |
387 | for (i = 0; i < count; i++) {
388 | lstrcat(cmdline, " \"");
389 | lstrcat(cmdline, options[i]);
390 | lstrcat(cmdline, "\"");
391 | }
392 |
393 | ok = CreateProcess(
394 | NULL, /* Module name. */
395 | cmdline, /* Command line. */
396 | NULL, /* Process handle not inheritable. */
397 | NULL, /* Thread handle not inheritable. */
398 | TRUE, /* yes, inherit handles. */
399 | DETACHED_PROCESS, /* No console for you. */
400 | NULL, /* Use parent's environment block. */
401 | NULL, /* Use parent's starting directory. */
402 | &si, /* Pointer to STARTUPINFO structure. */
403 | &pi); /* Pointer to PROCESS_INFORMATION structure. */
404 |
405 | if (!ok) {
406 | DWORD err = GetLastError();
407 | int chars = snprintf(msg, sizeof(msg) - 1,
408 | "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
409 |
410 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
411 | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
412 | (300-chars), 0);
413 | WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
414 | return 2;
415 | }
416 |
417 | /*
418 | * Close our references to the write handles that have now been inherited.
419 | */
420 |
421 | CloseHandle(si.hStdOutput);
422 | CloseHandle(si.hStdError);
423 |
424 | WaitForInputIdle(pi.hProcess, 5000);
425 | CloseHandle(pi.hThread);
426 |
427 | /*
428 | * Start the pipe reader threads.
429 | */
430 |
431 | pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
432 | pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
433 |
434 | /*
435 | * Block waiting for the process to end.
436 | */
437 |
438 | WaitForSingleObject(pi.hProcess, INFINITE);
439 | CloseHandle(pi.hProcess);
440 |
441 | /*
442 | * Wait for our pipe to get done reading, should it be a little slow.
443 | */
444 |
445 | WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
446 | CloseHandle(pipeThreads[0]);
447 | CloseHandle(pipeThreads[1]);
448 |
449 | /*
450 | * Look for the commandline warning code in the stderr stream.
451 | */
452 |
453 | return !(strstr(Out.buffer, "LNK1117") != NULL ||
454 | strstr(Err.buffer, "LNK1117") != NULL ||
455 | strstr(Out.buffer, "LNK4044") != NULL ||
456 | strstr(Err.buffer, "LNK4044") != NULL ||
457 | strstr(Out.buffer, "LNK4224") != NULL ||
458 | strstr(Err.buffer, "LNK4224") != NULL);
459 | }
460 |
461 | static DWORD WINAPI
462 | ReadFromPipe(
463 | LPVOID args)
464 | {
465 | pipeinfo *pi = (pipeinfo *) args;
466 | char *lastBuf = pi->buffer;
467 | DWORD dwRead;
468 | BOOL ok;
469 |
470 | again:
471 | if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
472 | CloseHandle(pi->pipe);
473 | return (DWORD)-1;
474 | }
475 | ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
476 | if (!ok || dwRead == 0) {
477 | CloseHandle(pi->pipe);
478 | return 0;
479 | }
480 | lastBuf += dwRead;
481 | goto again;
482 |
483 | return 0; /* makes the compiler happy */
484 | }
485 |
486 | static int
487 | IsIn(
488 | const char *string,
489 | const char *substring)
490 | {
491 | return (strstr(string, substring) != NULL);
492 | }
493 |
494 | /*
495 | * GetVersionFromFile --
496 | * Looks for a match string in a file and then returns the version
497 | * following the match where a version is anything acceptable to
498 | * package provide or package ifneeded.
499 | */
500 |
501 | static const char *
502 | GetVersionFromFile(
503 | const char *filename,
504 | const char *match,
505 | int numdots)
506 | {
507 | static char szBuffer[100];
508 | char *szResult = NULL;
509 | FILE *fp = fopen(filename, "rt");
510 |
511 | if (fp != NULL) {
512 | /*
513 | * Read data until we see our match string.
514 | */
515 |
516 | while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
517 | LPSTR p, q;
518 |
519 | p = strstr(szBuffer, match);
520 | if (p != NULL) {
521 | /*
522 | * Skip to first digit after the match.
523 | */
524 |
525 | p += strlen(match);
526 | while (*p && !isdigit((unsigned char)*p)) {
527 | ++p;
528 | }
529 |
530 | /*
531 | * Find ending whitespace.
532 | */
533 |
534 | q = p;
535 | while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q)
536 | && !strchr("ab", q[-1])) || --numdots))) {
537 | ++q;
538 | }
539 |
540 | *q = 0;
541 | szResult = p;
542 | break;
543 | }
544 | }
545 | fclose(fp);
546 | }
547 | return szResult;
548 | }
549 |
550 | /*
551 | * List helpers for the SubstituteFile function
552 | */
553 |
554 | typedef struct list_item_t {
555 | struct list_item_t *nextPtr;
556 | char * key;
557 | char * value;
558 | } list_item_t;
559 |
560 | /* insert a list item into the list (list may be null) */
561 | static list_item_t *
562 | list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
563 | {
564 | list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t));
565 | if (itemPtr) {
566 | itemPtr->key = strdup(key);
567 | itemPtr->value = strdup(value);
568 | itemPtr->nextPtr = NULL;
569 |
570 | while(*listPtrPtr) {
571 | listPtrPtr = &(*listPtrPtr)->nextPtr;
572 | }
573 | *listPtrPtr = itemPtr;
574 | }
575 | return itemPtr;
576 | }
577 |
578 | static void
579 | list_free(list_item_t **listPtrPtr)
580 | {
581 | list_item_t *tmpPtr, *listPtr = *listPtrPtr;
582 | while (listPtr) {
583 | tmpPtr = listPtr;
584 | listPtr = listPtr->nextPtr;
585 | free(tmpPtr->key);
586 | free(tmpPtr->value);
587 | free(tmpPtr);
588 | }
589 | }
590 |
591 | /*
592 | * SubstituteFile --
593 | * As windows doesn't provide anything useful like sed and it's unreliable
594 | * to use the tclsh you are building against (consider x-platform builds -
595 | * e.g. compiling AMD64 target from IX86) we provide a simple substitution
596 | * option here to handle autoconf style substitutions.
597 | * The substitution file is whitespace and line delimited. The file should
598 | * consist of lines matching the regular expression:
599 | * \s*\S+\s+\S*$
600 | *
601 | * Usage is something like:
602 | * nmakehlp -S << $** > $@
603 | * @PACKAGE_NAME@ $(PACKAGE_NAME)
604 | * @PACKAGE_VERSION@ $(PACKAGE_VERSION)
605 | * <<
606 | */
607 |
608 | static int
609 | SubstituteFile(
610 | const char *substitutions,
611 | const char *filename)
612 | {
613 | static char szBuffer[1024], szCopy[1024];
614 | list_item_t *substPtr = NULL;
615 | FILE *fp, *sp;
616 |
617 | fp = fopen(filename, "rt");
618 | if (fp != NULL) {
619 |
620 | /*
621 | * Build a list of substitutions from the first filename
622 | */
623 |
624 | sp = fopen(substitutions, "rt");
625 | if (sp != NULL) {
626 | while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) {
627 | unsigned char *ks, *ke, *vs, *ve;
628 | ks = (unsigned char*)szBuffer;
629 | while (ks && *ks && isspace(*ks)) ++ks;
630 | ke = ks;
631 | while (ke && *ke && !isspace(*ke)) ++ke;
632 | vs = ke;
633 | while (vs && *vs && isspace(*vs)) ++vs;
634 | ve = vs;
635 | while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
636 | *ke = 0, *ve = 0;
637 | list_insert(&substPtr, (char*)ks, (char*)vs);
638 | }
639 | fclose(sp);
640 | }
641 |
642 | /* debug: dump the list */
643 | #ifndef NDEBUG
644 | {
645 | int n = 0;
646 | list_item_t *p = NULL;
647 | for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
648 | fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
649 | }
650 | }
651 | #endif
652 |
653 | /*
654 | * Run the substitutions over each line of the input
655 | */
656 |
657 | while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
658 | list_item_t *p = NULL;
659 | for (p = substPtr; p != NULL; p = p->nextPtr) {
660 | char *m = strstr(szBuffer, p->key);
661 | if (m) {
662 | char *cp, *op, *sp;
663 | cp = szCopy;
664 | op = szBuffer;
665 | while (op != m) *cp++ = *op++;
666 | sp = p->value;
667 | while (sp && *sp) *cp++ = *sp++;
668 | op += strlen(p->key);
669 | while (*op) *cp++ = *op++;
670 | *cp = 0;
671 | memcpy(szBuffer, szCopy, sizeof(szCopy));
672 | }
673 | }
674 | printf("%s", szBuffer);
675 | }
676 |
677 | list_free(&substPtr);
678 | }
679 | fclose(fp);
680 | return 0;
681 | }
682 |
683 | BOOL FileExists(LPCTSTR szPath)
684 | {
685 | #ifndef INVALID_FILE_ATTRIBUTES
686 | #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
687 | #endif
688 | DWORD pathAttr = GetFileAttributes(szPath);
689 | return (pathAttr != INVALID_FILE_ATTRIBUTES &&
690 | !(pathAttr & FILE_ATTRIBUTE_DIRECTORY));
691 | }
692 |
693 |
694 | /*
695 | * QualifyPath --
696 | *
697 | * This composes the current working directory with a provided path
698 | * and returns the fully qualified and normalized path.
699 | * Mostly needed to setup paths for testing.
700 | */
701 |
702 | static int
703 | QualifyPath(
704 | const char *szPath)
705 | {
706 | char szCwd[MAX_PATH + 1];
707 |
708 | GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL);
709 | printf("%s\n", szCwd);
710 | return 0;
711 | }
712 |
713 | /*
714 | * Implements LocateDependency for a single directory. See that command
715 | * for an explanation.
716 | * Returns 0 if found after printing the directory.
717 | * Returns 1 if not found but no errors.
718 | * Returns 2 on any kind of error
719 | * Basically, these are used as exit codes for the process.
720 | */
721 | static int LocateDependencyHelper(const char *dir, const char *keypath)
722 | {
723 | HANDLE hSearch;
724 | char path[MAX_PATH+1];
725 | size_t dirlen;
726 | int keylen, ret;
727 | WIN32_FIND_DATA finfo;
728 |
729 | if (dir == NULL || keypath == NULL) {
730 | return 2; /* Have no real error reporting mechanism into nmake */
731 | }
732 | dirlen = strlen(dir);
733 | if (dirlen > sizeof(path) - 3) {
734 | return 2;
735 | }
736 | strncpy(path, dir, dirlen);
737 | strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */
738 | keylen = strlen(keypath);
739 |
740 | #if 0 /* This function is not available in Visual C++ 6 */
741 | /*
742 | * Use numerics 0 -> FindExInfoStandard,
743 | * 1 -> FindExSearchLimitToDirectories,
744 | * as these are not defined in Visual C++ 6
745 | */
746 | hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
747 | #else
748 | hSearch = FindFirstFile(path, &finfo);
749 | #endif
750 | if (hSearch == INVALID_HANDLE_VALUE) {
751 | return 1; /* Not found */
752 | }
753 |
754 | /* Loop through all subdirs checking if the keypath is under there */
755 | ret = 1; /* Assume not found */
756 | do {
757 | int sublen;
758 | /*
759 | * We need to check it is a directory despite the
760 | * FindExSearchLimitToDirectories in the above call. See SDK docs
761 | */
762 | if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
763 | continue;
764 | }
765 | sublen = strlen(finfo.cFileName);
766 | if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) {
767 | continue; /* Path does not fit, assume not matched */
768 | }
769 | strncpy(path+dirlen+1, finfo.cFileName, sublen);
770 | path[dirlen+1+sublen] = '\\';
771 | strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
772 | if (FileExists(path)) {
773 | /* Found a match, print to stdout */
774 | path[dirlen+1+sublen] = '\0';
775 | QualifyPath(path);
776 | ret = 0;
777 | break;
778 | }
779 | } while (FindNextFile(hSearch, &finfo));
780 | FindClose(hSearch);
781 | return ret;
782 | }
783 |
784 | /*
785 | * LocateDependency --
786 | *
787 | * Locates a dependency for a package.
788 | * keypath - a relative path within the package directory
789 | * that is used to confirm it is the correct directory.
790 | * The search path for the package directory is currently only
791 | * the parent and grandparent of the current working directory.
792 | * If found, the command prints
793 | * name_DIRPATH=
794 | * and returns 0. If not found, does not print anything and returns 1.
795 | */
796 | static int LocateDependency(const char *keypath)
797 | {
798 | size_t i;
799 | int ret;
800 | static const char *paths[] = {"..", "..\\..", "..\\..\\.."};
801 |
802 | for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
803 | ret = LocateDependencyHelper(paths[i], keypath);
804 | if (ret == 0) {
805 | return ret;
806 | }
807 | }
808 | return ret;
809 | }
810 |
811 |
812 | /*
813 | * Local variables:
814 | * mode: c
815 | * c-basic-offset: 4
816 | * fill-column: 78
817 | * indent-tabs-mode: t
818 | * tab-width: 8
819 | * End:
820 | */
821 |
--------------------------------------------------------------------------------