├── 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 | --------------------------------------------------------------------------------