Import Tcl 8.6.12

This commit is contained in:
Steve Dower
2021-11-08 17:30:58 +00:00
parent 1aadb2455c
commit 674867e7e6
608 changed files with 78089 additions and 60360 deletions

View File

@@ -0,0 +1,283 @@
2015-01-26 Don Porter <dgp@users.sourceforge.net>
* configure.in:
* README:
* library/tdbcsqlite3.tcl:
Advanced version number to 1.0.3.
* configure: autoconf-2.69
2014-10-23 Don Porter <dgp@users.sourceforge.net>
* configure.in:
* README:
* library/tdbcsqlite3.tcl:
Advanced version number to 1.0.2.
* configure: TEA update; autoconf-2.68
* doc/*.n: [TDBC Bug 00b792] OpenBSD friendly docs.
2012-11-08 Don Porter <dgp@users.sourceforge.net>
* configure.in:
* README:
* library/tdbcsqlite3.tcl:
Advanced version number to 1.0.1.
* configure: autoconf-2.68
2012-11-14 Donal K. Fellows <Donal.K.Fellows@man.ac.uk>
* configure.in: Added configuration code to allow `make test` to
* Makefile.in: run against an uninstalled 'tdbc' package.
* configure: autoconf-2.68
*** UPGRADED THE AUTOCONF VERSION IN USE ***
2012-11-08 Don Porter <dgp@users.sourceforge.net>
* configure.in:
* README:
* library/tdbcsqlite3.tcl:
Advanced version number to 1.0.0.
* configure: autoconf-2.59
2012-09-24 Harald Oehlmann <oehhar@users.sf.net>
* tdbcsqlite3/win/makefile.vc: Get DOTVERSION from file configure.in.
* tdbcsqlite3/win/nmakehelp.c: Copied from tcl Checkin [8be494c5ee]:
Let "nmakehlp -V" start searching digits after the found match
(nijtmans).
2012-08-17 Jan Nijtmans <nijtmans@users.sf.net>
* win/nmakehlp.c: Add "-V<num>" option, in order to be able
to detect partial version numbers.
2012-07-26 Jan Nijtmans <jan.nijtmans@gmail.com>
* tclconfig/install-sh: Update to latest TEA
* tclconfig/tcl.m4:
* configure: autoconf-2.59
2012-05-07 Kevin B. Kenny <kennyb@acm.org>
* library/tdbcsqlite.tcl: Revised the syntax of the 'variable'
command to avoid tripping over the
Tcl core changes made for TIP 380.
2011-09-19 Kevin B. Kenny <kennykb@acm.org>
* library/tdbcsqlite3.tcl: Reworked handling of the end of results
to avoid a bug where an empty result set at the end of the results
would crash in 'allrows' or 'foreach'. Thanks to Colin McCormack
for reporting the bug and providing a test case.
* tests/tdbcsqlite.tcl: Added a test case for the above bug,
observed to fail without the above change and pass with it.
2011-07-19 Kevin B. Kenny <kennykb@acm.org>
* configure.in:
* README:
* library/tdbcsqlite3.tcl:
Advanced version number to 1.0b17.
* configure: autoconf-2.59
2011-07-18 Don Porter <dgp@users.sourceforge.net>
* configure.in: Update to latest TEA 3.9 revisions.
* Makefile.in:
* tclconfig/*:
* configure: autoconf-2.59
2011-04-12 Kevin B. Kenny <kennykb@acm.org>
* library/tdbcsqlite3.tcl ([resultset nextresults]):
Corrected a bug in the handling of multiple result
sets when one or more is empty.
* tests/tdbcsqlite3.test (tdbc::sqlite3-30.6):
Added a test case for the above bug.
2011-02-20 Kevin B. Kenny <kennykb@acm.org>
* tests/tdbcsqlite3.test (tdbc::sqlite3-30.[45]):
Added tests for [foreach] and [allrows] against
multiple result sets.
2011-01-26 Kevin B. Kenny <kennykb@acm.org>
* doc/tdbc_sqlite3.n:
Added empty comment at the start of each manpage because 'man'
interprets comments there as directives. Thanks to Konstantin
Kohmoutov for reporting and diagnosing this error.
2010-09-03 Kevin B. Kenny <kennykb@acm.org>
* Makefile.in: Added a semicolon to the end of the -load option
on 'make test'. Without it, msys make changes all
the forward slashes in the -load option to backslashes.
* library/tdbcsqlite3.tcl:
* tests/tdbcsqlite3.test:
Changed 'keySequence' in 'foreignkeys' to
'ordinalPosition' for consistency with 'primarykeys'.
* configure.in:
* README:
* library/tdbcsqlite3.tcl:
* tclconfig/: Upgraded the build to use TEA 3.9.
Advanced version number to 1.0b16.
2010-06-19 Kevin B. Kenny <kennykb@acm.org>
* tdbcsqlite3.tcl: Added 'primarykeys' and 'foreignkeys'
* tdbcsqlite3.test: methods to the 'connection' object. Added
test cases for these methods.
2010-05-10 Kevin B. Kenny <kennykb@acm.org>
* aclocal.m4: Synchronized with 'tdbc'.
* configure.in: Advanced version to 1.0b15. Advanced TEA to 3.7.
* library/tdbcsqlite3.tcl:
Advanced version to 1.0b15.
* README: Advanced version to 1.0b15.
* tclconfig/: Advanced TEA to 3.7.
* configure: autoconf-2.59
2009-10-26 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b14.
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf 2.59
* tests/tdbcsqlite3.test: Added test cases (known bugs) for
duplicate column names in results.
* doc/tdbcsqlite3.n: Added a BUGS section documenting the
known problem with duplicate column
names.
2009-09-29 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b13
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2009-07-03 Kevin B. Kenny <kennykb@acm.org>
* tempTest.tcl (removed): Deleted obsolete test harness;
this package has used proper tcltest
testing for months.
* README: Advanced version number to 1.0b12
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2009-05-29 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b11
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2009-04-19 Kevin B. Kenny <kennykb@acm.org>
* doc/tdbc_sqlite3.n: Added missing documentation for 'new'
constructors.
2009-04-18 Kevin B. Kenny <kennykb@acm.org>
* tests/tdbcsqlite3.test: Changed the 'invalid path name' to a
path name that is more likely actually
to be invalid. Changed the tests for
inappropriate access to an array variable
not to expect failure.
* doc/tdbc_sqlite3.n: Made changes so that NROFF formatting matches
the Tcl standard.
2008-04-16 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b10
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2008-02-16 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b9
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2008-01-31 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b7
* configure.in:
* configure: autoconf-2.59
* library/tdbcsqlite3.tcl: Changed ::errorCode returns to
follow TDBC [try]-friendly convention
TDBC errorClass sqlState driver detail
2008-01-05 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b6
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2008-01-04 Kevin B. Kenny <kennykb@acm.org>
* Makefile.in: Changes to make 'make dist' work
* README: Advanced version number to 1.0b5
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2008-12-30 Kevin B. Kenny <kennykb@acm.org>
* README: Advanced version number to 1.0b4
* configure.in:
* library/tdbcsqlite3.tcl:
* configure: autoconf-2.59
2008-12-08 Kevin B. Kenny <kennykb@acm.org>
* doc/tdbcsqlite3.n: Added a man page for the driver.
* library/tdbcsqlite3.tcl (configure): Added a configurator for
* tests/tdbcsqlite3.test (tdbc::sqlite3-19.*): SQLite3 connections and
rudimentary test cases for connection configuration.
2008-12-07 Kevin B. Kenny <kennykb@acm.org>
* Makefile.in:
* aclocal.m4:
* configure.in:
* library/tdbcsqlite3.tcl:
* license.terms:
* pkgIndex.tcl.in:
* tclconfig/*:
* tests/all.tcl:
* tests/tdbcsqlite3.test:
Added infrastructure needed to make tdbc::sqlite3
a TEA-compliant module. Advanced revision number to 1.0b1 in
preparation for release.
2008-06-11 Kevin B. Kenny <kennykb@acm.org>
* library/tdbcsqlite3.tcl: Split [$resultset nextrow] into two
primitive methods: [$resultset nextlist] and [$resultset nextdict].
2008-05-13 Kevin B. Kenny <kennykb@acm.org>
* tests/tdbcsqlite3.test: Added cleanup for the test for
failing to open a database, in case we actually open it successfully.
2008-05-10 Kevin B. Kenny <kennykb@acm.org>
* ChangeLog: Added a change log.
* library/tdbcsqlite3.tcl: Added the 'columns' and 'tables'
methods for schema introspection.
* tests/tdbcsqlite3.test: Removed some superfluous debugging print.
Renumbered tdbcsqlite3-9.9. Corrected the tests for column
types to match SQLite's view of the world.

View File

@@ -0,0 +1,478 @@
# Makefile.in --
#
# This file is a Makefile for Sample TEA Extension. If it has the name
# "Makefile.in" then it is a template for a Makefile; to generate the
# actual Makefile, run "./configure", which is a configuration script
# generated by the "autoconf" program (constructs like "@foo@" will get
# replaced in the actual Makefile.
#
# Copyright (c) 1999 Scriptics Corporation.
# Copyright (c) 2002-2005 ActiveState Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#========================================================================
# Add additional lines to handle any additional AC_SUBST cases that
# have been added in a customized configure script.
#========================================================================
#SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@
#========================================================================
# Nothing of the variables below this line should need to be changed.
# Please check the TARGETS section below to make sure the make targets
# are correct.
#========================================================================
#========================================================================
# The names of the source files is defined in the configure script.
# The object files are used for linking into the final library.
# This will be used when a dist target is added to the Makefile.
# It is not important to specify the directory, as long as it is the
# $(srcdir) or in the generic, win or unix subdirectory.
#========================================================================
PKG_SOURCES = @PKG_SOURCES@
PKG_OBJECTS = @PKG_OBJECTS@
PKG_STUB_SOURCES = @PKG_STUB_SOURCES@
PKG_STUB_OBJECTS = @PKG_STUB_OBJECTS@
#========================================================================
# PKG_TCL_SOURCES identifies Tcl runtime files that are associated with
# this package that need to be installed, if any.
#========================================================================
PKG_TCL_SOURCES = @PKG_TCL_SOURCES@
#========================================================================
# This is a list of public header files to be installed, if any.
#========================================================================
PKG_HEADERS = @PKG_HEADERS@
#========================================================================
# "PKG_LIB_FILE" refers to the library (dynamic or static as per
# configuration options) composed of the named objects.
#========================================================================
PKG_LIB_FILE = @PKG_LIB_FILE@
PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@
lib_BINARIES = $(PKG_LIB_FILE)
BINARIES = $(lib_BINARIES)
SHELL = @SHELL@
srcdir = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
includedir = @includedir@
datarootdir = @datarootdir@
datadir = @datadir@
mandir = @mandir@
DESTDIR =
PKG_DIR = $(PACKAGE_NAME)-$(PACKAGE_VERSION)
pkgdatadir = $(datadir)/$(PKG_DIR)
pkglibdir = $(libdir)/$(PKG_DIR)
pkgincludedir = $(includedir)/$(PKG_DIR)
top_builddir = @abs_top_builddir@
INSTALL_OPTIONS =
INSTALL = @INSTALL@ $(INSTALL_OPTIONS)
INSTALL_DATA_DIR = @INSTALL_DATA_DIR@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_LIBRARY = @INSTALL_LIBRARY@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
CC = @CC@
CFLAGS_DEFAULT = @CFLAGS_DEFAULT@
CFLAGS_WARNING = @CFLAGS_WARNING@
EXEEXT = @EXEEXT@
LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@
MAKE_LIB = @MAKE_LIB@
MAKE_SHARED_LIB = @MAKE_SHARED_LIB@
MAKE_STATIC_LIB = @MAKE_STATIC_LIB@
MAKE_STUB_LIB = @MAKE_STUB_LIB@
OBJEXT = @OBJEXT@
RANLIB = @RANLIB@
RANLIB_STUB = @RANLIB_STUB@
SHLIB_CFLAGS = @SHLIB_CFLAGS@
SHLIB_LD = @SHLIB_LD@
SHLIB_LD_LIBS = @SHLIB_LD_LIBS@
STLIB_LD = @STLIB_LD@
#TCL_DEFS = @TCL_DEFS@
TCL_BIN_DIR = @TCL_BIN_DIR@
TCL_SRC_DIR = @TCL_SRC_DIR@
#TK_BIN_DIR = @TK_BIN_DIR@
#TK_SRC_DIR = @TK_SRC_DIR@
# Not used, but retained for reference of what libs Tcl required
#TCL_LIBS = @TCL_LIBS@
TDBC_VERSION = @TDBC_VERSION@
TDBC_BIN_DIR = @tdbc_BIN_DIR@
TDBC_LIB_FILE = @TDBC_LIB_FILE@
#========================================================================
# TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our
# package without installing. The other environment variables allow us
# to test against an uninstalled Tcl. Add special env vars that you
# require for testing here (like TCLX_LIBRARY).
#========================================================================
EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR)
#EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR)
TCLLIBPATH = $(top_builddir) $(TDBC_BIN_DIR)
TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library`
PKG_ENV = @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \
PATH="$(EXTRA_PATH):$(PATH)" \
TDBC_LIBRARY=`@CYGPATH@ @tdbc_LIBRARY_PATH@` \
TCLLIBPATH="$(TCLLIBPATH)"
TCLSH_PROG = @TCLSH_PROG@
TCLSH = $(TCLSH_ENV) $(PKG_ENV) $(TCLSH_PROG)
#WISH_ENV = TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library`
#WISH_PROG = @WISH_PROG@
#WISH = $(TCLSH_ENV) $(WISH_ENV) $(PKG_ENV) $(WISH_PROG)
SHARED_BUILD = @SHARED_BUILD@
INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@
#INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@
PKG_CFLAGS = @PKG_CFLAGS@
# TCL_DEFS is not strictly need here, but if you remove it, then you
# must make sure that configure.ac checks for the necessary components
# that your library may use. TCL_DEFS can actually be a problem if
# you do not compile with a similar machine setup as the Tcl core was
# compiled with.
#DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS)
DEFS = @DEFS@ $(PKG_CFLAGS)
# Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile
CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl
CLEANFILES = @CLEANFILES@
CPPFLAGS = @CPPFLAGS@
LIBS = @PKG_LIBS@ @LIBS@
AR = @AR@
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
GDB = gdb
VALGRIND = valgrind
VALGRINDARGS = --tool=memcheck --num-callers=8 --leak-resolution=high \
--leak-check=yes --show-reachable=yes -v
TCL_VERSION = @TCL_VERSION@
TCL_MAJOR_VERSION = @TCL_MAJOR_VERSION@
tmdir = $(libdir)/tcl$(TCL_MAJOR_VERSION)/$(TCL_VERSION)
pkgslash = `echo $(PACKAGE_NAME) | sed s=tdbc=tdbc/=`
pkgtmdir = $(tmdir)/tdbc
pkgtmfile = $(tmdir)/$(pkgslash)-$(PACKAGE_VERSION).tm
.SUFFIXES: .c .$(OBJEXT)
#========================================================================
# Start of user-definable TARGETS section
#========================================================================
#========================================================================
# TEA TARGETS. Please note that the "libraries:" target refers to platform
# independent files, and the "binaries:" target includes executable programs and
# platform-dependent libraries. Modify these targets so that they install
# the various pieces of your package. The make and install rules
# for the BINARIES that you specified above have already been done.
#========================================================================
all: binaries libraries doc
#========================================================================
# The binaries target builds executable programs, Windows .dll's, unix
# shared/static libraries, and any other platform-dependent files.
# The list of targets to build for "binaries:" is specified at the top
# of the Makefile, in the "BINARIES" variable.
#========================================================================
binaries: $(BINARIES)
libraries:
#========================================================================
# Your doc target should differentiate from doc builds (by the developer)
# and doc installs (see install-doc), which just install the docs on the
# end user machine when building from source.
#========================================================================
doc:
install: all install-tm install-doc
install-binaries: binaries install-lib-binaries install-bin-binaries
#========================================================================
# This rule installs platform-independent files, such as header files.
# The list=...; for p in $$list handles the empty list case x-platform.
#========================================================================
install-libraries: libraries
@$(INSTALL_DATA_DIR) $(DESTDIR)$(includedir)
@echo "Installing header files in $(DESTDIR)$(includedir)"
@list='$(PKG_HEADERS)'; for i in $$list; do \
echo "Installing $(srcdir)/$$i" ; \
$(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \
done;
#========================================================================
# Install documentation. Unix manpages should go in the $(mandir)
# directory.
#========================================================================
install-doc: doc
@$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/mann
@echo "Installing documentation in $(DESTDIR)$(mandir)"
@list='$(srcdir)/doc/*.n'; for i in $$list; do \
echo "Installing $$i"; \
$(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \
done
test: binaries libraries
$(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \
-load "package ifneeded tdbc::sqlite3 $(PACKAGE_VERSION) \
[list source `@CYGPATH@ $(srcdir)/library/tdbcsqlite3.tcl`]"
shell: binaries libraries
@$(TCLSH) $(SCRIPT)
gdb:
$(TCLSH_ENV) $(PKG_ENV) $(GDB) $(TCLSH_PROG) $(SCRIPT)
gdb-test: binaries libraries
$(TCLSH_ENV) $(PKG_ENV) $(GDB) \
--args $(TCLSH_PROG) `@CYGPATH@ $(srcdir)/tests/all.tcl` \
$(TESTFLAGS) -singleproc 1 \
-load "package ifneeded tdbc::sqlite3 $(PACKAGE_VERSION) \
[list source `@CYGPATH@ $(srcdir)/library/tdbcsqlite3.tcl`]"
valgrind: binaries libraries
$(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) \
`@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS)
valgrindshell: binaries libraries
$(TCLSH_ENV) $(PKG_ENV) $(VALGRIND) $(VALGRINDARGS) $(TCLSH_PROG) $(SCRIPT)
depend:
#========================================================================
# $(PKG_LIB_FILE) should be listed as part of the BINARIES variable
# mentioned above. That will ensure that this target is built when you
# run "make binaries".
#
# The $(PKG_OBJECTS) objects are created and linked into the final
# library. In most cases these object files will correspond to the
# source files above.
#========================================================================
$(PKG_LIB_FILE): $(PKG_OBJECTS)
-rm -f $(PKG_LIB_FILE)
${MAKE_LIB}
$(RANLIB) $(PKG_LIB_FILE)
$(PKG_STUB_LIB_FILE): $(PKG_STUB_OBJECTS)
-rm -f $(PKG_STUB_LIB_FILE)
${MAKE_STUB_LIB}
$(RANLIB_STUB) $(PKG_STUB_LIB_FILE)
#========================================================================
# We need to enumerate the list of .c to .o lines here.
#
# In the following lines, $(srcdir) refers to the toplevel directory
# containing your extension. If your sources are in a subdirectory,
# you will have to modify the paths to reflect this:
#
# sample.$(OBJEXT): $(srcdir)/generic/sample.c
# $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@
#
# Setting the VPATH variable to a list of paths will cause the makefile
# to look into these paths when resolving .c to .obj dependencies.
# As necessary, add $(srcdir):$(srcdir)/compat:....
#========================================================================
VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macosx
.c.@OBJEXT@:
$(COMPILE) -c `@CYGPATH@ $<` -o $@
#========================================================================
# Distribution creation
# You may need to tweak this target to make it work correctly.
#========================================================================
#COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar
COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR)
DIST_ROOT = /tmp/dist
DIST_DIR = $(DIST_ROOT)/$(PKG_DIR)
DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644
DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755
dist-clean:
rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.*
dist: dist-clean
$(INSTALL_DATA_DIR) $(DIST_DIR)
# TEA files
$(DIST_INSTALL_DATA) $(srcdir)/Makefile.in \
$(srcdir)/aclocal.m4 $(srcdir)/configure.ac \
$(DIST_DIR)/
$(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/
$(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig
$(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \
$(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \
$(DIST_DIR)/tclconfig/
# Extension files
$(DIST_INSTALL_DATA) \
$(srcdir)/ChangeLog \
$(srcdir)/license.terms \
$(srcdir)/README \
$(srcdir)/pkgIndex.tcl.in \
$(DIST_DIR)/
$(INSTALL_DATA_DIR) $(DIST_DIR)/doc
$(DIST_INSTALL_DATA) $(srcdir)/doc/tdbc_sqlite3.n $(DIST_DIR)/doc/
$(INSTALL_DATA_DIR) $(DIST_DIR)/library
$(DIST_INSTALL_DATA) $(srcdir)/library/tdbcsqlite3.tcl $(DIST_DIR)/library/
$(INSTALL_DATA_DIR) $(DIST_DIR)/tests
$(DIST_INSTALL_DATA) $(srcdir)/tests/all.tcl $(srcdir)/tests/tdbcsqlite3.test \
$(DIST_DIR)/tests/
$(INSTALL_DATA_DIR) $(DIST_DIR)/win
$(DIST_INSTALL_DATA) $(srcdir)/win/makefile.vc $(srcdir)/win/nmakehlp.c \
$(srcdir)/win/targets.vc $(srcdir)/win/rules-ext.vc \
$(srcdir)/win/rules.vc $(DIST_DIR)/win/
(cd $(DIST_ROOT); $(COMPRESS);)
#========================================================================
# End of user-definable section
#========================================================================
#========================================================================
# Don't modify the file to clean here. Instead, set the "CLEANFILES"
# variable in configure.ac
#========================================================================
clean:
-test -z "$(BINARIES)" || rm -f $(BINARIES)
-rm -f *.$(OBJEXT) core *.core
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean: clean
-rm -f *.tab.c
-rm -f $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log config.status
#========================================================================
# Install binary object libraries. On Windows this includes both .dll and
# .lib files. Because the .lib files are not explicitly listed anywhere,
# we need to deduce their existence from the .dll file of the same name.
# Library files go into the lib directory.
# In addition, this will generate the pkgIndex.tcl
# file in the install location (assuming it can find a usable tclsh shell)
#
# You should not have to modify this target.
#========================================================================
install-lib-binaries: binaries
@$(INSTALL_DATA_DIR) $(DESTDIR)$(pkglibdir)
@list='$(lib_BINARIES)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
$(INSTALL_LIBRARY) $$p $(DESTDIR)$(pkglibdir)/$$p; \
ext=`echo $$p|sed -e "s/.*\.//"`; \
if test "x$$ext" = "xdll"; then \
lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \
if test -f $$lib; then \
echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \
$(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \
fi; \
fi; \
fi; \
done
@list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
if test -f $(srcdir)/$$p; then \
destp=`basename $$p`; \
echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \
$(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \
fi; \
done
@if test "x$(SHARED_BUILD)" = "x1"; then \
echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \
$(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \
fi
#========================================================================
# Install binary executables (e.g. .exe files and dependent .dll files)
# This is for files that must go in the bin directory (located next to
# wish and tclsh), like dependent .dll files on Windows.
#
# You should not have to modify this target, except to define bin_BINARIES
# above if necessary.
#========================================================================
install-bin-binaries: binaries
@$(INSTALL_DATA_DIR) $(DESTDIR)$(bindir)
@list='$(bin_BINARIES)'; for p in $$list; do \
if test -f $$p; then \
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
fi; \
done
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
uninstall-binaries:
list='$(lib_BINARIES)'; for p in $$list; do \
rm -f $(DESTDIR)$(pkglibdir)/$$p; \
done
list='$(PKG_TCL_SOURCES)'; for p in $$list; do \
p=`basename $$p`; \
rm -f $(DESTDIR)$(pkglibdir)/$$p; \
done
list='$(bin_BINARIES)'; for p in $$list; do \
rm -f $(DESTDIR)$(bindir)/$$p; \
done
install-tm:
@$(INSTALL_DATA_DIR) $(DESTDIR)$(pkgtmdir)
$(INSTALL_DATA) $(srcdir)/library/tdbcsqlite3.tcl \
$(DESTDIR)$(pkgtmfile)
.PHONY: all binaries clean depend distclean doc install libraries test
.PHONY: gdb gdb-test valgrind valgrindshell
.PHONY: install-tm
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@@ -0,0 +1,41 @@
README: tdbcsqlite3
This is the 1.1.3 source distribution of the bridge between Tcl
Database Connectivity (TDBC) and SQLite3, an open-source SQL
database with an in-process server.
TDBC and its drivers are available from a Fossil version control
repository at http://tdbc.tcl.tk/
SQLite3 is available from http://sqlite.org/
RCS: @(#) $Id: $
1. Introduction
This directory contains the source code, documentation, and test
scripts for the SQLite3 driver for Tcl Database Connectivity. This
module, plus TDBC and SQLite3 themselves, allow you to access SQLite3
databases using a standard application programming interface (API)
from a Tcl script. This module is also available from
http://tdbc.tcl.tk along with the source code of TDBC itself. A bug
database and Wiki are available at the same location.
Tdbc::sqlite3 is a freely-available open source package. You can do
virtually anything you like with it, such as modifying it,
redistributing it, and selling it either in whole or in part. See the
file "license.terms" for complete information.
2. Documentation
The 'doc' subdirectory in this release contains a set of reference
manual entries for tdbc::sqlite3. Files with an extension '.n' are for
Tcl classes and commands; files with an extension '.3' are for C
library functions. The file, 'doc/tdbcsqlite3.n' gives an overview,
listing the classes and functions
3. See also
More information about TDBC and its drivers are available in the
README file for TDBC itself; refer to that file for compilation and
installation instructions, and support information.

86
pkgs/tdbcsqlite3-1.1.3/aclocal.m4 vendored Normal file
View File

@@ -0,0 +1,86 @@
#
# Include the TEA standard macro set
#
builtin(include,tclconfig/tcl.m4)
#
# Add here whatever m4 macros you want to define for your package
#
dnl Helper macros
AC_DEFUN([TEAX_LAPPEND], [$1="[$]{$1} $2"])
AC_DEFUN([TEAX_FOREACH], [for $1 in $2; do $3; done])
AC_DEFUN([TEAX_IFEQ], [AS_IF([test "x$1" = "x$2"], [$3])])
AC_DEFUN([TEAX_IFNEQ], [AS_IF([test "x$1" != "x$2"], [$3])])
AC_DEFUN([TEAX_SWITCH], [case "$1" in TEAX_SWITCH_Cases(m4_shift($@)) esac])
AC_DEFUN([TEAX_SWITCH_Cases], [m4_if([$#],0,,[$#],1,,[TEAX_SWITCH_OneCase($1,$2)TEAX_SWITCH_Cases(m4_shift(m4_shift($@)))])])
AC_DEFUN([TEAX_SWITCH_OneCase],[ $1) $2;;])
AC_DEFUN([CygPath],[`${CYGPATH} $1`])
dnl Interesting macros
AC_DEFUN([TEAX_SUBST_RESOURCE], [
AC_REQUIRE([TEA_CONFIG_CFLAGS])dnl
TEAX_IFEQ($TEA_PLATFORM, windows, [
AC_CHECK_PROGS(RC_, 'windres -o' 'rc -nologo -fo', none)
TEAX_SWITCH($RC_,
windres*, [
rcdef_inc="--include "
rcdef_start="--define "
rcdef_q='\"'
AC_SUBST(RES_SUFFIX, [res.o])
TEAX_LAPPEND(PKG_OBJECTS, ${PACKAGE_NAME}.res.o)],
rc*, [
rcdef_inc="-i "
rcdef_start="-d "
rcdef_q='"'
AC_SUBST(RES_SUFFIX, [res])
TEAX_LAPPEND(PKG_OBJECTS, ${PACKAGE_NAME}.res)],
*, [
AC_MSG_WARN([could not find resource compiler])
RC_=: ])])
# This next line is because of the brokenness of TEA...
AC_SUBST(RC, $RC_)
TEAX_FOREACH(i, $1, [
TEAX_LAPPEND(RES_DEFS, ${rcdef_inc}\"CygPath($i)\")])
TEAX_FOREACH(i, $2, [
TEAX_LAPPEND(RES_DEFS, ${rcdef_start}$i='${rcdef_q}\$($i)${rcdef_q}')])
AC_SUBST(RES_DEFS)])
AC_DEFUN([TEAX_ADD_PRIVATE_HEADERS], [
TEAX_FOREACH(i, $@, [
# check for existence, be strict because it should be present!
AS_IF([test ! -f "${srcdir}/$i"], [
AC_MSG_ERROR([could not find header file '${srcdir}/$i'])])
TEAX_LAPPEND(PKG_PRIVATE_HEADERS, $i)])
AC_SUBST(PKG_PRIVATE_HEADERS)])
AC_DEFUN([TEAX_SDX], [
AC_PATH_PROG(SDX, sdx, none)
TEAX_IFEQ($SDX, none, [
AC_PATH_PROG(SDX_KIT, sdx.kit, none)
TEAX_IFNEQ($SDX_KIT, none, [
# We assume that sdx.kit is on the path, and that the default
# tclsh is activetcl
SDX="tclsh '${SDX_KIT}'"])])
TEAX_IFEQ($SDX, none, [
AC_MSG_WARN([cannot find sdx; building starkits will fail])
AC_MSG_NOTICE([building as a normal library still supported])])])
dnl TODO: Adapt this for OSX Frameworks...
dnl This next bit is a bit ugly, but it makes things for tclooConfig.sh...
AC_DEFUN([TEAX_PATH_LINE], [
eval "$1=\"[]CygPath($2)\""
AC_SUBST($1)])
AC_DEFUN([TEAX_INCLUDE_LINE], [
eval "$1=\"-I[]CygPath($2)\""
AC_SUBST($1)])
AC_DEFUN([TEAX_LINK_LINE], [
AS_IF([test ${TCL_LIB_VERSIONS_OK} = nodots], [
eval "$1=\"-L[]CygPath($2) -l$3${TCL_TRIM_DOTS}\""
], [
eval "$1=\"-L[]CygPath($2) -l$3${PACKAGE_VERSION}\""
])
AC_SUBST($1)])
dnl Local Variables:
dnl mode: autoconf
dnl End:

8457
pkgs/tdbcsqlite3-1.1.3/configure vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,203 @@
#!/bin/bash -norc
dnl This file is an input file used by the GNU "autoconf" program to
dnl generate the file "configure", which is run during Tcl installation
dnl to configure the system for the local environment.
#-----------------------------------------------------------------------
# Sample configure.ac for Tcl Extensions. The only places you should
# need to modify this file are marked by the string __CHANGE__
#-----------------------------------------------------------------------
#-----------------------------------------------------------------------
# __CHANGE__
# Set your package name and version numbers here.
#
# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION
# set as provided. These will also be added as -D defs in your Makefile
# so you can encode the package version directly into the source files.
# This will also define a special symbol for Windows (BUILD_<PACKAGE_NAME>
# so that we create the export library with the dll.
#-----------------------------------------------------------------------
AC_INIT([tdbcsqlite3],[1.1.3])
#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
# This will define a ${TEA_PLATFORM} variable == "unix" or "windows"
# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE.
#--------------------------------------------------------------------
TEA_INIT()
AC_CONFIG_AUX_DIR(tclconfig)
#--------------------------------------------------------------------
# Load the tclConfig.sh file
#--------------------------------------------------------------------
TEA_PATH_TCLCONFIG
TEA_LOAD_TCLCONFIG
#--------------------------------------------------------------------
# Load the tkConfig.sh file if necessary (Tk extension)
#--------------------------------------------------------------------
#TEA_PATH_TKCONFIG
#TEA_LOAD_TKCONFIG
#----------------------------------------------------------------------
# Load the tdbcConfig.sh file
#----------------------------------------------------------------------
TEA_PATH_CONFIG(tdbc)
TEA_LOAD_CONFIG(tdbc)
# The next bit probably ought to be in TEA_LOAD_CONFIG
AC_MSG_WARN([Looking for "${tdbc_BIN_DIR}/Makefile"])
if test -f "${tdbc_BIN_DIR}/Makefile" ; then
AC_MSG_WARN([Found Makefile - using build include spec and lib specs for tdbc])
tdbc_INCLUDE_SPEC=${tdbc_BUILD_INCLUDE_SPEC}
tdbc_LIBRARY_PATH=${tdbc_BUILD_LIBRARY_PATH}
fi
AC_SUBST(tdbc_LIBRARY_PATH)
AC_SUBST(TDBC_VERSION)
AC_SUBST(tdbc_BIN_DIR)
AC_SUBST(TDBC_LIB_FILE)
#-----------------------------------------------------------------------
# Handle the --prefix=... option by defaulting to what Tcl gave.
# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER.
#-----------------------------------------------------------------------
TEA_PREFIX
#-----------------------------------------------------------------------
# Standard compiler checks.
# This sets up CC by using the CC env var, or looks for gcc otherwise.
# This also calls AC_PROG_CC and a few others to create the basic setup
# necessary to compile executables.
#-----------------------------------------------------------------------
#TEA_SETUP_COMPILER
#-----------------------------------------------------------------------
# __CHANGE__
# Specify the C source files to compile in TEA_ADD_SOURCES,
# public headers that need to be installed in TEA_ADD_HEADERS,
# stub library C source files to compile in TEA_ADD_STUB_SOURCES,
# and runtime Tcl library files in TEA_ADD_TCL_SOURCES.
# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS
# and PKG_TCL_SOURCES.
#-----------------------------------------------------------------------
#TEA_ADD_SOURCES([])
#TEA_ADD_HEADERS([])
#TEA_ADD_INCLUDES([])
#TEA_ADD_LIBS([])
#TEA_ADD_CFLAGS([])
#TEA_ADD_STUB_SOURCES([])
TEA_ADD_TCL_SOURCES([library/tdbcsqlite3.tcl])
#--------------------------------------------------------------------
# __CHANGE__
#
# You can add more files to clean if your extension creates any extra
# files by extending CLEANFILES.
# Add pkgIndex.tcl if it is generated in the Makefile instead of ./configure
# and change Makefile.in to move it from CONFIG_CLEAN_FILES to BINARIES var.
#
# A few miscellaneous platform-specific items:
# TEA_ADD_* any platform specific compiler/build info here.
#--------------------------------------------------------------------
#CLEANFILES="$CLEANFILES pkgIndex.tcl"
if test "${TEA_PLATFORM}" = "windows" ; then
# Ensure no empty if clauses
:
#TEA_ADD_SOURCES([win/winFile.c])
#TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"])
else
# Ensure no empty else clauses
:
#TEA_ADD_SOURCES([unix/unixFile.c])
#TEA_ADD_LIBS([-lsuperfly])
fi
#--------------------------------------------------------------------
# __CHANGE__
# Choose which headers you need. Extension authors should try very
# hard to only rely on the Tcl public header files. Internal headers
# contain private data structures and are subject to change without
# notice.
# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG
#--------------------------------------------------------------------
#TEA_PUBLIC_TCL_HEADERS
#TEA_PRIVATE_TCL_HEADERS
#TEA_PUBLIC_TK_HEADERS
#TEA_PRIVATE_TK_HEADERS
#TEA_PATH_X
#--------------------------------------------------------------------
# Check whether --enable-threads or --disable-threads was given.
# This auto-enables if Tcl was compiled threaded.
#--------------------------------------------------------------------
TEA_ENABLE_THREADS
#--------------------------------------------------------------------
# The statement below defines a collection of symbols related to
# building as a shared library instead of a static library.
#--------------------------------------------------------------------
#TEA_ENABLE_SHARED
#--------------------------------------------------------------------
# This macro figures out what flags to use with the compiler/linker
# when building shared/static debug/optimized objects. This information
# can be taken from the tclConfig.sh file, but this figures it all out.
#--------------------------------------------------------------------
#TEA_CONFIG_CFLAGS
#--------------------------------------------------------------------
# Set the default compiler switches based on the --enable-symbols option.
#--------------------------------------------------------------------
TEA_ENABLE_SYMBOLS
#--------------------------------------------------------------------
# This macro generates a line to use when building a library. It
# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS,
# and TEA_LOAD_TCLCONFIG macros above.
#--------------------------------------------------------------------
#TEA_MAKE_LIB
#--------------------------------------------------------------------
# Determine the name of the tclsh and/or wish executables in the
# Tcl and Tk build directories or the location they were installed
# into. These paths are used to support running test cases only,
# the Makefile should not be making use of these paths to generate
# a pkgIndex.tcl file or anything else at extension build time.
#--------------------------------------------------------------------
TEA_PROG_TCLSH
#TEA_PROG_WISH
#--------------------------------------------------------------------
# Substitute variables needed for .tm install.
#--------------------------------------------------------------------
AC_SUBST(TCL_VERSION)
AC_SUBST(TCL_MAJOR_VERSION)
AC_SUBST(TCL_MINOR_VERSION)
#--------------------------------------------------------------------
# Finally, substitute all of the various values into the Makefile.
# You may alternatively have a special pkgIndex.tcl.in or other files
# which require substituting the AC variables in. Include these here.
#--------------------------------------------------------------------
AC_CONFIG_FILES([Makefile pkgIndex.tcl])
AC_OUTPUT

View File

@@ -0,0 +1,119 @@
'\"
.\" tdbc_sqlite3.n --
.\"
.\" Copyright (c) 2008 by Kevin B. Kenny.
.\"
.\" See the file "license.terms" for information on usage and redistribution of
.\" this file, and for a DISCLAIMER OF ALL WARRANTIES.
.TH "tdbc::sqlite3" n 8.6 Tcl "Tcl Database Connectivity"
.\" .so man.macros
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.BS
.SH "NAME"
tdbc::sqlite3 \- TDBC driver for the SQLite3 database manager
.SH "SYNOPSIS"
package require \fBtdbc::sqlite3 1.0\fR
.sp
\fBtdbc::sqlite3::connection create\fR \fIdb\fR \fIfileName\fR ?\fI-option value...\fR?
.BE
.SH "DESCRIPTION"
.PP
The \fBtdbc::sqlite3\fR driver provides a database interface that conforms
to Tcl DataBase Connectivity (TDBC) and allows a Tcl script to connect
to a SQLite3 database. It is also provided
as a worked example of how to write a database driver in Tcl, so that
driver authors have a starting point for further development.
.PP
Connection to a SQLite3 database is established by invoking
\fBtdbc::sqlite3::connection create\fR, passing it a string to be used
as the connection handle followed by the file name of
the database. The side effect of \fBtdbc::sqlite3::connection
create\fR is to create a new database connection..
As an alternative, \fBtdbc::sqlite::connection new\fR may be used to create
a database connection with an automatically assigned name. The return value
from \fBtdbc::sqlite::connection new\fR is the name that was chosen for the
connection handle. See
\fBtdbc::connection(n)\fR for the details of how to use the connection
to manipulate a database.
.SH "CONFIGURATION OPTIONS"
.PP
The standard configuration options \fB-encoding\fR, \fB-isolation\fR,
\fB-readonly\fR and \fB-timeout\fR are all recognized, both on
\fBtdbc::sqlite3::connection create\fR and on the \fBconfigure\fR
method of the resulting connection.
.PP
Since the encoding of a SQLite3 database is always well known, the
\fB-encoding\fR option accepts only \fButf-8\fR as an encoding and
always returns \fButf-8\fR for an encoding. The actual encoding may be
set using a SQLite3 \fBPRAGMA\fR statement when creating a new
database.
.PP
Only the isolation levels \fBreaduncommitted\fR and \fBserializable\fR
are implemented. Other isolation levels are promoted to
\fBserializable\fR.
.PP
The \fB-readonly\fR flag is not implemented. \fB-readonly 0\fR is
accepted silently, while \fB-readonly 1\fR reports an error.
.SH "BUGS"
If any column name is not unique among the columns in a result set, the
results of \fB-as dicts\fR returns will be missing all but the rightmost
of the duplicated columns. This limitation can be worked around by adding
appropriate \fBAS\fR clauses to \fBSELECT\fR statements to ensure that
all returned column names are unique. Plans are to fix this bug by using
a C implementation of the driver, which will also improve performance
significantly.
.SH "SEE ALSO"
tdbc(n), tdbc::connection(n), tdbc::resultset(n), tdbc::statement(n)
.SH "KEYWORDS"
TDBC, SQL, SQLite3, database, connectivity, connection
.SH "COPYRIGHT"
Copyright (c) 2008 by Kevin B. Kenny.
.\" Local Variables:
.\" mode: nroff
.\" End:
.\"

View File

@@ -0,0 +1,715 @@
# tdbcsqlite3.tcl --
#
# SQLite3 database driver for TDBC
#
# Copyright (c) 2008 by Kevin B. Kenny.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: tdbcodbc.tcl,v 1.47 2008/02/27 02:08:27 kennykb Exp $
#
#------------------------------------------------------------------------------
package require tdbc
package require sqlite3
package provide tdbc::sqlite3 1.1.3
namespace eval tdbc::sqlite3 {
namespace export connection
}
#------------------------------------------------------------------------------
#
# tdbc::sqlite3::connection --
#
# Class representing a SQLite3 database connection
#
#------------------------------------------------------------------------------
::oo::class create ::tdbc::sqlite3::connection {
superclass ::tdbc::connection
variable timeout
# The constructor accepts a database name and opens the database.
constructor {databaseName args} {
set timeout 0
if {[llength $args] % 2 != 0} {
set cmd [lrange [info level 0] 0 end-[llength $args]]
return -code error \
-errorcode {TDBC GENERAL_ERROR HY000 SQLITE3 WRONGNUMARGS} \
"wrong # args, should be \"$cmd ?-option value?...\""
}
next
sqlite3 [namespace current]::db $databaseName
if {[llength $args] > 0} {
my configure {*}$args
}
db nullvalue \ufffd
}
# The 'statementCreate' method forwards to the constructor of the
# statement class
forward statementCreate ::tdbc::sqlite3::statement create
# The 'configure' method queries and sets options to the database
method configure args {
if {[llength $args] == 0} {
# Query all configuration options
set result {-encoding utf-8}
lappend result -isolation
if {[db onecolumn {PRAGMA read_uncommitted}]} {
lappend result readuncommitted
} else {
lappend result serializable
}
lappend result -readonly 0
lappend result -timeout $timeout
return $result
} elseif {[llength $args] == 1} {
# Query a single option
set option [lindex $args 0]
switch -exact -- $option {
-e - -en - -enc - -enco - -encod - -encodi - -encodin -
-encoding {
return utf-8
}
-i - -is - -iso - -isol - -isola - -isolat - -isolati -
-isolatio - -isolation {
if {[db onecolumn {PRAGMA read_uncommitted}]} {
return readuncommitted
} else {
return serializable
}
}
-r - -re - -rea - -read - -reado - -readon - -readonl -
-readonly {
return 0
}
-t - -ti - -tim - -time - -timeo - -timeou - -timeout {
return $timeout
}
default {
return -code error \
-errorcode [list TDBC GENERAL_ERROR HY000 SQLITE3 \
BADOPTION $option] \
"bad option \"$option\": must be\
-encoding, -isolation, -readonly or -timeout"
}
}
} elseif {[llength $args] % 2 != 0} {
# Syntax error
set cmd [lrange [info level 0] 0 end-[llength $args]]
return -code error \
-errorcode [list TDBC GENERAL_ERROR HY000 \
SQLITE3 WRONGNUMARGS] \
"wrong # args, should be \" $cmd ?-option value?...\""
}
# Set one or more options
foreach {option value} $args {
switch -exact -- $option {
-e - -en - -enc - -enco - -encod - -encodi - -encodin -
-encoding {
if {$value ne {utf-8}} {
return -code error \
-errorcode [list TDBC FEATURE_NOT_SUPPORTED 0A000 \
SQLITE3 ENCODING] \
"-encoding not supported. SQLite3 is always \
Unicode."
}
}
-i - -is - -iso - -isol - -isola - -isolat - -isolati -
-isolatio - -isolation {
switch -exact -- $value {
readu - readun - readunc - readunco - readuncom -
readuncomm - readuncommi - readuncommit -
readuncommitt - readuncommitte - readuncommitted {
db eval {PRAGMA read_uncommitted = 1}
}
readc - readco - readcom - readcomm - readcommi -
readcommit - readcommitt - readcommitte -
readcommitted -
rep - repe - repea - repeat - repeata - repeatab -
repeatabl - repeatable - repeatabler - repeatablere -
repeatablerea - repeatablread -
s - se - ser - seri - seria - serial - seriali -
serializ - serializa - serializab - serializabl -
serializable -
reado - readon - readonl - readonly {
db eval {PRAGMA read_uncommitted = 0}
}
default {
return -code error \
-errorcode [list TDBC GENERAL_ERROR HY000 \
SQLITE3 BADISOLATION $value] \
"bad isolation level \"$value\":\
should be readuncommitted, readcommitted,\
repeatableread, serializable, or readonly"
}
}
}
-r - -re - -rea - -read - -reado - -readon - -readonl -
-readonly {
if {$value} {
return -code error \
-errorcode [list TDBC FEATURE_NOT_SUPPORTED 0A000 \
SQLITE3 READONLY] \
"SQLite3's Tcl API does not support read-only\
access"
}
}
-t - -ti - -tim - -time - -timeo - -timeou - -timeout {
if {![string is integer $value]} {
return -code error \
-errorcode [list TDBC DATA_EXCEPTION 22018 \
SQLITE3 $value] \
"expected integer but got \"$value\""
}
db timeout $value
set timeout $value
}
default {
return -code error \
-errorcode [list TDBC GENERAL_ERROR HY000 \
SQLITE3 BADOPTION $value] \
"bad option \"$option\": must be\
-encoding, -isolation, -readonly or -timeout"
}
}
}
return
}
# The 'tables' method introspects on the tables in the database.
method tables {{pattern %}} {
set retval {}
my foreach row {
SELECT * from sqlite_master
WHERE type IN ('table', 'view')
AND name LIKE :pattern
} {
dict set row name [string tolower [dict get $row name]]
dict set retval [dict get $row name] $row
}
return $retval
}
# The 'columns' method introspects on columns of a table.
method columns {table {pattern %}} {
regsub -all ' $table '' table
set retval {}
set pattern [string map [list \
* {[*]} \
? {[?]} \
\[ \\\[ \
\] \\\[ \
_ ? \
% *] [string tolower $pattern]]
my foreach origrow "PRAGMA table_info('$table')" {
set row {}
dict for {key value} $origrow {
dict set row [string tolower $key] $value
}
dict set row name [string tolower [dict get $row name]]
if {![string match $pattern [dict get $row name]]} {
continue
}
switch -regexp -matchvar info [dict get $row type] {
{^(.+)\(\s*([[:digit:]]+)\s*,\s*([[:digit:]]+)\s*\)\s*$} {
dict set row type [string tolower [lindex $info 1]]
dict set row precision [lindex $info 2]
dict set row scale [lindex $info 3]
}
{^(.+)\(\s*([[:digit:]]+)\s*\)\s*$} {
dict set row type [string tolower [lindex $info 1]]
dict set row precision [lindex $info 2]
dict set row scale 0
}
default {
dict set row type [string tolower [dict get $row type]]
dict set row precision 0
dict set row scale 0
}
}
dict set row nullable [expr {![dict get $row notnull]}]
dict set retval [dict get $row name] $row
}
return $retval
}
# The 'primarykeys' method enumerates the primary keys on a table.
method primarykeys {table} {
set result {}
my foreach row "PRAGMA table_info($table)" {
if {[dict get $row pk]} {
lappend result [dict create ordinalPosition \
[expr {[dict get $row cid]+1}] \
columnName \
[dict get $row name]]
}
}
return $result
}
# The 'foreignkeys' method enumerates the foreign keys that are
# declared in a table or that refer to a given table.
method foreignkeys {args} {
variable ::tdbc::generalError
# Check arguments
set argdict {}
if {[llength $args] % 2 != 0} {
set errorcode $generalError
lappend errorcode wrongNumArgs
return -code error -errorcode $errorcode \
"wrong # args: should be [lrange [info level 0] 0 1]\
?-option value?..."
}
foreach {key value} $args {
if {$key ni {-primary -foreign}} {
set errorcode $generalError
lappend errorcode badOption
return -code error -errorcode $errorcode \
"bad option \"$key\", must be -primary or -foreign"
}
set key [string range $key 1 end]
if {[dict exists $argdict $key]} {
set errorcode $generalError
lappend errorcode dupOption
return -code error -errorcode $errorcode \
"duplicate option \"$key\" supplied"
}
dict set argdict $key $value
}
# If we know the table with the foreign key, search just its
# foreign keys. Otherwise, iterate over all the tables in the
# database.
if {[dict exists $argdict foreign]} {
return [my ForeignKeysForTable [dict get $argdict foreign] \
$argdict]
} else {
set result {}
foreach foreignTable [dict keys [my tables]] {
lappend result {*}[my ForeignKeysForTable \
$foreignTable $argdict]
}
return $result
}
}
# The private ForeignKeysForTable method enumerates the foreign keys
# in a specific table.
#
# Parameters:
#
# foreignTable - Name of the table containing foreign keys.
# argdict - Dictionary that may or may not contain a key,
# 'primary', whose value is the name of a table that
# must hold the primary key corresponding to the foreign
# key. If the 'primary' key is absent, all tables are
# candidates.
# Results:
#
# Returns the list of foreign keys that meed the specified
# conditions, as a list of dictionaries, each containing the
# keys, foreignConstraintName, foreignTable, foreignColumn,
# primaryTable, primaryColumn, and ordinalPosition. Note that the
# foreign constraint name is constructed arbitrarily, since SQLite3
# does not report this information.
method ForeignKeysForTable {foreignTable argdict} {
set result {}
set n 0
# Go through the foreign keys in the given table, looking for
# ones that refer to the primary table (if one is given), or
# for any primary keys if none is given.
my foreach row "PRAGMA foreign_key_list($foreignTable)" {
if {(![dict exists $argdict primary])
|| ([string tolower [dict get $row table]]
eq [dict get $argdict primary])} {
# Construct a dictionary for each key, translating
# SQLite names to TDBC ones and converting sequence
# numbers to 1-based indexing.
set rrow [dict create foreignTable $foreignTable \
foreignConstraintName \
?$foreignTable?[dict get $row id]]
if {[dict exists $row seq]} {
dict set rrow ordinalPosition \
[expr {1 + [dict get $row seq]}]
}
foreach {to from} {
foreignColumn from
primaryTable table
primaryColumn to
deleteAction on_delete
updateAction on_update
} {
if {[dict exists $row $from]} {
dict set rrow $to [dict get $row $from]
}
}
# Add the newly-constucted dictionary to the result list
lappend result $rrow
}
}
return $result
}
# The 'preparecall' method prepares a call to a stored procedure.
# SQLite3 does not have stored procedures, since it's an in-process
# server.
method preparecall {call} {
return -code error \
-errorcode [list TDBC FEATURE_NOT_SUPPORTED 0A000 \
SQLITE3 PREPARECALL] \
{SQLite3 does not support stored procedures}
}
# The 'begintransaction' method launches a database transaction
method begintransaction {} {
db eval {BEGIN TRANSACTION}
}
# The 'commit' method commits a database transaction
method commit {} {
db eval {COMMIT}
}
# The 'rollback' method abandons a database transaction
method rollback {} {
db eval {ROLLBACK}
}
# The 'transaction' method executes a script as a single transaction.
# We override the 'transaction' method of the base class, since SQLite3
# has a faster implementation of the same thing. (The base class's generic
# method should also work.)
# (Don't overload the base class method, because 'break', 'continue'
# and 'return' in the transaction body don't work!)
#method transaction {script} {
# uplevel 1 [list {*}[namespace code db] transaction $script]
#}
method prepare {sqlCode} {
set result [next $sqlCode]
return $result
}
method getDBhandle {} {
return [namespace which db]
}
}
#------------------------------------------------------------------------------
#
# tdbc::sqlite3::statement --
#
# Class representing a statement to execute against a SQLite3 database
#
#------------------------------------------------------------------------------
::oo::class create ::tdbc::sqlite3::statement {
superclass ::tdbc::statement
variable Params db sql
# The constructor accepts the handle to the connection and the SQL
# code for the statement to prepare. All that it does is to parse the
# statement and store it. The parse is used to support the
# 'params' and 'paramtype' methods.
constructor {connection sqlcode} {
next
set Params {}
set db [$connection getDBhandle]
set sql $sqlcode
foreach token [::tdbc::tokenize $sqlcode] {
if {[string index $token 0] in {$ : @}} {
dict set Params [string range $token 1 end] \
{type Tcl_Obj precision 0 scale 0 nullable 1 direction in}
}
}
}
# The 'resultSetCreate' method relays to the result set constructor
forward resultSetCreate ::tdbc::sqlite3::resultset create
# The 'params' method returns descriptions of the parameters accepted
# by the statement
method params {} {
return $Params
}
# The 'paramtype' method need do nothing; Sqlite3 uses manifest typing.
method paramtype args {;}
method getDBhandle {} {
return $db
}
method getSql {} {
return $sql
}
}
#-------------------------------------------------------------------------------
#
# tdbc::sqlite3::resultset --
#
# Class that represents a SQLlite result set in Tcl
#
#-------------------------------------------------------------------------------
::oo::class create ::tdbc::sqlite3::resultset {
superclass ::tdbc::resultset
# The variables of this class all have peculiar names. The reason is
# that the RunQuery method needs to execute with an activation record
# that has no local variables whose names could conflict with names
# in the SQL query. We start the variable names with hyphens because
# they can't be bind variables.
variable -set {*}{
-columns -db -needcolumns -resultArray
-results -sql -Cursor -RowCount -END
}
constructor {statement args} {
next
set -db [$statement getDBhandle]
set -sql [$statement getSql]
set -columns {}
set -results {}
${-db} trace [namespace code {my RecordStatement}]
if {[llength $args] == 0} {
# Variable substitutions are evaluated in caller's context
uplevel 1 [list ${-db} eval ${-sql} \
[namespace which -variable -resultArray] \
[namespace code {my RecordResult}]]
} elseif {[llength $args] == 1} {
# Variable substitutions are in the dictionary at [lindex $args 0].
set -paramDict [lindex $args 0]
# At this point, the activation record must contain no variables
# that might be bound within the query. All variables at this point
# begin with hyphens so that they are syntactically incorrect
# as bound variables in SQL.
unset args
unset statement
dict with -paramDict {
${-db} eval ${-sql} -resultArray {
my RecordResult
}
}
} else {
${-db} trace {}
# Too many args
return -code error \
-errorcode [list TDBC GENERAL_ERROR HY000 \
SQLITE3 WRONGNUMARGS] \
"wrong # args: should be\
[lrange [info level 0] 0 1] statement ?dictionary?"
}
${-db} trace {}
set -Cursor 0
if {${-Cursor} < [llength ${-results}]
&& [lindex ${-results} ${-Cursor}] eq {statement}} {
incr -Cursor 2
}
if {${-Cursor} < [llength ${-results}]
&& [lindex ${-results} ${-Cursor}] eq {columns}} {
incr -Cursor
set -columns [lindex ${-results} ${-Cursor}]
incr -Cursor
}
set -RowCount [${-db} changes]
}
# Record the start of a SQL statement
method RecordStatement {stmt} {
set -needcolumns 1
lappend -results statement {}
}
# Record one row of results from a query by appending it as a dictionary
# to the 'results' list. As a side effect, set 'columns' to a list
# comprising the names of the columns of the result.
method RecordResult {} {
set columns ${-resultArray(*)}
if {[info exists -needcolumns]} {
lappend -results columns $columns
unset -needcolumns
}
set dict {}
foreach key $columns {
if {[set -resultArray($key)] ne "\ufffd"} {
dict set dict $key [set -resultArray($key)]
}
}
lappend -results row $dict
}
# Advance to the next result set
method nextresults {} {
set have 0
while {${-Cursor} < [llength ${-results}]} {
if {[lindex ${-results} ${-Cursor}] eq {statement}} {
set have 1
incr -Cursor 2
break
}
incr -Cursor 2
}
if {!$have} {
set -END {}
}
if {${-Cursor} >= [llength ${-results}]} {
set -columns {}
} elseif {[lindex ${-results} ${-Cursor}] eq {columns}} {
incr -Cursor
set -columns [lindex ${-results} ${-Cursor}]
incr -Cursor
} else {
set -columns {}
}
return $have
}
method getDBhandle {} {
return ${-db}
}
# Return a list of the columns
method columns {} {
if {[info exists -END]} {
return -code error \
-errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
"Function sequence error: result set is exhausted."
}
return ${-columns}
}
# Return the next row of the result set as a list
method nextlist var {
upvar 1 $var row
if {[info exists -END]} {
return -code error \
-errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
"Function sequence error: result set is exhausted."
}
if {${-Cursor} >= [llength ${-results}]
|| [lindex ${-results} ${-Cursor}] ne {row}} {
return 0
} else {
set row {}
incr -Cursor
set d [lindex ${-results} ${-Cursor}]
incr -Cursor
foreach key ${-columns} {
if {[dict exists $d $key]} {
lappend row [dict get $d $key]
} else {
lappend row {}
}
}
}
return 1
}
# Return the next row of the result set as a dict
method nextdict var {
upvar 1 $var row
if {[info exists -END]} {
return -code error \
-errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
"Function sequence error: result set is exhausted."
}
if {${-Cursor} >= [llength ${-results}]
|| [lindex ${-results} ${-Cursor}] ne {row}} {
return 0
} else {
incr -Cursor
set row [lindex ${-results} ${-Cursor}]
incr -Cursor
}
return 1
}
# Return the number of rows affected by a statement
method rowcount {} {
if {[info exists -END]} {
return -code error \
-errorcode {TDBC GENERAL_ERROR HY010 SQLITE3 FUNCTIONSEQ} \
"Function sequence error: result set is exhausted."
}
return ${-RowCount}
}
}

View File

@@ -0,0 +1,38 @@
This software is copyrighted by the Scriptics Corporation, and other
parties. The following terms apply to all files associated with the
software unless explicitly disclaimed in individual files.
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
GOVERNMENT USE: If you are acquiring this software on behalf of the
U.S. government, the Government shall have only "Restricted Rights"
in the software and related documentation as defined in the Federal
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
are acquiring the software on behalf of the Department of Defense, the
software shall be classified as "Commercial Computer Software" and the
Government shall have only "Restricted Rights" as defined in Clause
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
authors grant the U.S. Government and others acting in its behalf
permission to use and distribute the software in accordance with the
terms specified in this license.

View File

@@ -0,0 +1,4 @@
# Index file to load the TDBC SQLite3 package.
package ifneeded tdbc::sqlite3 @PACKAGE_VERSION@ \
[list source [file join $dir .. library tdbcsqlite3.tcl]]

View File

@@ -0,0 +1,26 @@
These files comprise the basic building blocks for a Tcl Extension
Architecture (TEA) extension. For more information on TEA see:
http://www.tcl.tk/doc/tea/
This package is part of the Tcl project at SourceForge, but sources
and bug/patch database are hosted on fossil here:
https://core.tcl-lang.org/tclconfig
This package is a freely available open source package. You can do
virtually anything you like with it, such as modifying it, redistributing
it, and selling it either in whole or in part.
CONTENTS
========
The following is a short description of the files you will find in
the sample extension.
README.txt This file
install-sh Program used for copying binaries and script files
to their install locations.
tcl.m4 Collection of Tcl autoconf macros. Included by a package's
aclocal.m4 to define TEA_* macros.

View File

@@ -0,0 +1,518 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2020-07-26.22; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
# Create dirs (including intermediate dirs) using mode 755.
# This is like GNU 'install' as of coreutils 8.32 (2020).
mkdir_umask=22
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-S OPTION $stripprog installed files using OPTION.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-S) stripcmd="$stripprog $2"
shift;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dstbase=`basename "$src"`
case $dst in
*/) dst=$dst$dstbase;;
*) dst=$dst/$dstbase;;
esac
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
case $dstdir in
*/) dstdirslash=$dstdir;;
*) dstdirslash=$dstdir/;;
esac
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
# The $RANDOM variable is not portable (e.g., dash). Use it
# here however when possible just to lower collision chance.
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap '
ret=$?
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
exit $ret
' 0
# Because "mkdir -p" follows existing symlinks and we likely work
# directly in world-writeable /tmp, make sure that the '$tmpdir'
# directory is successfully created first before we actually test
# 'mkdir -p'.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
trap '' 0;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=${dstdirslash}_inst.$$_
rmtmp=${dstdirslash}_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask &&
{ test -z "$stripcmd" || {
# Create $dsttmp read-write so that cp doesn't create it read-only,
# which would cause strip to fail.
if test -z "$doit"; then
: >"$dsttmp" # No need to fork-exec 'touch'.
else
$doit touch "$dsttmp"
fi
}
} &&
$doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
# all.tcl --
#
# This file contains a top-level script to run all of the Tcl
# tests. Execute it by invoking "source all.test" when running tcltest
# in this directory.
#
# Copyright (c) 1998-2000 by Scriptics Corporation.
# All rights reserved.
#
# RCS: @(#) $Id: all.tcl,v 1.4 2004/07/04 22:04:20 patthoyts Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest
namespace import ::tcltest::*
}
set ::tcltest::testSingleFile false
set ::tcltest::testsDirectory [file dir [info script]]
# We need to ensure that the testsDirectory is absolute
if {[catch {::tcltest::normalizePath ::tcltest::testsDirectory}]} {
# The version of tcltest we have here does not support
# 'normalizePath', so we have to do this on our own.
set oldpwd [pwd]
catch {cd $::tcltest::testsDirectory}
set ::tcltest::testsDirectory [pwd]
cd $oldpwd
}
set chan $::tcltest::outputChannel
puts $chan "Tests running in interp: [info nameofexecutable]"
puts $chan "Tests running with pwd: [pwd]"
puts $chan "Tests running in working dir: $::tcltest::testsDirectory"
if {[llength $::tcltest::skip] > 0} {
puts $chan "Skipping tests that match: $::tcltest::skip"
}
if {[llength $::tcltest::match] > 0} {
puts $chan "Only running tests that match: $::tcltest::match"
}
if {[llength $::tcltest::skipFiles] > 0} {
puts $chan "Skipping test files that match: $::tcltest::skipFiles"
}
if {[llength $::tcltest::matchFiles] > 0} {
puts $chan "Only sourcing test files that match: $::tcltest::matchFiles"
}
set timeCmd {clock format [clock seconds]}
puts $chan "Tests began at [eval $timeCmd]"
# source each of the specified tests
foreach file [lsort [::tcltest::getMatchingFiles]] {
set tail [file tail $file]
puts $chan $tail
if {[catch {source $file} msg]} {
puts $chan $msg
}
}
# cleanup
puts $chan "\nTests ended at [eval $timeCmd]"
::tcltest::cleanupTests 1
return

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
#------------------------------------------------------------- -*- makefile -*-
#
# Makefile for TBDC Sqlite3 interface
#
# Basic test and install
# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\installdir TCLDIR=c:\path\to\tcl\source test
# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\installdir TCLDIR=c:\path\to\tcl\source install
#
# For other build options (debug, static etc.)
# See TIP 477 (https://core.tcl-lang.org/tips/doc/trunk/tip/477.md) for
# detailed documentation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
#------------------------------------------------------------------------------
PROJECT = tdbcsqlite3
!include "rules-ext.vc"
# Pure Tcl extension, no object files
PRJ_OBJS =
TM_INSTALL_DIR = $(_INSTALLDIR)\tcl$(TCL_MAJOR_VERSION)\$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
$(PROJECT):
@echo "This is a pure Tcl module and does not require a build step. Do a nmake install to install"
setup: default-setup
install: install-tm default-install-docs-n
clean: default-clean
realclean: hose
hose: default-hose
distclean: realclean default-distclean
install-tm:
@echo Installing 'tdbcsqlite3.tcl' file to '$(TM_INSTALL_DIR)\tdbc\sqlite3-$(DOTVERSION).tm'
@if not exist "$(TM_INSTALL_DIR)\tdbc" mkdir "$(TM_INSTALL_DIR)\tdbc"
@if exist $(LIBDIR) $(COPY) $(LIBDIR)\tdbcsqlite3.tcl "$(TM_INSTALL_DIR)\tdbc\sqlite3-$(DOTVERSION).tm"
test: default-test
shell: default-shell

View File

@@ -0,0 +1,815 @@
/*
* ----------------------------------------------------------------------------
* nmakehlp.c --
*
* This is used to fix limitations within nmake and the environment.
*
* Copyright (c) 2002 by David Gravereaux.
* Copyright (c) 2006 by Pat Thoyts
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
* ----------------------------------------------------------------------------
*/
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")
#include <stdio.h>
#include <math.h>
/*
* This library is required for x64 builds with _some_ versions of MSVC
*/
#if defined(_M_IA64) || defined(_M_AMD64)
#if _MSC_VER >= 1400 && _MSC_VER < 1500
#pragma comment(lib, "bufferoverflowU")
#endif
#endif
/* ISO hack for dumb VC++ */
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
/* protos */
static int CheckForCompilerFeature(const char *option);
static int CheckForLinkerFeature(const char **options, int count);
static int IsIn(const char *string, const char *substring);
static int SubstituteFile(const char *substs, const char *filename);
static int QualifyPath(const char *path);
static int LocateDependency(const char *keyfile);
static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
static DWORD WINAPI ReadFromPipe(LPVOID args);
/* globals */
#define CHUNK 25
#define STATICBUFFERSIZE 1000
typedef struct {
HANDLE pipe;
char buffer[STATICBUFFERSIZE];
} pipeinfo;
pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};
/*
* exitcodes: 0 == no, 1 == yes, 2 == error
*/
int
main(
int argc,
char *argv[])
{
char msg[300];
DWORD dwWritten;
int chars;
const char *s;
/*
* Make sure children (cl.exe and link.exe) are kept quiet.
*/
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
/*
* Make sure the compiler and linker aren't effected by the outside world.
*/
SetEnvironmentVariable("CL", "");
SetEnvironmentVariable("LINK", "");
if (argc > 1 && *argv[1] == '-') {
switch (*(argv[1]+1)) {
case 'c':
if (argc != 3) {
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -c <compiler option>\n"
"Tests for whether cl.exe supports an option\n"
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 2;
}
return CheckForCompilerFeature(argv[2]);
case 'l':
if (argc < 3) {
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -l <linker option> ?<mandatory option> ...?\n"
"Tests for whether link.exe supports an option\n"
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 2;
}
return CheckForLinkerFeature(&argv[2], argc-2);
case 'f':
if (argc == 2) {
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -f <string> <substring>\n"
"Find a substring within another\n"
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 2;
} else if (argc == 3) {
/*
* If the string is blank, there is no match.
*/
return 0;
} else {
return IsIn(argv[2], argv[3]);
}
case 's':
if (argc == 2) {
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -s <substitutions file> <file>\n"
"Perform a set of string map type substutitions on a file\n"
"exitcodes: 0\n",
argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 2;
}
return SubstituteFile(argv[2], argv[3]);
case 'V':
if (argc != 4) {
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -V filename matchstring\n"
"Extract a version from a file:\n"
"eg: pkgIndex.tcl \"package ifneeded http\"",
argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 0;
}
s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
if (s && *s) {
printf("%s\n", s);
return 0;
} else
return 1; /* Version not found. Return non-0 exit code */
case 'Q':
if (argc != 3) {
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -Q path\n"
"Emit the fully qualified path\n"
"exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 2;
}
return QualifyPath(argv[2]);
case 'L':
if (argc != 3) {
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -L keypath\n"
"Emit the fully qualified path of directory containing keypath\n"
"exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
&dwWritten, NULL);
return 2;
}
return LocateDependency(argv[2]);
}
}
chars = snprintf(msg, sizeof(msg) - 1,
"usage: %s -c|-f|-l|-Q|-s|-V ...\n"
"This is a little helper app to equalize shell differences between WinNT and\n"
"Win9x and get nmake.exe to accomplish its job.\n",
argv[0]);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
return 2;
}
static int
CheckForCompilerFeature(
const char *option)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
DWORD threadID;
char msg[300];
BOOL ok;
HANDLE hProcess, h, pipeThreads[2];
char cmdline[100];
hProcess = GetCurrentProcess();
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = INVALID_HANDLE_VALUE;
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
/*
* Create a non-inheritible pipe.
*/
CreatePipe(&Out.pipe, &h, &sa, 0);
/*
* Dupe the write side, make it inheritible, and close the original.
*/
DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
/*
* Same as above, but for the error side.
*/
CreatePipe(&Err.pipe, &h, &sa, 0);
DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
/*
* Base command line.
*/
lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");
/*
* Append our option for testing
*/
lstrcat(cmdline, option);
/*
* Filename to compile, which exists, but is nothing and empty.
*/
lstrcat(cmdline, " .\\nul");
ok = CreateProcess(
NULL, /* Module name. */
cmdline, /* Command line. */
NULL, /* Process handle not inheritable. */
NULL, /* Thread handle not inheritable. */
TRUE, /* yes, inherit handles. */
DETACHED_PROCESS, /* No console for you. */
NULL, /* Use parent's environment block. */
NULL, /* Use parent's starting directory. */
&si, /* Pointer to STARTUPINFO structure. */
&pi); /* Pointer to PROCESS_INFORMATION structure. */
if (!ok) {
DWORD err = GetLastError();
int chars = snprintf(msg, sizeof(msg) - 1,
"Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
(300-chars), 0);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
return 2;
}
/*
* Close our references to the write handles that have now been inherited.
*/
CloseHandle(si.hStdOutput);
CloseHandle(si.hStdError);
WaitForInputIdle(pi.hProcess, 5000);
CloseHandle(pi.hThread);
/*
* Start the pipe reader threads.
*/
pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
/*
* Block waiting for the process to end.
*/
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
/*
* Wait for our pipe to get done reading, should it be a little slow.
*/
WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
CloseHandle(pipeThreads[0]);
CloseHandle(pipeThreads[1]);
/*
* Look for the commandline warning code in both streams.
* - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
*/
return !(strstr(Out.buffer, "D4002") != NULL
|| strstr(Err.buffer, "D4002") != NULL
|| strstr(Out.buffer, "D9002") != NULL
|| strstr(Err.buffer, "D9002") != NULL
|| strstr(Out.buffer, "D2021") != NULL
|| strstr(Err.buffer, "D2021") != NULL);
}
static int
CheckForLinkerFeature(
const char **options,
int count)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sa;
DWORD threadID;
char msg[300];
BOOL ok;
HANDLE hProcess, h, pipeThreads[2];
int i;
char cmdline[255];
hProcess = GetCurrentProcess();
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = INVALID_HANDLE_VALUE;
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
/*
* Create a non-inheritible pipe.
*/
CreatePipe(&Out.pipe, &h, &sa, 0);
/*
* Dupe the write side, make it inheritible, and close the original.
*/
DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
/*
* Same as above, but for the error side.
*/
CreatePipe(&Err.pipe, &h, &sa, 0);
DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
/*
* Base command line.
*/
lstrcpy(cmdline, "link.exe -nologo ");
/*
* Append our option for testing.
*/
for (i = 0; i < count; i++) {
lstrcat(cmdline, " \"");
lstrcat(cmdline, options[i]);
lstrcat(cmdline, "\"");
}
ok = CreateProcess(
NULL, /* Module name. */
cmdline, /* Command line. */
NULL, /* Process handle not inheritable. */
NULL, /* Thread handle not inheritable. */
TRUE, /* yes, inherit handles. */
DETACHED_PROCESS, /* No console for you. */
NULL, /* Use parent's environment block. */
NULL, /* Use parent's starting directory. */
&si, /* Pointer to STARTUPINFO structure. */
&pi); /* Pointer to PROCESS_INFORMATION structure. */
if (!ok) {
DWORD err = GetLastError();
int chars = snprintf(msg, sizeof(msg) - 1,
"Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPVOID)&msg[chars],
(300-chars), 0);
WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
return 2;
}
/*
* Close our references to the write handles that have now been inherited.
*/
CloseHandle(si.hStdOutput);
CloseHandle(si.hStdError);
WaitForInputIdle(pi.hProcess, 5000);
CloseHandle(pi.hThread);
/*
* Start the pipe reader threads.
*/
pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
/*
* Block waiting for the process to end.
*/
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
/*
* Wait for our pipe to get done reading, should it be a little slow.
*/
WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
CloseHandle(pipeThreads[0]);
CloseHandle(pipeThreads[1]);
/*
* Look for the commandline warning code in the stderr stream.
*/
return !(strstr(Out.buffer, "LNK1117") != NULL ||
strstr(Err.buffer, "LNK1117") != NULL ||
strstr(Out.buffer, "LNK4044") != NULL ||
strstr(Err.buffer, "LNK4044") != NULL ||
strstr(Out.buffer, "LNK4224") != NULL ||
strstr(Err.buffer, "LNK4224") != NULL);
}
static DWORD WINAPI
ReadFromPipe(
LPVOID args)
{
pipeinfo *pi = (pipeinfo *) args;
char *lastBuf = pi->buffer;
DWORD dwRead;
BOOL ok;
again:
if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
CloseHandle(pi->pipe);
return (DWORD)-1;
}
ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
if (!ok || dwRead == 0) {
CloseHandle(pi->pipe);
return 0;
}
lastBuf += dwRead;
goto again;
return 0; /* makes the compiler happy */
}
static int
IsIn(
const char *string,
const char *substring)
{
return (strstr(string, substring) != NULL);
}
/*
* GetVersionFromFile --
* Looks for a match string in a file and then returns the version
* following the match where a version is anything acceptable to
* package provide or package ifneeded.
*/
static const char *
GetVersionFromFile(
const char *filename,
const char *match,
int numdots)
{
size_t cbBuffer = 100;
static char szBuffer[100];
char *szResult = NULL;
FILE *fp = fopen(filename, "rt");
if (fp != NULL) {
/*
* Read data until we see our match string.
*/
while (fgets(szBuffer, cbBuffer, fp) != NULL) {
LPSTR p, q;
p = strstr(szBuffer, match);
if (p != NULL) {
/*
* Skip to first digit after the match.
*/
p += strlen(match);
while (*p && !isdigit(*p)) {
++p;
}
/*
* Find ending whitespace.
*/
q = p;
while (*q && (strchr("0123456789.ab", *q)) && ((!strchr(".ab", *q)
&& (!strchr("ab", q[-1])) || --numdots))) {
++q;
}
memcpy(szBuffer, p, q - p);
szBuffer[q-p] = 0;
szResult = szBuffer;
break;
}
}
fclose(fp);
}
return szResult;
}
/*
* List helpers for the SubstituteFile function
*/
typedef struct list_item_t {
struct list_item_t *nextPtr;
char * key;
char * value;
} list_item_t;
/* insert a list item into the list (list may be null) */
static list_item_t *
list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
{
list_item_t *itemPtr = malloc(sizeof(list_item_t));
if (itemPtr) {
itemPtr->key = strdup(key);
itemPtr->value = strdup(value);
itemPtr->nextPtr = NULL;
while(*listPtrPtr) {
listPtrPtr = &(*listPtrPtr)->nextPtr;
}
*listPtrPtr = itemPtr;
}
return itemPtr;
}
static void
list_free(list_item_t **listPtrPtr)
{
list_item_t *tmpPtr, *listPtr = *listPtrPtr;
while (listPtr) {
tmpPtr = listPtr;
listPtr = listPtr->nextPtr;
free(tmpPtr->key);
free(tmpPtr->value);
free(tmpPtr);
}
}
/*
* SubstituteFile --
* As windows doesn't provide anything useful like sed and it's unreliable
* to use the tclsh you are building against (consider x-platform builds -
* eg compiling AMD64 target from IX86) we provide a simple substitution
* option here to handle autoconf style substitutions.
* The substitution file is whitespace and line delimited. The file should
* consist of lines matching the regular expression:
* \s*\S+\s+\S*$
*
* Usage is something like:
* nmakehlp -S << $** > $@
* @PACKAGE_NAME@ $(PACKAGE_NAME)
* @PACKAGE_VERSION@ $(PACKAGE_VERSION)
* <<
*/
static int
SubstituteFile(
const char *substitutions,
const char *filename)
{
size_t cbBuffer = 1024;
static char szBuffer[1024], szCopy[1024];
char *szResult = NULL;
list_item_t *substPtr = NULL;
FILE *fp, *sp;
fp = fopen(filename, "rt");
if (fp != NULL) {
/*
* Build a list of substutitions from the first filename
*/
sp = fopen(substitutions, "rt");
if (sp != NULL) {
while (fgets(szBuffer, cbBuffer, sp) != NULL) {
unsigned char *ks, *ke, *vs, *ve;
ks = (unsigned char*)szBuffer;
while (ks && *ks && isspace(*ks)) ++ks;
ke = ks;
while (ke && *ke && !isspace(*ke)) ++ke;
vs = ke;
while (vs && *vs && isspace(*vs)) ++vs;
ve = vs;
while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
*ke = 0, *ve = 0;
list_insert(&substPtr, (char*)ks, (char*)vs);
}
fclose(sp);
}
/* debug: dump the list */
#ifndef NDEBUG
{
int n = 0;
list_item_t *p = NULL;
for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
}
}
#endif
/*
* Run the substitutions over each line of the input
*/
while (fgets(szBuffer, cbBuffer, fp) != NULL) {
list_item_t *p = NULL;
for (p = substPtr; p != NULL; p = p->nextPtr) {
char *m = strstr(szBuffer, p->key);
if (m) {
char *cp, *op, *sp;
cp = szCopy;
op = szBuffer;
while (op != m) *cp++ = *op++;
sp = p->value;
while (sp && *sp) *cp++ = *sp++;
op += strlen(p->key);
while (*op) *cp++ = *op++;
*cp = 0;
memcpy(szBuffer, szCopy, sizeof(szCopy));
}
}
printf(szBuffer);
}
list_free(&substPtr);
}
fclose(fp);
return 0;
}
BOOL FileExists(LPCTSTR szPath)
{
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif
DWORD pathAttr = GetFileAttributes(szPath);
return (pathAttr != INVALID_FILE_ATTRIBUTES &&
!(pathAttr & FILE_ATTRIBUTE_DIRECTORY));
}
/*
* QualifyPath --
*
* This composes the current working directory with a provided path
* and returns the fully qualified and normalized path.
* Mostly needed to setup paths for testing.
*/
static int
QualifyPath(
const char *szPath)
{
char szCwd[MAX_PATH + 1];
GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL);
printf("%s\n", szCwd);
return 0;
}
/*
* Implements LocateDependency for a single directory. See that command
* for an explanation.
* Returns 0 if found after printing the directory.
* Returns 1 if not found but no errors.
* Returns 2 on any kind of error
* Basically, these are used as exit codes for the process.
*/
static int LocateDependencyHelper(const char *dir, const char *keypath)
{
HANDLE hSearch;
char path[MAX_PATH+1];
int dirlen, keylen, ret;
WIN32_FIND_DATA finfo;
if (dir == NULL || keypath == NULL)
return 2; /* Have no real error reporting mechanism into nmake */
dirlen = strlen(dir);
if ((dirlen + 3) > sizeof(path))
return 2;
strncpy(path, dir, dirlen);
strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */
keylen = strlen(keypath);
#if 0 /* This function is not available in Visual C++ 6 */
/*
* Use numerics 0 -> FindExInfoStandard,
* 1 -> FindExSearchLimitToDirectories,
* as these are not defined in Visual C++ 6
*/
hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
#else
hSearch = FindFirstFile(path, &finfo);
#endif
if (hSearch == INVALID_HANDLE_VALUE)
return 1; /* Not found */
/* Loop through all subdirs checking if the keypath is under there */
ret = 1; /* Assume not found */
do {
int sublen;
/*
* We need to check it is a directory despite the
* FindExSearchLimitToDirectories in the above call. See SDK docs
*/
if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
continue;
sublen = strlen(finfo.cFileName);
if ((dirlen+1+sublen+1+keylen+1) > sizeof(path))
continue; /* Path does not fit, assume not matched */
strncpy(path+dirlen+1, finfo.cFileName, sublen);
path[dirlen+1+sublen] = '\\';
strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
if (FileExists(path)) {
/* Found a match, print to stdout */
path[dirlen+1+sublen] = '\0';
QualifyPath(path);
ret = 0;
break;
}
} while (FindNextFile(hSearch, &finfo));
FindClose(hSearch);
return ret;
}
/*
* LocateDependency --
*
* Locates a dependency for a package.
* keypath - a relative path within the package directory
* that is used to confirm it is the correct directory.
* The search path for the package directory is currently only
* the parent and grandparent of the current working directory.
* If found, the command prints
* name_DIRPATH=<full path of located directory>
* and returns 0. If not found, does not print anything and returns 1.
*/
static int LocateDependency(const char *keypath)
{
int i, ret;
static const char *paths[] = {"..", "..\\..", "..\\..\\.."};
for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
ret = LocateDependencyHelper(paths[i], keypath);
if (ret == 0)
return ret;
}
return ret;
}
/*
* Local variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* indent-tabs-mode: t
* tab-width: 8
* End:
*/

View File

@@ -0,0 +1,118 @@
# This file should only be included in makefiles for Tcl extensions,
# NOT in the makefile for Tcl itself.
!ifndef _RULES_EXT_VC
# We need to run from the directory the parent makefile is located in.
# nmake does not tell us what makefile was used to invoke it so parent
# makefile has to set the MAKEFILEVC macro or we just make a guess and
# warn if we think that is not the case.
!if "$(MAKEFILEVC)" == ""
!if exist("$(PROJECT).vc")
MAKEFILEVC = $(PROJECT).vc
!elseif exist("makefile.vc")
MAKEFILEVC = makefile.vc
!endif
!endif # "$(MAKEFILEVC)" == ""
!if !exist("$(MAKEFILEVC)")
MSG = ^
You must run nmake from the directory containing the project makefile.^
If you are doing that and getting this message, set the MAKEFILEVC^
macro to the name of the project makefile.
!message WARNING: $(MSG)
!endif
!if "$(PROJECT)" == "tcl"
!error The rules-ext.vc file is not intended for Tcl itself.
!endif
# We extract version numbers using the nmakehlp program. For now use
# the local copy of nmakehlp. Once we locate Tcl, we will use that
# one if it is newer.
!if [$(CC) -nologo "nmakehlp.c" -link -subsystem:console > nul]
!endif
# First locate the Tcl directory that we are working with.
!if "$(TCLDIR)" != ""
_RULESDIR = $(TCLDIR:/=\)
!else
# If an installation path is specified, that is also the Tcl directory.
# Also Tk never builds against an installed Tcl, it needs Tcl sources
!if defined(INSTALLDIR) && "$(PROJECT)" != "tk"
_RULESDIR=$(INSTALLDIR:/=\)
!else
# Locate Tcl sources
!if [echo _RULESDIR = \> nmakehlp.out] \
|| [nmakehlp -L generic\tcl.h >> nmakehlp.out]
_RULESDIR = ..\..\tcl
!else
!include nmakehlp.out
!endif
!endif # defined(INSTALLDIR)....
!endif # ifndef TCLDIR
# Now look for the targets.vc file under the Tcl root. Note we check this
# file and not rules.vc because the latter also exists on older systems.
!if exist("$(_RULESDIR)\lib\nmake\targets.vc") # Building against installed Tcl
_RULESDIR = $(_RULESDIR)\lib\nmake
!elseif exist("$(_RULESDIR)\win\targets.vc") # Building against Tcl sources
_RULESDIR = $(_RULESDIR)\win
!else
# If we have not located Tcl's targets file, most likely we are compiling
# against an older version of Tcl and so must use our own support files.
_RULESDIR = .
!endif
!if "$(_RULESDIR)" != "."
# Potentially using Tcl's support files. If this extension has its own
# nmake support files, need to compare the versions and pick newer.
!if exist("rules.vc") # The extension has its own copy
!if [echo TCL_RULES_MAJOR = \> versions.vc] \
&& [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MAJOR >> versions.vc]
!endif
!if [echo TCL_RULES_MINOR = \>> versions.vc] \
&& [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MINOR >> versions.vc]
!endif
!if [echo OUR_RULES_MAJOR = \>> versions.vc] \
&& [nmakehlp -V "rules.vc" RULES_VERSION_MAJOR >> versions.vc]
!endif
!if [echo OUR_RULES_MINOR = \>> versions.vc] \
&& [nmakehlp -V "rules.vc" RULES_VERSION_MINOR >> versions.vc]
!endif
!include versions.vc
# We have a newer version of the support files, use them
!if ($(TCL_RULES_MAJOR) != $(OUR_RULES_MAJOR)) || ($(TCL_RULES_MINOR) < $(OUR_RULES_MINOR))
_RULESDIR = .
!endif
!endif # if exist("rules.vc")
!endif # if $(_RULESDIR) != "."
# Let rules.vc know what copy of nmakehlp.c to use.
NMAKEHLPC = $(_RULESDIR)\nmakehlp.c
# Get rid of our internal defines before calling rules.vc
!undef TCL_RULES_MAJOR
!undef TCL_RULES_MINOR
!undef OUR_RULES_MAJOR
!undef OUR_RULES_MINOR
!if exist("$(_RULESDIR)\rules.vc")
!message *** Using $(_RULESDIR)\rules.vc
!include "$(_RULESDIR)\rules.vc"
!else
!error *** Could not locate rules.vc in $(_RULESDIR)
!endif
!endif # _RULES_EXT_VC

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,98 @@
#------------------------------------------------------------- -*- makefile -*-
# targets.vc --
#
# Part of the nmake based build system for Tcl and its extensions.
# This file defines some standard targets for the convenience of extensions
# and can be optionally included by the extension makefile.
# See TIP 477 (https://core.tcl-lang.org/tips/doc/trunk/tip/477.md) for docs.
$(PROJECT): setup pkgindex $(PRJLIB)
!ifdef PRJ_STUBOBJS
$(PROJECT): $(PRJSTUBLIB)
$(PRJSTUBLIB): $(PRJ_STUBOBJS)
$(LIBCMD) $**
$(PRJ_STUBOBJS):
$(CCSTUBSCMD) %s
!endif # PRJ_STUBOBJS
!ifdef PRJ_MANIFEST
$(PROJECT): $(PRJLIB).manifest
$(PRJLIB).manifest: $(PRJ_MANIFEST)
@nmakehlp -s << $** >$@
@MACHINE@ $(MACHINE:IX86=X86)
<<
!endif
!if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk"
$(PRJLIB): $(PRJ_OBJS) $(RESFILE)
!if $(STATIC_BUILD)
$(LIBCMD) $**
!else
$(DLLCMD) $**
$(_VC_MANIFEST_EMBED_DLL)
!endif
-@del $*.exp
!endif
!if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != ""
$(PRJ_OBJS): $(PRJ_HEADERS)
!endif
# If parent makefile has defined stub objects, add their installation
# to the default install
!if "$(PRJ_STUBOBJS)" != ""
default-install: default-install-stubs
!endif
# Unlike the other default targets, these cannot be in rules.vc because
# the executed command depends on existence of macro PRJ_HEADERS_PUBLIC
# that the parent makefile will not define until after including rules-ext.vc
!if "$(PRJ_HEADERS_PUBLIC)" != ""
default-install: default-install-headers
default-install-headers:
@echo Installing headers to '$(INCLUDE_INSTALL_DIR)'
@for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)"
!endif
!if "$(DISABLE_STANDARD_TARGETS)" == ""
DISABLE_STANDARD_TARGETS = 0
!endif
!if "$(DISABLE_TARGET_setup)" == ""
DISABLE_TARGET_setup = 0
!endif
!if "$(DISABLE_TARGET_install)" == ""
DISABLE_TARGET_install = 0
!endif
!if "$(DISABLE_TARGET_clean)" == ""
DISABLE_TARGET_clean = 0
!endif
!if "$(DISABLE_TARGET_test)" == ""
DISABLE_TARGET_test = 0
!endif
!if "$(DISABLE_TARGET_shell)" == ""
DISABLE_TARGET_shell = 0
!endif
!if !$(DISABLE_STANDARD_TARGETS)
!if !$(DISABLE_TARGET_setup)
setup: default-setup
!endif
!if !$(DISABLE_TARGET_install)
install: default-install
!endif
!if !$(DISABLE_TARGET_clean)
clean: default-clean
realclean: hose
hose: default-hose
distclean: realclean default-distclean
!endif
!if !$(DISABLE_TARGET_test)
test: default-test
!endif
!if !$(DISABLE_TARGET_shell)
shell: default-shell
!endif
!endif # DISABLE_STANDARD_TARGETS